mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-15 20:48:12 +01:00
Compare commits
193 Commits
v3.0.0-alp
...
fix/modal-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd9f97c454 | ||
|
|
f0297e02d0 | ||
|
|
64421a190f | ||
|
|
3af77ccca1 | ||
|
|
a3a562b699 | ||
|
|
3159a89436 | ||
|
|
ba1dd13173 | ||
|
|
3fc2210e03 | ||
|
|
931211a634 | ||
|
|
27fdc8e260 | ||
|
|
1e88512bef | ||
|
|
533ccec110 | ||
|
|
86e1888474 | ||
|
|
12a1ab00df | ||
|
|
b64b24f65a | ||
|
|
b8276020b3 | ||
|
|
75f7064b40 | ||
|
|
51e5e65be7 | ||
|
|
6df9a1a44b | ||
|
|
ec5d5c98a2 | ||
|
|
de9ecb1d76 | ||
|
|
865a47f125 | ||
|
|
9ccfe8fbb3 | ||
|
|
1bf370e6fd | ||
|
|
3309ef60b2 | ||
|
|
a6cc7bf53b | ||
|
|
e2cee110b4 | ||
|
|
01b7547ccc | ||
|
|
e7c10bcb0d | ||
|
|
1d54fd3e2d | ||
|
|
f85b0985bd | ||
|
|
c902a40f7c | ||
|
|
1a54ab231b | ||
|
|
9d0f8617b2 | ||
|
|
23493af406 | ||
|
|
582fe87d70 | ||
|
|
c957bbf9a1 | ||
|
|
965e1aacaf | ||
|
|
1ba2e185b2 | ||
|
|
53afc40481 | ||
|
|
5c2c55ff08 | ||
|
|
39a3d2592c | ||
|
|
ee4c33cb1a | ||
|
|
d5dba0ebc9 | ||
|
|
a3dbf7c27d | ||
|
|
a3cf25f5cd | ||
|
|
02c8988a7a | ||
|
|
046785359e | ||
|
|
85b8553893 | ||
|
|
5288f87e0b | ||
|
|
25a71aa3ae | ||
|
|
a3bae03a20 | ||
|
|
01ce7e2d14 | ||
|
|
11a3f03a7f | ||
|
|
0531211ee5 | ||
|
|
039788a044 | ||
|
|
9aa6812423 | ||
|
|
3107039b56 | ||
|
|
c79acc15b0 | ||
|
|
15b411de4a | ||
|
|
410b7db201 | ||
|
|
5a443944ae | ||
|
|
82ade16fd0 | ||
|
|
af736b0c6a | ||
|
|
30ba53e20b | ||
|
|
4e482750cb | ||
|
|
01bf99eec8 | ||
|
|
446a9f7d31 | ||
|
|
638808c32c | ||
|
|
6a81db2b9c | ||
|
|
1f71d74899 | ||
|
|
cc50ef6ccd | ||
|
|
4344e36664 | ||
|
|
cc523a3d23 | ||
|
|
d7981ab2d5 | ||
|
|
697994e15d | ||
|
|
18b2c51282 | ||
|
|
a68f57c5d2 | ||
|
|
2050bed050 | ||
|
|
9bf93575a7 | ||
|
|
5c19c79350 | ||
|
|
fd5a529565 | ||
|
|
61389b8b5a | ||
|
|
ef7ecd242f | ||
|
|
41dc11ceef | ||
|
|
00b3c86584 | ||
|
|
8c88912a8f | ||
|
|
0128c1c9e0 | ||
|
|
254bf3a65f | ||
|
|
5ac25b5a84 | ||
|
|
71e98a4024 | ||
|
|
561fcd0b19 | ||
|
|
1c4bae8c86 | ||
|
|
0903e80b03 | ||
|
|
fae9895836 | ||
|
|
f19308d401 | ||
|
|
2f19136fd8 | ||
|
|
0201a3de75 | ||
|
|
c770ae124e | ||
|
|
a18ad84edf | ||
|
|
64f85a029f | ||
|
|
d4653e3c02 | ||
|
|
546a82c4c9 | ||
|
|
e878115a73 | ||
|
|
91da9aa83a | ||
|
|
9759320438 | ||
|
|
4f05b1aac9 | ||
|
|
ffba108291 | ||
|
|
5550d184bb | ||
|
|
c8cd06e92d | ||
|
|
b326a14fb0 | ||
|
|
5183582a90 | ||
|
|
ac54c7523c | ||
|
|
4c0bdf38fc | ||
|
|
c223281763 | ||
|
|
7f09299de5 | ||
|
|
6510e1e47d | ||
|
|
2202d05119 | ||
|
|
7eea62899c | ||
|
|
f66e272b63 | ||
|
|
23550c2263 | ||
|
|
d6179912de | ||
|
|
78be40a286 | ||
|
|
c2d777625f | ||
|
|
e1d385a175 | ||
|
|
1b3c919222 | ||
|
|
0f37aca317 | ||
|
|
7f64198a70 | ||
|
|
6f8087f44b | ||
|
|
6974f23645 | ||
|
|
f3f4edae28 | ||
|
|
7302a846a9 | ||
|
|
2c99bb80c7 | ||
|
|
607792ea25 | ||
|
|
1b6dda1ea9 | ||
|
|
6520790ff7 | ||
|
|
ad8db69990 | ||
|
|
242ff3b0ed | ||
|
|
e931880671 | ||
|
|
82d63446a1 | ||
|
|
9b4694f8d9 | ||
|
|
4c5a4fb526 | ||
|
|
6fb426fc17 | ||
|
|
fdaff6630f | ||
|
|
0285bf33fa | ||
|
|
5efae599b6 | ||
|
|
908f2b569a | ||
|
|
52b561dbed | ||
|
|
34ec90c974 | ||
|
|
194f3b6f03 | ||
|
|
2e17fb68de | ||
|
|
babfcdcb02 | ||
|
|
2fc43d66d5 | ||
|
|
d9967f5e28 | ||
|
|
cef16cd49d | ||
|
|
0b86f4315e | ||
|
|
bfb9b5200c | ||
|
|
aa3b38fc39 | ||
|
|
ae33adb900 | ||
|
|
f97d2e3b88 | ||
|
|
473194fbaf | ||
|
|
33fb2cad0b | ||
|
|
8d3f0fdc39 | ||
|
|
3167fda517 | ||
|
|
7ebd8d813d | ||
|
|
b40b73129c | ||
|
|
93ea5b958e | ||
|
|
76db00db7a | ||
|
|
3445078cab | ||
|
|
f179f8588a | ||
|
|
5a6a165a8d | ||
|
|
7ee733e82b | ||
|
|
a0b8b93a5a | ||
|
|
52e2a4d68f | ||
|
|
efd104a10f | ||
|
|
d8d56d909b | ||
|
|
d5f9cc27a4 | ||
|
|
db9ac5778f | ||
|
|
e73f38d1d1 | ||
|
|
206366a70e | ||
|
|
88a5a7055d | ||
|
|
b2f68dcf81 | ||
|
|
edad9b7f5c | ||
|
|
c5a8914483 | ||
|
|
57f4d613e6 | ||
|
|
c186169562 | ||
|
|
31b8c56ff7 | ||
|
|
cc1e32edf5 | ||
|
|
9fc42bab2e | ||
|
|
1acf99390d | ||
|
|
bf45094f89 | ||
|
|
eaddb8cb33 | ||
|
|
51de839aca |
@@ -2,11 +2,6 @@ name: "🐛 Bug report (v3)"
|
||||
description: Report a bug to help us improve the module (v3 only).
|
||||
labels: ["triage", "bug", "v3"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> [!IMPORTANT]
|
||||
> As Nuxt UI v3 is currently in alpha, we recommend thorough testing before using it in production environments. We're actively working on stabilization and welcome feedback from early adopters to improve the library.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
@@ -49,7 +44,7 @@ body:
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Reproduction
|
||||
description: Please provide a reproduction link. A minimal [reproduction is required](https://antfu.me/posts/why-reproductions-are-required) unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "needs reproduction" label. If no reproduction is provided we might close it.
|
||||
description: Please provide a reproduction link using the Nuxt template https://codesandbox.io/p/devbox/nuxt-ui3-n3sxks or the Vue template https://codesandbox.io/p/devbox/nuxt-ui3-vue-4h5gqn. A minimal [reproduction is required](https://antfu.me/posts/why-reproductions-are-required) unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "needs reproduction" label. If no reproduction is provided we might close it.
|
||||
placeholder: https://github.com/my/reproduction
|
||||
validations:
|
||||
required: true
|
||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -28,7 +28,7 @@ body:
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
placeholder: v2.8.0
|
||||
placeholder: v2.20.0
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
20
.github/ISSUE_TEMPLATE/feature-request-v3.yml
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature-request-v3.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: "🚀 Feature request (v3)"
|
||||
description: Suggest an idea or enhancement for the module (v3 only).
|
||||
labels: ["triage", "enhancement", "v3"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before requesting a feature, please make sure that you have read through our [v3 documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: A clear and concise description of what you think would be an helpful addition to the module, including the possible use cases and alternatives you have considered. If you have a working prototype or module that implements it, please include a link.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additonal
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: If applicable, add any other context or screenshots here.
|
||||
9
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
9
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -6,15 +6,6 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
Before requesting a feature, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
- type: dropdown
|
||||
id: version
|
||||
attributes:
|
||||
label: For what version of Nuxt UI are you suggesting this?
|
||||
options:
|
||||
- v2.x
|
||||
- v3.0.0-alpha.x
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
14
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
Normal file
14
.github/ISSUE_TEMPLATE/question-v3.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: "💬 Question (v3)"
|
||||
description: Ask a question about the module (v3 only).
|
||||
labels: ["question", "v3"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before asking a question, please make sure that you have read through our [v3 documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
validations:
|
||||
required: true
|
||||
9
.github/ISSUE_TEMPLATE/question.yml
vendored
9
.github/ISSUE_TEMPLATE/question.yml
vendored
@@ -6,15 +6,6 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
Before asking a question, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
- type: dropdown
|
||||
id: version
|
||||
attributes:
|
||||
label: For what version of Nuxt UI are you asking this question?
|
||||
options:
|
||||
- v2.x
|
||||
- v3.0.0-alpha.x
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
57
.github/workflows/docs.yml
vendored
Normal file
57
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v3
|
||||
pull_request:
|
||||
branches:
|
||||
- v3
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
environment:
|
||||
name: ${{ github.ref == 'refs/heads/v3' && 'production' || 'preview' }}
|
||||
url: ${{ steps.deploy.outputs.deployment-url }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [22]
|
||||
|
||||
env:
|
||||
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Prepare build
|
||||
run: pnpm run dev:prepare
|
||||
|
||||
- name: Build application
|
||||
run: pnpm run docs:build
|
||||
|
||||
- name: Deploy to NuxtHub
|
||||
uses: nuxt-hub/action@v1
|
||||
id: deploy
|
||||
with:
|
||||
project-key: ui-7eg3
|
||||
directory: docs/dist
|
||||
@@ -1,4 +1,4 @@
|
||||
name: ci-v3
|
||||
name: module
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
- v3
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [20]
|
||||
node: [22]
|
||||
|
||||
env:
|
||||
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
|
||||
53
.github/workflows/playground.yml
vendored
Normal file
53
.github/workflows/playground.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: playground
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v3
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
environment:
|
||||
name: ${{ github.ref == 'refs/heads/v3' && 'production' || 'preview' }}
|
||||
url: ${{ steps.deploy.outputs.deployment-url }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [22]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Prepare build
|
||||
run: pnpm run dev:prepare
|
||||
|
||||
- name: Build application
|
||||
run: pnpm run dev:build
|
||||
env:
|
||||
NITRO_PRESET: cloudflare-pages
|
||||
|
||||
- name: Deploy to NuxtHub
|
||||
uses: nuxt-hub/action@v1
|
||||
id: deploy
|
||||
with:
|
||||
project-key: ui3-playground-pb9b
|
||||
directory: playground/dist
|
||||
52
CHANGELOG.md
52
CHANGELOG.md
@@ -1,5 +1,57 @@
|
||||
# Changelog
|
||||
|
||||
## [3.0.0-alpha.11](https://github.com/nuxt/ui/compare/v3.0.0-alpha.10...v3.0.0-alpha.11) (2025-01-13)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **Modal/Popover/Slideover:** rename `prevent-close` to `dismissible` + uniformize docs
|
||||
|
||||
### Features
|
||||
|
||||
* **Badge:** rework sizes ([d9967f5](https://github.com/nuxt/ui/commit/d9967f5e282d41f4000d5451efed7254b4c1608c))
|
||||
* **CommandPalette:** add `autofocus` prop ([#2942](https://github.com/nuxt/ui/issues/2942)) ([1b3c919](https://github.com/nuxt/ui/commit/1b3c919222a4002d84dd968f93bcf9d615e412bc))
|
||||
* **locale:** add Danish language ([#2952](https://github.com/nuxt/ui/issues/2952)) ([e1d385a](https://github.com/nuxt/ui/commit/e1d385a17545f8091c8d2459842fe4c39b8c9399))
|
||||
* **locale:** add Estonian language ([#3036](https://github.com/nuxt/ui/issues/3036)) ([01bf99e](https://github.com/nuxt/ui/commit/01bf99eec8c2fd0e3dbe1271be152844e401287a))
|
||||
* **locale:** add Finnish language ([#3013](https://github.com/nuxt/ui/issues/3013)) ([c770ae1](https://github.com/nuxt/ui/commit/c770ae124e626682935475dc6a164aacd1408c01))
|
||||
* **locale:** add Greek language ([#2975](https://github.com/nuxt/ui/issues/2975)) ([b326a14](https://github.com/nuxt/ui/commit/b326a14fb0e62edc8e55599c16f934f54f95aa42))
|
||||
* **locale:** add Indonesian language ([#3024](https://github.com/nuxt/ui/issues/3024)) ([a18ad84](https://github.com/nuxt/ui/commit/a18ad84edfe6b3f444d379f24defeecb63e5cdb9))
|
||||
* **locale:** add Swedish language ([#3012](https://github.com/nuxt/ui/issues/3012)) ([0201a3d](https://github.com/nuxt/ui/commit/0201a3de757db426c877ef2761de8e9d7493983e))
|
||||
* **locale:** add Thai language ([#2980](https://github.com/nuxt/ui/issues/2980)) ([c8cd06e](https://github.com/nuxt/ui/commit/c8cd06e92dab208271ab7b7f6806793eea1e8969))
|
||||
* **locale:** add Ukrainian language ([#2908](https://github.com/nuxt/ui/issues/2908)) ([5efae59](https://github.com/nuxt/ui/commit/5efae599b642e65ec8ccaf2361b69abe993a0173))
|
||||
* **locale:** add Viet language ([#2986](https://github.com/nuxt/ui/issues/2986)) ([ffba108](https://github.com/nuxt/ui/commit/ffba108291f321471650ca9060ea264f41482648))
|
||||
* **module:** allow `tv` customization through `app.config` ([#2938](https://github.com/nuxt/ui/issues/2938)) ([30ba53e](https://github.com/nuxt/ui/commit/30ba53e20b3b91909c2c8162f35b13b6ad305d13))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Accordion/Collapsible/NavigationMenu/Tabs:** define `unmountOnHide` default ([4344e36](https://github.com/nuxt/ui/commit/4344e366647e9618c21fe800b43d2b4ae2611226))
|
||||
* **Avatar:** bind `$attrs` on `AvatarFallback` ([#2933](https://github.com/nuxt/ui/issues/2933)) ([7f64198](https://github.com/nuxt/ui/commit/7f64198a70104436f39f2f9d8527df0508fd84f6))
|
||||
* **Badge:** reduce radius on `sm` size ([f97d2e3](https://github.com/nuxt/ui/commit/f97d2e3b88d1ba9be5f7e2916c6502e38ac4d4c1))
|
||||
* **CommandPalette/SelectMenu:** missing translations ([#3057](https://github.com/nuxt/ui/issues/3057)) ([d5dba0e](https://github.com/nuxt/ui/commit/d5dba0ebc98594906ef1d9428da11d44317b70fc))
|
||||
* **components:** enable pointer events on menus ([#2881](https://github.com/nuxt/ui/issues/2881)) ([f85b098](https://github.com/nuxt/ui/commit/f85b0985bdd6f51aff41acc6f86dd02db9832b24))
|
||||
* **defineShortcuts:** handle extract when using `onSelect` or `onClick` ([#2896](https://github.com/nuxt/ui/issues/2896)) ([2e17fb6](https://github.com/nuxt/ui/commit/2e17fb68dee7e7bb27750c816d27b62249a1247b))
|
||||
* **DropdownMenu/ContextMenu:** correct bindings of `checkbox` items ([#2921](https://github.com/nuxt/ui/issues/2921)) ([4c5a4fb](https://github.com/nuxt/ui/commit/4c5a4fb5265c36a39e551b8ee43b86e9ebd3d064))
|
||||
* **FormField:** restore `eager-validation` prop behavior ([#3031](https://github.com/nuxt/ui/issues/3031)) ([41dc11c](https://github.com/nuxt/ui/commit/41dc11ceefd8f505fbc5214fe61f12483b0da4a2))
|
||||
* **InputMenu:** removing `tag` does not change `modelValue` ([#3054](https://github.com/nuxt/ui/issues/3054)) ([5a44394](https://github.com/nuxt/ui/commit/5a443944ae622c8f4a893e0a18a80026ea9c1fe0))
|
||||
* **locale:** improve Traditional Chinese translation ([#3051](https://github.com/nuxt/ui/issues/3051)) ([5c2c55f](https://github.com/nuxt/ui/commit/5c2c55ff08fbc16c869ad382e5fe5ac9fcc791de))
|
||||
* **Modal/Popover/Slideover:** rename `prevent-close` to `dismissible` + uniformize docs ([6fb426f](https://github.com/nuxt/ui/commit/6fb426fc17d6d524e7d0503c2c8f3610f60b954d))
|
||||
* **NavigationMenu:** `arrow` styles after `reka-ui` migration ([9759320](https://github.com/nuxt/ui/commit/97593204384669c479b85932024317a300ce29d8))
|
||||
* **NavigationMenu:** highlight border on children only with `vertical` orientation ([e931880](https://github.com/nuxt/ui/commit/e93188067172d357a7724f937aeec70a0dabe611))
|
||||
* **NavigationMenu:** remove `w-full` on root slot ([ef7ecd2](https://github.com/nuxt/ui/commit/ef7ecd242f4550838dbe3a45e33855afff89f506)), closes [#3000](https://github.com/nuxt/ui/issues/3000)
|
||||
* **NavigationMenu:** unbind link on collapsible trigger with `vertical` orientation ([82d6344](https://github.com/nuxt/ui/commit/82d63446a12445accbca9131a83806994631761b))
|
||||
* **SelectMenu:** handle `resetSearchTermOnBlur` manually ([#3082](https://github.com/nuxt/ui/issues/3082)) ([c902a40](https://github.com/nuxt/ui/commit/c902a40f7c0ce5ceb4624bbe2bbdfa09c87f7c75))
|
||||
* **Stepper:** correct item `value` type ([4f05b1a](https://github.com/nuxt/ui/commit/4f05b1aac9af096cdc9404395d25d2261522a1db))
|
||||
* **Stepper:** wrong `item` in `title` & `description` slots ([473194f](https://github.com/nuxt/ui/commit/473194fbaf2a9d21e2acb67d16715c412528d7d2)), closes [#2888](https://github.com/nuxt/ui/issues/2888)
|
||||
* **templates:** allow any string in colors autocomplete ([5183582](https://github.com/nuxt/ui/commit/5183582a90c0d86bd986ef0f280bc58e740c6458)), closes [#2143](https://github.com/nuxt/ui/issues/2143)
|
||||
* **templates:** infer variants types in generated theme ([2c99bb8](https://github.com/nuxt/ui/commit/2c99bb80c72fdbde9cd2ff3ad7caae0be632b864))
|
||||
* **unplugin:** invalid url schema on windows ([#2899](https://github.com/nuxt/ui/issues/2899)) ([9b4694f](https://github.com/nuxt/ui/commit/9b4694f8d9b0fc244e805a7bfb2795d5131f7d18))
|
||||
* **vue:** head injection ([#2929](https://github.com/nuxt/ui/issues/2929)) ([7302a84](https://github.com/nuxt/ui/commit/7302a846a9c394373c47def12dca00274e58f269))
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "chore(deps): update `typescript`" ([3107039](https://github.com/nuxt/ui/commit/3107039b560cef973c117a251e4407ca5e615a72))
|
||||
* Revert "chore(deps): update `@nuxt/module-builder`" ([c79acc1](https://github.com/nuxt/ui/commit/c79acc15b00f23b189821ebe2f4430e900cac34f))
|
||||
* Revert "build: remove `cjs` support" ([15b411d](https://github.com/nuxt/ui/commit/15b411de4a6a7d322a3dea5703a5a5464c4e709a))
|
||||
|
||||
## [3.0.0-alpha.10](https://github.com/nuxt/ui/compare/v3.0.0-alpha.9...v3.0.0-alpha.10) (2024-12-09)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
We're thrilled to introduce Nuxt UI v3, a significant upgrade to our UI library that delivers extensive improvements and robust new capabilities. This major update harnesses the combined strengths of [Reka UI](https://reka-ui.com/), [Tailwind CSS v4](https://tailwindcss.com/docs/v4-beta), and [Tailwind Variants](https://www.tailwind-variants.org/) to offer developers an unparalleled set of tools for creating sophisticated, accessible, and highly performant user interfaces.
|
||||
|
||||
> [!NOTE]
|
||||
> You are on the `v3` development branch, check out the [dev branch](https://github.com/nuxt/ui) for Nuxt UI v2.
|
||||
> You are on the `v3` development branch, check out the [dev branch](https://github.com/nuxt/ui/tree/dev) for Nuxt UI v2.
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -74,11 +74,18 @@ export default defineConfig({
|
||||
|
||||
```ts [main.ts]
|
||||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import ui from '@nuxt/ui/vue-plugin'
|
||||
import App from './App.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
const router = createRouter({
|
||||
routes: [],
|
||||
history: createWebHistory()
|
||||
})
|
||||
|
||||
app.use(router)
|
||||
app.use(ui)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
@@ -32,6 +32,10 @@ export default defineCommand({
|
||||
content: {
|
||||
type: 'boolean',
|
||||
description: 'Create a content component (with --pro).'
|
||||
},
|
||||
template: {
|
||||
type: 'string',
|
||||
description: 'Only generate template.'
|
||||
}
|
||||
},
|
||||
async setup({ args }) {
|
||||
@@ -53,6 +57,10 @@ export default defineCommand({
|
||||
const path = resolve('.')
|
||||
|
||||
for (const template of Object.keys(templates)) {
|
||||
if (args.template && template !== args.template) {
|
||||
continue
|
||||
}
|
||||
|
||||
const { filename, contents } = templates[template](args)
|
||||
if (!contents) {
|
||||
continue
|
||||
@@ -70,6 +78,10 @@ export default defineCommand({
|
||||
consola.success(`🪄 Generated ${filePath}!`)
|
||||
}
|
||||
|
||||
if (args.template) {
|
||||
return
|
||||
}
|
||||
|
||||
const themePath = resolve(path, `src/theme/${args.prose ? 'prose/' : ''}${args.content ? 'content/' : ''}index.ts`)
|
||||
await appendFile(themePath, `export { default as ${camelCase(name)} } from './${kebabCase(name)}'`)
|
||||
await sortFile(themePath)
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"citty": "^0.1.6",
|
||||
"consola": "^3.2.3",
|
||||
"pathe": "^1.1.2",
|
||||
"consola": "^3.3.3",
|
||||
"pathe": "^2.0.1",
|
||||
"scule": "^1.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@ const component = ({ name, primitive, pro, prose, content }) => {
|
||||
contents: primitive
|
||||
? `
|
||||
<script lang="ts">
|
||||
import { tv } from 'tailwind-variants'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
||||
import { tv } from '${pro ? '#ui/utils/tv' : '../utils/tv'}'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
||||
|
||||
@@ -57,7 +57,7 @@ export interface ${upperName}Slots {
|
||||
<script setup lang="ts">
|
||||
import { Primitive } from 'reka-ui'
|
||||
|
||||
const props = withDefaults(defineProps<${upperName}Props>(), { as: 'div' })
|
||||
const props = defineProps<${upperName}Props>()
|
||||
defineSlots<${upperName}Slots>()
|
||||
|
||||
const ui = ${camelName}()
|
||||
@@ -71,11 +71,12 @@ const ui = ${camelName}()
|
||||
`
|
||||
: `
|
||||
<script lang="ts">
|
||||
import { tv, type VariantProps } from 'tailwind-variants'
|
||||
import type { VariantProps } from 'tailwind-variants'
|
||||
import type { ${upperName}RootProps, ${upperName}RootEmits } from 'reka-ui'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/${path}/${prose ? 'prose/' : ''}${content ? 'content/' : ''}${kebabName}'
|
||||
import { tv } from '${pro ? '#ui/utils/tv' : '../utils/tv'}'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ${key}: { ${prose ? 'prose: { ' : ''}${camelName}: Partial<typeof theme> } }${prose ? ' }' : ''}
|
||||
|
||||
@@ -163,15 +164,19 @@ describe('${upperName}', () => {
|
||||
}
|
||||
}
|
||||
|
||||
const doc = ({ name, pro }) => {
|
||||
const docs = ({ name, pro, primitive }) => {
|
||||
const kebabName = kebabCase(name)
|
||||
const upperName = splitByCase(name).map(p => upperFirst(p)).join('')
|
||||
|
||||
return {
|
||||
filename: `docs/content/${pro ? 'pro' : '3.components'}/${kebabName}.md`,
|
||||
filename: `docs/content/3.components/${kebabName}.md`,
|
||||
contents: `---
|
||||
description:
|
||||
links: ${pro
|
||||
title: ${upperName}
|
||||
description: ''${pro
|
||||
? `
|
||||
module: ui-pro`
|
||||
: ''}
|
||||
links:${primitive
|
||||
? ''
|
||||
: `
|
||||
- label: ${upperName}
|
||||
@@ -190,19 +195,19 @@ links: ${pro
|
||||
|
||||
### Props
|
||||
|
||||
:component-props
|
||||
:component-props${pro ? '{pro}' : ''}
|
||||
|
||||
### Slots
|
||||
|
||||
:component-slots
|
||||
:component-slots${pro ? '{pro}' : ''}
|
||||
|
||||
### Emits
|
||||
|
||||
:component-emits
|
||||
:component-emits${pro ? '{pro}' : ''}
|
||||
|
||||
## Theme
|
||||
|
||||
:component-theme
|
||||
:component-theme${pro ? '{pro}' : ''}
|
||||
`
|
||||
}
|
||||
}
|
||||
@@ -212,5 +217,5 @@ export default {
|
||||
component,
|
||||
theme,
|
||||
test,
|
||||
doc
|
||||
docs
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ const code = computed(() => {
|
||||
|
||||
const slotsTemplate = props.themeSlots
|
||||
? genPropValue(Object.keys(props.themeSlots).filter(key => key !== 'base').reduce((acc, key) => {
|
||||
acc[key] = genPropValue(props.themeSlots?.[key])
|
||||
return acc
|
||||
}, {} as Record<string, string>))
|
||||
acc[key] = genPropValue(props.themeSlots?.[key])
|
||||
return acc
|
||||
}, {} as Record<string, string>))
|
||||
: undefined
|
||||
|
||||
const extraTemplate = [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
|
||||
export const arrayInputSchema = z.object({
|
||||
kind: z.literal('array'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
|
||||
export const booleanInputSchema = z.literal('boolean').or(z.object({
|
||||
kind: z.literal('enum'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
|
||||
export const numberInputSchema = z.literal('number')
|
||||
export type NumberInputSchema = z.infer<typeof numberInputSchema>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
|
||||
export const objectInputSchema = z.object({
|
||||
kind: z.literal('object'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
|
||||
export const stringEnumInputSchema = z.object({
|
||||
kind: z.literal('enum'),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
|
||||
export const stringInputSchema = z.literal('string').or(z.string().transform(t => t.split('|').find(s => s.trim() === 'string')).pipe(z.string()))
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/ui": "latest",
|
||||
"knitwork": "^1.1.0",
|
||||
"nuxt": "^3.14.1592",
|
||||
"knitwork": "^1.2.0",
|
||||
"nuxt": "^3.15.1",
|
||||
"prettier": "^3.4.2",
|
||||
"zod": "^3.23.8"
|
||||
"zod": "^3.24.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,4 +151,6 @@ html[data-module="ui-pro"] .ui-only,
|
||||
html[data-module="ui"] .ui-pro-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Safelist (do not remove): [&>div]:*:my-0 [&>div]:*:w-full */
|
||||
</style>
|
||||
|
||||
5
docs/app/assets/icons/fuse-js.svg
Normal file
5
docs/app/assets/icons/fuse-js.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 90">
|
||||
<g transform="translate(0,90) scale(0.1,-0.1)" fill="#9b59b6" stroke="none">
|
||||
<path d="M385 796 c-17 -12 -18 -19 -7 -109 20 -164 25 -158 -75 -77 -50 39 -97 70 -110 70 -26 0 -73 -72 -73 -112 0 -23 10 -30 103 -68 56 -24 106 -46 110 -50 4 -4 -32 -22 -80 -40 -146 -54 -155 -66 -108 -147 19 -31 32 -43 49 -43 13 0 61 29 109 65 99 75 94 80 75 -72 -11 -90 -10 -97 7 -109 24 -18 106 -18 130 0 17 12 18 19 7 109 -19 152 -24 147 75 72 47 -36 96 -65 109 -65 16 0 30 13 48 44 47 81 39 92 -107 147 -48 18 -84 36 -80 39 5 4 54 26 111 50 92 38 102 45 102 68 0 41 -47 112 -74 112 -13 0 -59 -29 -109 -70 -100 -81 -95 -86 -75 77 11 90 10 97 -7 109 -10 8 -40 14 -65 14 -25 0 -55 -6 -65 -14z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 756 B |
@@ -6,6 +6,10 @@ const value = ref<string | undefined>(undefined)
|
||||
onMounted(() => {
|
||||
value.value = framework.value
|
||||
})
|
||||
|
||||
watch(framework, () => {
|
||||
value.value = framework.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -18,6 +22,7 @@ onMounted(() => {
|
||||
indicator: 'bg-[var(--ui-bg)]',
|
||||
trigger: 'px-1 data-[state=active]:text-[var(--ui-text-highlighted)]'
|
||||
}"
|
||||
size="sm"
|
||||
@update:model-value="(framework = $event as string)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -9,19 +9,23 @@ const props = defineProps<{
|
||||
const config = useRuntimeConfig().public
|
||||
const { module } = useSharedData()
|
||||
|
||||
const value = ref<string | undefined>(module.value)
|
||||
|
||||
watch(module, () => {
|
||||
value.value = module.value
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
value.value = module.value
|
||||
})
|
||||
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
|
||||
const items = computed(() => props.links.map(({ icon, ...link }) => link))
|
||||
|
||||
defineShortcuts({
|
||||
meta_g: () => {
|
||||
window.open('https://github.com/nuxt/ui/tree/v3', '_blank')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UHeader :ui="{ left: 'min-w-0', toggle: '-mr-1.5' }" mode="drawer" :menu="{ shouldScaleBackground: true }">
|
||||
<UHeader :ui="{ left: 'min-w-0' }" mode="drawer" :menu="{ shouldScaleBackground: true }">
|
||||
<template #left>
|
||||
<NuxtLink to="/" class="flex items-end gap-2 font-bold text-xl text-[var(--ui-text-highlighted)] min-w-0 focus-visible:outline-[var(--ui-primary)] shrink-0" aria-label="Nuxt UI">
|
||||
<LogoPro class="w-auto h-6 shrink-0 ui-pro-only" />
|
||||
@@ -58,11 +62,11 @@ defineShortcuts({
|
||||
<UContentSearchButton />
|
||||
</UTooltip>
|
||||
|
||||
<UTooltip text="Open on GitHub" :kbds="['meta', 'G']" class="hidden lg:flex">
|
||||
<UTooltip text="Open on GitHub" class="hidden lg:flex">
|
||||
<UButton
|
||||
color="neutral"
|
||||
variant="ghost"
|
||||
to="https://github.com/nuxt/ui"
|
||||
:to="`https://github.com/nuxt/${value}`"
|
||||
target="_blank"
|
||||
icon="i-simple-icons-github"
|
||||
aria-label="GitHub"
|
||||
@@ -76,11 +80,19 @@ defineShortcuts({
|
||||
<USeparator type="dashed" class="mt-4 mb-6" />
|
||||
|
||||
<div class="flex flex-col gap-2 w-[calc(100%+1.25rem)] mb-5.5 -mx-2.5">
|
||||
<ModuleSelect />
|
||||
<FrameworkSelect />
|
||||
<ModuleSelect />
|
||||
</div>
|
||||
|
||||
<UContentNavigation :navigation="navigation" highlight />
|
||||
<UContentNavigation :navigation="navigation" highlight :ui="{ linkTrailingBadge: 'font-semibold uppercase' }">
|
||||
<template #link-title="{ link }">
|
||||
<span class="inline-flex items-center gap-0.5">
|
||||
{{ link.title }}
|
||||
|
||||
<sup v-if="link.module === 'ui-pro' && link.path.startsWith('/components')" class="text-[8px] font-medium text-(--ui-primary)">PRO</sup>
|
||||
</span>
|
||||
</template>
|
||||
</UContentNavigation>
|
||||
</template>
|
||||
</UHeader>
|
||||
</template>
|
||||
|
||||
@@ -6,6 +6,10 @@ const value = ref<string | undefined>(undefined)
|
||||
onMounted(() => {
|
||||
value.value = module.value
|
||||
})
|
||||
|
||||
watch(module, () => {
|
||||
value.value = module.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -14,7 +18,11 @@ onMounted(() => {
|
||||
:items="modules"
|
||||
:content="false"
|
||||
color="neutral"
|
||||
:ui="{ indicator: 'bg-[var(--ui-bg)]', trigger: 'px-1 data-[state=active]:text-[var(--ui-text-highlighted)]' }"
|
||||
:ui="{
|
||||
indicator: 'bg-[var(--ui-bg)]',
|
||||
trigger: 'px-1 data-[state=active]:text-[var(--ui-text-highlighted)]'
|
||||
}"
|
||||
size="sm"
|
||||
@update:model-value="(module = $event as string)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { upperFirst, camelCase, kebabCase } from 'scule'
|
||||
import { hash } from 'ohash'
|
||||
import { CalendarDate } from '@internationalized/date'
|
||||
import * as theme from '#build/ui'
|
||||
import * as themePro from '#build/ui-pro'
|
||||
import { get, set } from '#ui/utils'
|
||||
|
||||
interface Cast {
|
||||
@@ -40,6 +41,9 @@ const castMap: Record<string, Cast> = {
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
pro?: boolean
|
||||
prose?: boolean
|
||||
prefix?: string
|
||||
/** Override the slug taken from the route */
|
||||
slug?: string
|
||||
class?: any
|
||||
@@ -71,14 +75,32 @@ const props = defineProps<{
|
||||
* A list of line numbers to highlight in the code block
|
||||
*/
|
||||
highlights?: number[]
|
||||
/**
|
||||
* Whether to add overflow-hidden to wrapper
|
||||
*/
|
||||
overflowHidden?: boolean
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
const { $prettier } = useNuxtApp()
|
||||
|
||||
const camelName = camelCase(props.slug ?? route.params.slug?.[route.params.slug.length - 1] ?? '')
|
||||
const name = `U${upperFirst(camelName)}`
|
||||
const component = defineAsyncComponent(() => import(`#ui/components/${upperFirst(camelName)}.vue`))
|
||||
const name = `${props.prose ? 'Prose' : 'U'}${upperFirst(camelName)}`
|
||||
const component = defineAsyncComponent(() => {
|
||||
if (props.pro) {
|
||||
if (props.prefix) {
|
||||
return import(`#ui-pro/components/${props.prefix}/${upperFirst(camelName)}.vue`)
|
||||
}
|
||||
|
||||
if (props.prose) {
|
||||
return import(`#ui-pro/components/prose/${upperFirst(camelName)}.vue`)
|
||||
}
|
||||
|
||||
return import(`#ui-pro/components/${upperFirst(camelName)}.vue`)
|
||||
}
|
||||
|
||||
return import(`#ui/components/${upperFirst(camelName)}.vue`)
|
||||
})
|
||||
|
||||
const componentProps = reactive({
|
||||
...Object.fromEntries(Object.entries(props.props || {}).map(([key, value]) => {
|
||||
@@ -104,7 +126,7 @@ function setComponentProp(name: string, value: any) {
|
||||
set(componentProps, name, value)
|
||||
}
|
||||
|
||||
const componentTheme = (theme as any)[camelName]
|
||||
const componentTheme = ((props.pro ? props.prose ? themePro.prose : themePro : theme) as any)[camelName]
|
||||
const meta = await fetchComponentMeta(name as any)
|
||||
|
||||
function mapKeys(obj: object, parentKey = ''): any {
|
||||
@@ -127,16 +149,18 @@ const options = computed(() => {
|
||||
const propItems = get(props.items, key, [])
|
||||
const items = propItems.length
|
||||
? propItems.map((item: any) => ({
|
||||
value: item,
|
||||
label: item
|
||||
}))
|
||||
value: item,
|
||||
label: String(item)
|
||||
}))
|
||||
: prop?.type === 'boolean' || prop?.type === 'boolean | undefined'
|
||||
? [{ value: true, label: 'true' }, { value: false, label: 'false' }]
|
||||
: Object.keys(componentTheme?.variants?.[key] || {}).map(variant => ({
|
||||
value: variant,
|
||||
label: variant,
|
||||
chip: key.toLowerCase().endsWith('color') ? { color: variant } : undefined
|
||||
}))
|
||||
: Object.keys(componentTheme?.variants?.[key] || {}).filter((variant) => {
|
||||
return variant !== 'true' && variant !== 'false'
|
||||
}).map(variant => ({
|
||||
value: variant,
|
||||
label: variant,
|
||||
chip: key.toLowerCase().endsWith('color') ? { color: variant } : undefined
|
||||
}))
|
||||
|
||||
return {
|
||||
name: key,
|
||||
@@ -150,6 +174,30 @@ const options = computed(() => {
|
||||
const code = computed(() => {
|
||||
let code = ''
|
||||
|
||||
if (props.prose) {
|
||||
code += `\`\`\`mdc
|
||||
::${camelName}`
|
||||
|
||||
const proseProps = Object.entries(componentProps).map(([key, value]) => {
|
||||
if (value === undefined || value === null || value === '' || props.hide?.includes(key)) {
|
||||
return
|
||||
}
|
||||
|
||||
return `${key}="${value}"`
|
||||
}).filter(Boolean).join(' ')
|
||||
|
||||
if (proseProps.length) {
|
||||
code += `{${proseProps}}`
|
||||
}
|
||||
|
||||
code += `
|
||||
${props.slots?.default}
|
||||
::
|
||||
\`\`\``
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
if (props.collapse) {
|
||||
code += `::code-collapse
|
||||
`
|
||||
@@ -191,23 +239,23 @@ const code = computed(() => {
|
||||
}
|
||||
|
||||
const prop = meta?.meta?.props?.find((prop: any) => prop.name === key)
|
||||
const propDefault = prop && (prop.default ?? prop.tags?.find(tag => tag.name === 'defaultValue')?.text ?? componentTheme?.defaultVariants?.[prop.name])
|
||||
const name = kebabCase(key)
|
||||
|
||||
if (typeof value === 'boolean') {
|
||||
if (value && prop?.default === 'true') {
|
||||
if (value && (propDefault === 'true' || propDefault === '`true`' || propDefault === true)) {
|
||||
continue
|
||||
}
|
||||
if (!value && (!prop?.default || prop.default === 'false')) {
|
||||
if (!value && (!propDefault || propDefault === 'false' || propDefault === '`false`' || propDefault === false)) {
|
||||
continue
|
||||
}
|
||||
|
||||
code += value ? ` ${name}` : ` :${key}="false"`
|
||||
code += value ? ` ${name}` : ` :${name}="false"`
|
||||
} else if (typeof value === 'object') {
|
||||
const parsedValue = !props.external?.includes(key) ? json5.stringify(value, null, 2).replace(/,([ |\t\n]+[}|\])])/g, '$1') : key
|
||||
|
||||
code += ` :${name}="${parsedValue}"`
|
||||
} else {
|
||||
const propDefault = prop && (prop.default ?? prop.tags?.find(tag => tag.name === 'defaultValue')?.text ?? componentTheme?.defaultVariants?.[prop.name])
|
||||
if (propDefault === value) {
|
||||
continue
|
||||
}
|
||||
@@ -225,7 +273,7 @@ const code = computed(() => {
|
||||
code += `
|
||||
<template #${key}>
|
||||
${value}
|
||||
</template>`
|
||||
</template>\n`
|
||||
}
|
||||
}
|
||||
code += (Object.keys(props.slots).length > 1 ? '\n' : '') + `</${name}>`
|
||||
@@ -305,7 +353,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
|
||||
</USelect>
|
||||
<UInput
|
||||
v-else
|
||||
:type="option.type?.includes('number') ? 'number' : 'text'"
|
||||
:type="option.type?.includes('number') && typeof getComponentProp(option.name) === 'number' ? 'number' : 'text'"
|
||||
:model-value="getComponentProp(option.name)"
|
||||
color="neutral"
|
||||
variant="soft"
|
||||
@@ -316,7 +364,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="component" class="flex justify-center border border-b-0 border-[var(--ui-border-muted)] relative p-4 z-[1]" :class="[!options.length && 'rounded-t-[calc(var(--ui-radius)*1.5)]', props.class]">
|
||||
<div v-if="component" class="flex justify-center border border-b-0 border-[var(--ui-border-muted)] relative p-4 z-[1]" :class="[!options.length && 'rounded-t-[calc(var(--ui-radius)*1.5)]', props.class, { 'overflow-hidden': props.overflowHidden }]">
|
||||
<component :is="component" v-bind="{ ...componentProps, ...componentEvents }">
|
||||
<template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]>
|
||||
<slot :name="slot" mdc-unwrap="p">
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { upperFirst, camelCase } from 'scule'
|
||||
|
||||
const props = defineProps<{
|
||||
prose?: boolean
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const camelName = camelCase(route.params.slug?.[route.params.slug.length - 1] ?? '')
|
||||
const name = `U${upperFirst(camelName)}`
|
||||
const name = props.prose ? `Prose${upperFirst(camelName)}` : `U${upperFirst(camelName)}`
|
||||
|
||||
const meta = await fetchComponentMeta(name as any)
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { camelCase } from 'scule'
|
||||
import { useElementSize } from '@vueuse/core'
|
||||
import { get, set } from '#ui/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
name: string
|
||||
class?: any
|
||||
/**
|
||||
* Whether to render the component in an iframe
|
||||
* @defaultValue false
|
||||
*/
|
||||
iframe?: boolean | { [key: string]: any }
|
||||
/**
|
||||
* Whether to display the component in a mobile-sized iframe viewport
|
||||
* @defaultValue false
|
||||
*/
|
||||
iframeMobile?: boolean
|
||||
props?: { [key: string]: any }
|
||||
/**
|
||||
* Whether to format the code with Prettier
|
||||
@@ -42,6 +53,10 @@ const props = withDefaults(defineProps<{
|
||||
* A list of line numbers to highlight in the code block
|
||||
*/
|
||||
highlights?: number[]
|
||||
/**
|
||||
* Whether to add overflow-hidden to wrapper
|
||||
*/
|
||||
overflowHidden?: boolean
|
||||
}>(), {
|
||||
preview: true,
|
||||
source: true
|
||||
@@ -49,9 +64,13 @@ const props = withDefaults(defineProps<{
|
||||
|
||||
const slots = defineSlots<{
|
||||
options(props?: {}): any
|
||||
code(props?: {}): any
|
||||
}>()
|
||||
|
||||
const el = ref<HTMLElement | null>(null)
|
||||
|
||||
const { $prettier } = useNuxtApp()
|
||||
const { width } = useElementSize(el)
|
||||
|
||||
const camelName = camelCase(props.name)
|
||||
|
||||
@@ -112,12 +131,18 @@ const optionsValues = ref(props.options?.reduce((acc, option) => {
|
||||
}
|
||||
return acc
|
||||
}, {} as Record<string, any>) || {})
|
||||
|
||||
const urlSearchParams = computed(() => new URLSearchParams({
|
||||
...optionsValues.value,
|
||||
...componentProps,
|
||||
width: Math.round(width.value).toString()
|
||||
}).toString())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="my-5">
|
||||
<div ref="el" class="my-5">
|
||||
<template v-if="preview">
|
||||
<div class="border border-[var(--ui-border-muted)] relative z-[1]" :class="[{ 'border-b-0 rounded-t-[calc(var(--ui-radius)*1.5)]': props.source, 'rounded-[calc(var(--ui-radius)*1.5)]': !props.source }]">
|
||||
<div class="border border-[var(--ui-border-muted)] relative z-[1]" :class="[{ 'border-b-0 rounded-t-[calc(var(--ui-radius)*1.5)]': props.source, 'rounded-[calc(var(--ui-radius)*1.5)]': !props.source, 'overflow-hidden': props.overflowHidden }]">
|
||||
<div v-if="props.options?.length || !!slots.options" class="flex gap-4 p-4 border-b border-[var(--ui-border-muted)]">
|
||||
<slot name="options" />
|
||||
|
||||
@@ -169,12 +194,24 @@ const optionsValues = ref(props.options?.reduce((acc, option) => {
|
||||
</UFormField>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center p-4" :class="props.class">
|
||||
<iframe
|
||||
v-if="iframe"
|
||||
v-bind="typeof iframe === 'object' ? iframe : {}"
|
||||
:src="`/examples/${name}?${urlSearchParams}`"
|
||||
class="relative w-full"
|
||||
:class="[props.class, !iframeMobile && 'lg:left-1/2 lg:-translate-x-1/2 lg:w-[1024px]']"
|
||||
/>
|
||||
<div v-else class="flex justify-center p-4" :class="props.class">
|
||||
<component :is="camelName" v-bind="{ ...componentProps, ...optionsValues }" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<MDCRenderer v-if="ast && props.source" :body="ast.body" :data="ast.data" class="[&_pre]:!rounded-t-none [&_div.my-5]:!mt-0" />
|
||||
<template v-if="props.source">
|
||||
<div v-if="!!slots.code" class="[&_pre]:!rounded-t-none [&_div.my-5]:!mt-0">
|
||||
<slot name="code" />
|
||||
</div>
|
||||
<MDCRenderer v-else-if="ast" :body="ast.body" :data="ast.data" class="[&_pre]:!rounded-t-none [&_div.my-5]:!mt-0" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -5,8 +5,10 @@ import * as theme from '#build/ui'
|
||||
import * as themePro from '#build/ui-pro'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
name?: string
|
||||
ignore?: string[]
|
||||
pro?: boolean
|
||||
prose?: boolean
|
||||
}>(), {
|
||||
ignore: () => [
|
||||
'activeClass',
|
||||
@@ -25,17 +27,18 @@ const props = withDefaults(defineProps<{
|
||||
'exactQuery',
|
||||
'exactHash',
|
||||
'external',
|
||||
'onClick'
|
||||
'onClick',
|
||||
'viewTransition'
|
||||
]
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const camelName = camelCase(route.params.slug?.[route.params.slug.length - 1] ?? '')
|
||||
const name = `U${upperFirst(camelName)}`
|
||||
const camelName = camelCase(props.name ?? route.params.slug?.[route.params.slug.length - 1] ?? '')
|
||||
const componentName = props.prose ? `Prose${upperFirst(camelName)}` : `U${upperFirst(camelName)}`
|
||||
|
||||
const componentTheme = ((props.pro ? themePro : theme) as any)[camelName]
|
||||
const meta = await fetchComponentMeta(name as any)
|
||||
const componentTheme = ((props.pro ? props.prose ? themePro.prose : themePro : theme) as any)[camelName]
|
||||
const meta = await fetchComponentMeta(componentName as any)
|
||||
|
||||
const metaProps: ComputedRef<ComponentMeta['props']> = computed(() => {
|
||||
if (!meta?.meta?.props?.length) {
|
||||
@@ -45,7 +48,17 @@ const metaProps: ComputedRef<ComponentMeta['props']> = computed(() => {
|
||||
return meta.meta.props.filter((prop) => {
|
||||
return !props.ignore?.includes(prop.name)
|
||||
}).map((prop) => {
|
||||
prop.default = prop.default ?? prop.tags?.find(tag => tag.name === 'defaultValue')?.text ?? componentTheme?.defaultVariants?.[prop.name]
|
||||
if (prop.default) {
|
||||
prop.default = prop.default.replace(' as never', '').replace(/^"(.*)"$/, '\'$1\'')
|
||||
} else {
|
||||
const tag = prop.tags?.find(tag => tag.name === 'defaultValue')?.text
|
||||
if (tag) {
|
||||
prop.default = tag
|
||||
} else if (componentTheme?.defaultVariants?.[prop.name]) {
|
||||
prop.default = typeof componentTheme?.defaultVariants?.[prop.name] === 'string' ? `'${componentTheme?.defaultVariants?.[prop.name]}'` : componentTheme?.defaultVariants?.[prop.name]
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error - Type is not correct
|
||||
prop.type = !prop.type.startsWith('boolean') && prop.schema?.kind === 'enum' && Object.keys(prop.schema.schema)?.length ? Object.values(prop.schema.schema).map(schema => schema?.type ? schema.type : schema).join(' | ') : prop.type
|
||||
return prop
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { upperFirst, camelCase } from 'scule'
|
||||
|
||||
const props = defineProps<{
|
||||
prose?: boolean
|
||||
slug?: string
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const camelName = camelCase(route.params.slug?.[route.params.slug.length - 1] ?? '')
|
||||
const name = `U${upperFirst(camelName)}`
|
||||
const camelName = camelCase(props.slug ?? route.params.slug?.[route.params.slug.length - 1] ?? '')
|
||||
const name = `${props.prose ? 'Prose' : 'U'}${upperFirst(camelName)}`
|
||||
|
||||
const meta = await fetchComponentMeta(name as any)
|
||||
</script>
|
||||
|
||||
@@ -6,18 +6,23 @@ import * as themePro from '#build/ui-pro'
|
||||
|
||||
const props = defineProps<{
|
||||
pro?: boolean
|
||||
prose?: boolean
|
||||
slug?: string
|
||||
extra?: string[]
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
const { framework } = useSharedData()
|
||||
|
||||
const name = camelCase(route.params.slug?.[route.params.slug.length - 1] ?? '')
|
||||
const name = camelCase(props.slug ?? route.params.slug?.[route.params.slug.length - 1] ?? '')
|
||||
|
||||
const strippedCompoundVariants = ref(false)
|
||||
|
||||
const computedTheme = computed(() => props.pro ? props.prose ? themePro.prose : themePro : theme)
|
||||
|
||||
const strippedTheme = computed(() => {
|
||||
const strippedTheme = {
|
||||
...((props.pro ? themePro : theme) as any)[name]
|
||||
...(computedTheme.value as any)[name]
|
||||
}
|
||||
|
||||
if (strippedTheme?.compoundVariants) {
|
||||
@@ -54,10 +59,21 @@ const strippedTheme = computed(() => {
|
||||
})
|
||||
|
||||
const component = computed(() => {
|
||||
const baseKey = props.pro ? 'uiPro' : 'ui'
|
||||
|
||||
const content = props.prose
|
||||
? { prose: { [name]: strippedTheme.value } }
|
||||
: { [name]: strippedTheme.value }
|
||||
|
||||
if (props.extra?.length) {
|
||||
props.extra.forEach((extra) => {
|
||||
const target = props.prose ? content.prose! : content
|
||||
target[extra as keyof typeof target] = computedTheme.value[extra as keyof typeof computedTheme.value]
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
[props.pro ? 'uiPro' : 'ui']: {
|
||||
[name]: strippedTheme.value
|
||||
}
|
||||
[baseKey]: content
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -8,28 +8,29 @@ const props = withDefaults(defineProps<{
|
||||
})
|
||||
|
||||
function getEmojiFlag(locale: string): string {
|
||||
// Map language codes to default country codes
|
||||
const languageToCountry: Record<string, string> = {
|
||||
en: 'gb',
|
||||
ar: 'sa',
|
||||
cs: 'cz',
|
||||
zh: 'cn',
|
||||
da: 'dk',
|
||||
el: 'gr',
|
||||
et: 'ee',
|
||||
en: 'gb',
|
||||
ja: 'jp',
|
||||
ko: 'kr'
|
||||
kh: 'km',
|
||||
ko: 'kr',
|
||||
nb: 'no',
|
||||
sv: 'se',
|
||||
uk: 'ua',
|
||||
vi: 'vn',
|
||||
zh: 'cn'
|
||||
}
|
||||
|
||||
// Get base language code before any region specifier
|
||||
const baseLanguage = locale.split('-')[0]?.toLowerCase() || locale
|
||||
|
||||
// Use mapped country code or extract from locale if it contains a region
|
||||
const countryCode = languageToCountry[baseLanguage] || locale.replace(/^.*-/, '').slice(0, 2)
|
||||
|
||||
return countryCode
|
||||
return countryCode.toUpperCase()
|
||||
.split('')
|
||||
.map((char: string) => {
|
||||
const codePoint = char.toUpperCase().codePointAt(0)
|
||||
return codePoint ? String.fromCodePoint(0x1F1A5 + codePoint) : ''
|
||||
})
|
||||
.map(char => String.fromCodePoint(0x1F1A5 + char.charCodeAt(0)))
|
||||
.join('')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
const open = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UDrawer v-model:open="open" :dismissible="false" :ui="{ header: 'flex items-center justify-between' }">
|
||||
<UButton label="Open" color="neutral" variant="subtle" trailing-icon="i-lucide-chevron-up" />
|
||||
|
||||
<template #header>
|
||||
<h2 class="text-[var(--ui-text-highlighted)] font-semibold">
|
||||
Drawer non-dismissible
|
||||
</h2>
|
||||
|
||||
<UButton color="neutral" variant="ghost" icon="i-lucide-x" @click="open = false" />
|
||||
</template>
|
||||
|
||||
<template #body>
|
||||
<Placeholder class="h-48" />
|
||||
</template>
|
||||
</UDrawer>
|
||||
</template>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui'
|
||||
|
||||
const schema = z.object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui'
|
||||
|
||||
const schema = z.object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui'
|
||||
|
||||
const schema = z.object({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
|
||||
const schema = z.object({
|
||||
|
||||
@@ -4,12 +4,21 @@ const modal = useModal()
|
||||
defineProps<{
|
||||
count: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
function onSuccess() {
|
||||
emit('success')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UModal :title="`This modal was opened programmatically ${count} times`">
|
||||
<template #footer>
|
||||
<UButton color="neutral" label="Close" @click="modal.close()" />
|
||||
<div class="flex gap-2">
|
||||
<UButton color="neutral" label="Close" @click="modal.close()" />
|
||||
<UButton label="Success" @click="onSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LazyModalExample } from '#components'
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
const toast = useToast()
|
||||
const modal = useModal()
|
||||
|
||||
function open() {
|
||||
@@ -10,7 +11,13 @@ function open() {
|
||||
|
||||
modal.open(LazyModalExample, {
|
||||
description: 'And you can even provide a description!',
|
||||
count: count.value
|
||||
count: count.value,
|
||||
onSuccess() {
|
||||
toast.add({
|
||||
title: 'Success !',
|
||||
id: 'modal-success'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -59,7 +59,7 @@ const items = [
|
||||
<template>
|
||||
<UNavigationMenu
|
||||
:items="items"
|
||||
class="justify-center"
|
||||
class="w-full justify-center"
|
||||
:ui="{
|
||||
viewport: 'sm:w-[var(--reka-navigation-menu-viewport-width)]',
|
||||
childList: 'sm:w-96',
|
||||
|
||||
@@ -19,7 +19,7 @@ const items = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UNavigationMenu :items="items" class="justify-center">
|
||||
<UNavigationMenu :items="items" class="w-full justify-center">
|
||||
<template #components-trailing>
|
||||
<UBadge label="44" variant="subtle" size="sm" />
|
||||
</template>
|
||||
|
||||
@@ -111,5 +111,5 @@ defineShortcuts({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UNavigationMenu v-model="active" :items="items" class="justify-center" />
|
||||
<UNavigationMenu v-model="active" :items="items" class="w-full justify-center" />
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
const open = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UPopover v-model:open="open" :dismissible="false" :ui="{ content: 'p-4' }">
|
||||
<UButton label="Open" color="neutral" variant="subtle" />
|
||||
|
||||
<template #content>
|
||||
<div class="flex items-center gap-4 mb-4">
|
||||
<h2 class="text-[var(--ui-text-highlighted)] font-semibold">
|
||||
Popover non-dismissible
|
||||
</h2>
|
||||
|
||||
<UButton color="neutral" variant="ghost" icon="i-lucide-x" @click="open = false" />
|
||||
</div>
|
||||
|
||||
<Placeholder class="size-full min-h-48" />
|
||||
</template>
|
||||
</UPopover>
|
||||
</template>
|
||||
@@ -4,6 +4,12 @@ const slideover = useSlideover()
|
||||
defineProps<{
|
||||
count: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
function onSuccess() {
|
||||
emit('success')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -13,7 +19,10 @@ defineProps<{
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<UButton color="neutral" label="Close" @click="slideover.close()" />
|
||||
<div class="flex gap-2">
|
||||
<UButton color="neutral" label="Close" @click="slideover.close()" />
|
||||
<UButton label="Success" @click="onSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
</USlideover>
|
||||
</template>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { LazySlideoverExample } from '#components'
|
||||
|
||||
const count = ref(0)
|
||||
|
||||
const toast = useToast()
|
||||
const slideover = useSlideover()
|
||||
|
||||
function open() {
|
||||
@@ -10,7 +11,13 @@ function open() {
|
||||
|
||||
slideover.open(LazySlideoverExample, {
|
||||
title: 'Slideover',
|
||||
count: count.value
|
||||
count: count.value,
|
||||
onSuccess() {
|
||||
toast.add({
|
||||
title: 'Success !',
|
||||
id: 'modal-success'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -15,13 +15,13 @@ export function useSharedData() {
|
||||
|
||||
const module = useCookie('nuxt-ui-module', { default: () => 'ui' })
|
||||
const modules = computed(() => [{
|
||||
label: 'nuxt/ui',
|
||||
label: 'UI',
|
||||
icon: 'i-lucide-box',
|
||||
value: 'ui',
|
||||
onSelect: () => module.value = 'ui'
|
||||
}, {
|
||||
label: 'nuxt/ui-pro',
|
||||
icon: 'i-lucide-boxes',
|
||||
label: 'UI Pro',
|
||||
icon: 'i-lucide-panels-top-left',
|
||||
value: 'ui-pro',
|
||||
disabled: framework.value === 'vue',
|
||||
onSelect: () => module.value = 'ui-pro'
|
||||
|
||||
@@ -12,12 +12,20 @@ const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
<UPageAside>
|
||||
<template #top>
|
||||
<div class="flex flex-col gap-2 w-[calc(100%+1.25rem)] -mx-2.5">
|
||||
<ModuleSelect />
|
||||
<FrameworkSelect />
|
||||
<ModuleSelect />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<UContentNavigation :navigation="navigation" highlight />
|
||||
<UContentNavigation :navigation="navigation" highlight :ui="{ linkTrailingBadge: 'font-semibold uppercase' }">
|
||||
<template #link-title="{ link }">
|
||||
<span class="inline-flex items-center gap-0.5">
|
||||
{{ link.title }}
|
||||
|
||||
<sup v-if="link.module === 'ui-pro'" class="text-[8px] font-medium text-(--ui-primary)">PRO</sup>
|
||||
</span>
|
||||
</template>
|
||||
</UContentNavigation>
|
||||
</UPageAside>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -14,6 +14,16 @@ if (!page.value) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
|
||||
}
|
||||
|
||||
// Update the framework/module if the page has different ones
|
||||
watch(page, () => {
|
||||
if (page.value?.framework && page.value?.framework !== framework.value) {
|
||||
framework.value = page.value?.framework as string
|
||||
}
|
||||
if (page.value?.module && page.value?.module !== module.value) {
|
||||
module.value = page.value?.module as string
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
|
||||
return queryCollectionItemSurroundings('content', route.path, {
|
||||
fields: ['description']
|
||||
@@ -53,20 +63,11 @@ if (!import.meta.prerender) {
|
||||
})
|
||||
}
|
||||
|
||||
// Update the framework/module if the page has different ones
|
||||
watch(page, () => {
|
||||
if (page.value?.framework && page.value?.framework !== framework.value) {
|
||||
framework.value = page.value?.framework as string
|
||||
}
|
||||
if (page.value?.module && page.value?.module !== module.value) {
|
||||
module.value = page.value?.module as string
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
const type = page.value?.path.includes('components') ? 'Vue Component ' : page.value?.path.includes('composables') ? 'Vue Composable ' : ''
|
||||
useSeoMeta({
|
||||
titleTemplate: `%s - Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} v3${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||
titleTemplate: `%s ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} v3${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||
title: page.value.navigation?.title ? page.value.navigation.title : page.value.title,
|
||||
ogTitle: `${page.value.navigation?.title ? page.value.navigation.title : page.value.title} - Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} v3${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||
ogTitle: `${page.value.navigation?.title ? page.value.navigation.title : page.value.title} ${type}- Nuxt UI ${page.value.module === 'ui-pro' ? 'Pro' : ''} v3${page.value.framework === 'vue' ? ' for Vue' : ''}`,
|
||||
description: page.value.description,
|
||||
ogDescription: page.value.description
|
||||
})
|
||||
@@ -78,13 +79,21 @@ defineOgImageComponent('Docs', {
|
||||
const communityLinks = computed(() => [{
|
||||
icon: 'i-lucide-file-pen',
|
||||
label: 'Edit this page',
|
||||
to: `https://github.com/nuxt/ui/edit/v3/docs/content/${page?.value?.stem}.md`,
|
||||
to: `https://github.com/nuxt/${page.value?.module === 'ui-pro' ? 'ui-pro' : 'ui'}/edit/v3/docs/content/${page?.value?.stem}.md`,
|
||||
target: '_blank'
|
||||
}, {
|
||||
icon: 'i-lucide-star',
|
||||
label: 'Star on GitHub',
|
||||
to: 'https://github.com/nuxt/ui',
|
||||
to: `https://github.com/nuxt/${page.value?.module === 'ui-pro' ? 'ui-pro' : 'ui'}`,
|
||||
target: '_blank'
|
||||
}, {
|
||||
icon: 'i-heroicons-lifebuoy',
|
||||
label: 'Contribution',
|
||||
to: '/getting-started/contribution'
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
icon: 'i-heroicons-map',
|
||||
to: '/roadmap'
|
||||
}])
|
||||
|
||||
// const resourcesLinks = [{
|
||||
@@ -122,7 +131,7 @@ const communityLinks = computed(() => [{
|
||||
:key="link.label"
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
target="_blank"
|
||||
:target="link.to.startsWith('http') ? '_blank' : undefined"
|
||||
v-bind="link"
|
||||
>
|
||||
<template v-if="link.avatar" #leading>
|
||||
@@ -135,7 +144,7 @@ const communityLinks = computed(() => [{
|
||||
<UPageBody>
|
||||
<ContentRenderer v-if="page.body" :value="page" />
|
||||
|
||||
<USeparator />
|
||||
<USeparator v-if="surround?.filter(Boolean).length" />
|
||||
|
||||
<UContentSurround :surround="(surround as any)" />
|
||||
</UPageBody>
|
||||
|
||||
@@ -2,10 +2,20 @@
|
||||
const route = useRoute()
|
||||
|
||||
const name = route.params.slug?.[0]
|
||||
|
||||
const width = computed(() => route.query.width && Number.parseInt(route.query.width as string) > 0 ? `${Number.parseInt(route.query.width as string) - 2}px` : '864px')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-4 flex flex-col justify-center h-screen overflow-auto">
|
||||
<component :is="name" />
|
||||
<div class="example flex flex-col items-center h-screen">
|
||||
<component :is="name" v-bind="route.query" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@media (min-width: 1024px) {
|
||||
.example {
|
||||
--ui-container: v-bind(width);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,6 +8,8 @@ We're thrilled to introduce this major update to our UI library, bringing signif
|
||||
|
||||
## What's New in v3?
|
||||
|
||||
<iframe width="100%" height="100%" src="https://www.youtube-nocookie.com/embed/_eQxomah-nA?si=pDSzchUBDKb2NQu7" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen style="aspect-ratio: 16/9;"></iframe>
|
||||
|
||||
### Reka UI (Radix Vue)
|
||||
|
||||
We've transitioned from [Headless UI](https://headlessui.com/) to [Reka UI](https://reka-ui.com/) as our core component foundation. This shift brings several key advantages:
|
||||
@@ -28,7 +30,7 @@ Nuxt UI v3 integrates the latest Tailwind CSS v4 beta (released Nov 21, 2024), b
|
||||
- **CSS-first configuration**: A reimagined developer experience where you customize and extend the framework directly in CSS instead of a JavaScript configuration file.
|
||||
- **Designed for the modern web**: Built on native cascade layers, wide-gamut colors, and including first-class support for modern CSS features like container queries, @starting-style, popovers, and more.
|
||||
|
||||
::note{to="https://tailwindcss.com/docs/v4-beta" target="_blank"}
|
||||
::note{to="https://tailwindcss.com/docs/v4-beta" target="_blank" aria-label="Tailwind CSS v4 beta documentation"}
|
||||
For a comprehensive overview of Tailwind CSS v4 beta features, read the **prerelease documentation**.
|
||||
::
|
||||
|
||||
@@ -58,7 +60,7 @@ Nuxt UI v3 offers significantly improved TypeScript integration, providing a sup
|
||||
- Leveraging Tailwind Variants for type-safe styling options
|
||||
- Customizable types for extended theme configurations
|
||||
|
||||
::note{to="/components/accordion#with-custom-slot"}
|
||||
::note{to="/components/accordion#with-custom-slot" aria-label="Accordion component with custom slot"}
|
||||
Check out an example of the Accordion component with auto-completion for props and slots.
|
||||
::
|
||||
|
||||
@@ -70,15 +72,30 @@ You can now use Nuxt UI in any Vue project without Nuxt by adding the Vite and V
|
||||
- **Theming System**: Full theming support with customizable colors, sizes, variants and more
|
||||
- **Developer Experience**: Complete TypeScript support with IntelliSense and auto-completion
|
||||
|
||||
::tip{to="/getting-started/installation/vue"}
|
||||
::tip{to="/getting-started/installation/vue" aria-label="Vue installation guide"}
|
||||
Learn how to install and configure Nuxt UI in a Vue project in the **Vue installation guide**.
|
||||
::
|
||||
|
||||
## Nuxt DevTools Integration
|
||||
|
||||
Nuxt UI is deeply integrated with Nuxt Devtools, providing a powerful development experience:
|
||||
|
||||
- **Component Inspector**: Inspect and analyze Nuxt UI components in real-time
|
||||
- **Live Preview**: Modify component props and see changes instantly
|
||||
- **Code Generation**: Get the corresponding code for your component configurations
|
||||
|
||||
::video{poster="https://res.cloudinary.com/nuxt/video/upload/so_0/v1736788078/nuxt-ui/nuxt-ui3-devtools_wbmgmc.jpg" controls class="w-full h-auto rounded"}
|
||||
:source{src="https://res.cloudinary.com/nuxt/video/upload/v1736788078/nuxt-ui/nuxt-ui3-devtools_wbmgmc.webm" type="video/webm"}
|
||||
:source{src="https://res.cloudinary.com/nuxt/video/upload/v1736788078/nuxt-ui/nuxt-ui3-devtools_wbmgmc.mp4" type="video/mp4"}
|
||||
:source{src="https://res.cloudinary.com/nuxt/video/upload/v1736788078/nuxt-ui/nuxt-ui3-devtools_wbmgmc.ogg" type="video/ogg"}
|
||||
::
|
||||
|
||||
## Migration
|
||||
|
||||
We want to be transparent: migrating from Nuxt UI v2 to v3 will require significant effort. While we've maintained core concepts and components, Nuxt UI v3 has been rebuilt from the ground up, resulting in a new library with enhanced capabilities.
|
||||
|
||||
Key points to consider:
|
||||
|
||||
- A comprehensive migration guide will be available in the coming weeks.
|
||||
- Review the new documentation and components carefully before attempting to upgrade.
|
||||
- If you encounter any issues, please report them on our [GitHub repository](https://github.com/nuxt/ui/issues).
|
||||
|
||||
@@ -3,6 +3,10 @@ title: Installation
|
||||
description: 'Learn how to install and configure Nuxt UI in your Nuxt application.'
|
||||
framework: nuxt
|
||||
module: ui
|
||||
links:
|
||||
- label: Playground
|
||||
to: https://codesandbox.io/p/devbox/nuxt-ui3-n3sxks
|
||||
icon: i-lucide-codesandbox
|
||||
---
|
||||
|
||||
::callout{to="/getting-started/installation/vue" icon="i-logos-vue" class="hidden"}
|
||||
@@ -65,12 +69,13 @@ export default defineNuxtConfig({
|
||||
css: ['~/assets/css/main.css']
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-visualstudiocode"}
|
||||
It's recommended to install the [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and add the following settings:
|
||||
|
||||
```json [settings.json]
|
||||
```json [.vscode/settings.json]
|
||||
"files.associations": {
|
||||
"*.css": "tailwindcss"
|
||||
},
|
||||
@@ -99,12 +104,12 @@ The `App` component provides global configurations and is required for **Toast**
|
||||
|
||||
### Use our Nuxt Starter
|
||||
|
||||
Start your project with a Nuxt template with Nuxt UI v3 pre-configured by using our [Nuxt UI Starter](https://github.com/nuxt/starter/tree/ui3).
|
||||
Start your project using the [nuxt/starter#ui3](https://github.com/nuxt/starter/tree/ui3) template with Nuxt UI v3 pre-configured.
|
||||
|
||||
Create a new project locally by running the following command:
|
||||
|
||||
```bash [Terminal]
|
||||
npx nuxi@latest init -t ui3 <my-app>
|
||||
npx nuxi init -t ui3 <my-app>
|
||||
```
|
||||
|
||||
::note
|
||||
|
||||
@@ -3,6 +3,10 @@ title: Installation
|
||||
description: 'Learn how to install and configure Nuxt UI in your Vue application.'
|
||||
framework: vue
|
||||
module: ui
|
||||
links:
|
||||
- label: Playground
|
||||
to: https://codesandbox.io/p/devbox/nuxt-ui3-vue-4h5gqn
|
||||
icon: i-lucide-codesandbox
|
||||
---
|
||||
|
||||
::callout{to="/getting-started/installation/nuxt" icon="i-logos-nuxt-icon" class="hidden"}
|
||||
@@ -11,6 +15,8 @@ Looking for the **Nuxt** version?
|
||||
|
||||
## Setup
|
||||
|
||||
### Add to a Vue project
|
||||
|
||||
::steps{level="4"}
|
||||
|
||||
#### Install the Nuxt UI v3 alpha package
|
||||
@@ -68,17 +74,25 @@ Nuxt UI registers `unplugin-auto-import` and `unplugin-vue-components`, which wi
|
||||
auto-imports.d.ts
|
||||
components.d.ts
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
#### Use the Nuxt UI Vue plugin in your `main.ts`
|
||||
|
||||
```ts [main.ts]{2,7}
|
||||
```ts [main.ts]{3,14}
|
||||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import ui from '@nuxt/ui/vue-plugin'
|
||||
import App from './App.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
const router = createRouter({
|
||||
routes: [],
|
||||
history: createWebHistory()
|
||||
})
|
||||
|
||||
app.use(router)
|
||||
app.use(ui)
|
||||
|
||||
app.mount('#app')
|
||||
@@ -98,21 +112,29 @@ Import the CSS file in your `main.ts`.
|
||||
import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import ui from '@nuxt/ui/vue-plugin'
|
||||
import App from './App.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
const router = createRouter({
|
||||
routes: [],
|
||||
history: createWebHistory()
|
||||
})
|
||||
|
||||
app.use(router)
|
||||
app.use(ui)
|
||||
|
||||
app.mount('#app')
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-visualstudiocode"}
|
||||
It's recommended to install the [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and add the following settings:
|
||||
|
||||
```json [settings.json]
|
||||
```json [.vscode/settings.json]
|
||||
"files.associations": {
|
||||
"*.css": "tailwindcss"
|
||||
},
|
||||
@@ -139,6 +161,27 @@ The `App` component provides global configurations and is required for **Toast**
|
||||
|
||||
::
|
||||
|
||||
### Use our Vue starter
|
||||
|
||||
Start your project using the [nuxtlabs/nuxt-ui3-vue-starter](https://github.com/nuxtlabs/nuxt-ui3-vue-starter) template with Nuxt UI v3 pre-configured.
|
||||
|
||||
Create a new project locally by running the following command:
|
||||
|
||||
```bash [Terminal]
|
||||
npx nuxi init -t github:nuxtlabs/nuxt-ui3-vue-starter <my-app>
|
||||
```
|
||||
|
||||
::note
|
||||
The `<my-app>` argument is the name of the directory where the project will be created, replace it with your project name.
|
||||
::
|
||||
|
||||
Once the installation is complete, navigate into your project and start the development server:
|
||||
|
||||
```bash [Terminal]
|
||||
cd <my-app>
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
You can customize Nuxt UI by providing options in your `vite.config.ts`.
|
||||
|
||||
@@ -14,6 +14,7 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
@@ -36,10 +37,12 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
|
||||
--color-green-950: #052E16;
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
@@ -62,6 +65,7 @@ Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your
|
||||
--color-green-950: #052E16;
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -80,22 +84,26 @@ This can be useful when writing Tailwind classes in markdown files with [`@nuxt/
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
@source "../content";
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
@source "../content";
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -110,22 +118,26 @@ You can use the `@plugin` directive to import Tailwind CSS plugins.
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
|
||||
@plugin "@tailwindcss/typography";
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
@plugin "@tailwindcss/typography";
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -172,6 +184,7 @@ export default defineAppConfig({
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
#vue
|
||||
@@ -197,6 +210,7 @@ export default defineConfig({
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
::
|
||||
@@ -240,6 +254,7 @@ export default defineNuxtConfig({
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#vue
|
||||
@@ -267,6 +282,7 @@ export default defineConfig({
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -277,7 +293,8 @@ However, you can generate these classes using Tailwind's `@theme` directive, all
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
@@ -296,10 +313,12 @@ However, you can generate these classes using Tailwind's `@theme` directive, all
|
||||
--color-primary-950: var(--ui-color-primary-950);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
@@ -318,6 +337,7 @@ However, you can generate these classes using Tailwind's `@theme` directive, all
|
||||
--color-primary-950: var(--ui-color-primary-950);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -366,7 +386,8 @@ You can change which shade is used for each color on light and dark mode:
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
@@ -379,10 +400,12 @@ You can change which shade is used for each color on light and dark mode:
|
||||
--ui-primary: var(--ui-color-primary-200);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
@@ -395,6 +418,7 @@ You can change which shade is used for each color on light and dark mode:
|
||||
--ui-primary: var(--ui-color-primary-200);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -486,6 +510,7 @@ body {
|
||||
@apply antialiased text-[var(--ui-text)] bg-[var(--ui-bg)];
|
||||
}
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
::tip
|
||||
@@ -493,7 +518,8 @@ You can customize these CSS variables to tailor the appearance of your applicati
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
@@ -508,10 +534,12 @@ You can customize these CSS variables to tailor the appearance of your applicati
|
||||
--ui-border: var(--ui-color-neutral-900);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
@@ -526,6 +554,7 @@ You can customize these CSS variables to tailor the appearance of your applicati
|
||||
--ui-border: var(--ui-color-neutral-900);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -550,7 +579,8 @@ You can customize the default radius value using the default Tailwind CSS variab
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
@@ -559,10 +589,12 @@ You can customize the default radius value using the default Tailwind CSS variab
|
||||
--ui-radius: var(--radius-sm);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
@@ -571,6 +603,7 @@ You can customize the default radius value using the default Tailwind CSS variab
|
||||
--ui-radius: var(--radius-sm);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -591,7 +624,8 @@ You can customize the default container width using the default Tailwind CSS var
|
||||
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
@@ -604,10 +638,12 @@ You can customize the default container width using the default Tailwind CSS var
|
||||
--ui-container: var(--container-8xl);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
:::div{class="*:!mb-0 *:!mt-2.5"}
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
@@ -620,6 +656,7 @@ You can customize the default container width using the default Tailwind CSS var
|
||||
--ui-container: var(--container-8xl);
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
@@ -758,6 +795,7 @@ You can explore the theme for each component in two ways:
|
||||
|
||||
- Check the `Theme` section in the documentation of each individual component.
|
||||
- Browse the source code directly in the GitHub repository at [`v3/src/theme`](https://github.com/nuxt/ui/tree/v3/src/theme).
|
||||
|
||||
::
|
||||
|
||||
### Config
|
||||
@@ -780,6 +818,7 @@ export default defineAppConfig({
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
#vue
|
||||
@@ -808,6 +847,7 @@ export default defineConfig({
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
::
|
||||
|
||||
@@ -34,7 +34,7 @@ props:
|
||||
::
|
||||
|
||||
::note
|
||||
You can use any name from the https://icones.js.org collection.
|
||||
You can use any name from the <https://icones.js.org> collection.
|
||||
::
|
||||
|
||||
### Component Props
|
||||
|
||||
@@ -28,7 +28,7 @@ props:
|
||||
::
|
||||
|
||||
::note
|
||||
You can use any name from the https://icones.js.org collection.
|
||||
You can use any name from the <https://icones.js.org> collection.
|
||||
::
|
||||
|
||||
### Component Props
|
||||
|
||||
@@ -16,6 +16,7 @@ Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/font
|
||||
::module-only
|
||||
#ui
|
||||
:::div
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
@@ -24,10 +25,12 @@ Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/font
|
||||
--font-sans: 'Public Sans', sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#ui-pro
|
||||
:::div
|
||||
|
||||
```css [main.css]
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui-pro";
|
||||
@@ -36,6 +39,7 @@ Nuxt UI automatically registers the [`@nuxt/fonts`](https://github.com/nuxt/font
|
||||
--font-sans: 'Public Sans', sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
::
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
badge: New
|
||||
shadow: true
|
||||
|
||||
@@ -55,8 +55,10 @@ const locale = defineLocale({
|
||||
|
||||
::tip
|
||||
Look at the `code` parameter, there you need to pass the iso code of the language. Example:
|
||||
|
||||
* `hi` Hindi (language)
|
||||
* `de-AT`: German (language) as used in Austria (region)
|
||||
|
||||
::
|
||||
|
||||
### Dynamic locale
|
||||
|
||||
@@ -57,8 +57,10 @@ const locale = defineLocale({
|
||||
|
||||
::tip
|
||||
Look at the `code` parameter, there you need to pass the iso code of the language. Example:
|
||||
|
||||
* `hi` Hindi (language)
|
||||
* `de-AT`: German (language) as used in Austria (region)
|
||||
|
||||
::
|
||||
|
||||
### Dynamic locale
|
||||
@@ -91,12 +93,20 @@ bun add vue-i18n@10
|
||||
|
||||
#### Use the Vue I18n plugin in your `main.ts`
|
||||
|
||||
```ts [main.ts]{2,6-18,22}
|
||||
```ts [main.ts]{3,14-26,29}
|
||||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import ui from '@nuxt/ui/vue-plugin'
|
||||
import App from './App.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
const router = createRouter({
|
||||
routes: [],
|
||||
history: createWebHistory()
|
||||
})
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
@@ -111,8 +121,7 @@ const i18n = createI18n({
|
||||
}
|
||||
})
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(router)
|
||||
app.use(i18n)
|
||||
app.use(ui)
|
||||
|
||||
|
||||
253
docs/content/1.getting-started/contribution.md
Normal file
253
docs/content/1.getting-started/contribution.md
Normal file
@@ -0,0 +1,253 @@
|
||||
---
|
||||
title: Contribution Guide
|
||||
description: 'A comprehensive guide on contributing to Nuxt UI v3, including project structure, development workflow, and best practices.'
|
||||
navigation: false
|
||||
---
|
||||
|
||||
Nuxt UI thrives thanks to its incredible community ❤️. We welcome all contributions through bug reports, pull requests, and feedback to help make this library even better.
|
||||
|
||||
::caution
|
||||
Before reporting a bug or requesting a feature, make sure that you have read through our [documentation](https://ui3.nuxt.dev/) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue%20is%3Aopen%20sort%3Aupdated-desc%20label%3Av3).
|
||||
::
|
||||
|
||||
## Project Structure
|
||||
|
||||
Here's an overview of the key directories and files in the Nuxt UI project structure:
|
||||
|
||||
### Documentation
|
||||
|
||||
The documentation lives in the `docs` folder as a Nuxt app using `@nuxt/content` v3 to generate pages from Markdown files. See the [Content v3 Docs](https://content3.nuxt.dev/docs/getting-started) for details on how it works. Here's a breakdown of its structure:
|
||||
|
||||
```bash
|
||||
├── app/
|
||||
│ ├── assets/
|
||||
│ ├── components/
|
||||
│ │ └── content/
|
||||
│ │ └── examples # Components used in documentation as examples
|
||||
│ ├── composables/
|
||||
│ └── ...
|
||||
├── content/
|
||||
│ ├── 1.getting-started
|
||||
│ ├── 2.composables
|
||||
│ └── 3.components # Components documentation
|
||||
```
|
||||
|
||||
### Module
|
||||
|
||||
The module code resides in the `src` folder. Here's a breakdown of its structure:
|
||||
|
||||
```bash
|
||||
├── devtools/
|
||||
├── plugins/
|
||||
├── runtime/
|
||||
│ ├── components/ # Where all the components are located
|
||||
│ │ ├── Accordion.vue
|
||||
│ │ ├── Alert.vue
|
||||
│ │ └── ...
|
||||
│ ├── composables/
|
||||
│ ├── locale/
|
||||
│ ├── plugins/
|
||||
│ ├── types/
|
||||
│ ├── utils/
|
||||
│ └── vue/
|
||||
│ ├── components/
|
||||
│ └── plugins/
|
||||
├── theme/ # This where the theme for each component is located
|
||||
│ ├── accordion.ts # Theme for Accordion component
|
||||
│ ├── alert.ts
|
||||
│ └── ...
|
||||
└── module.ts
|
||||
```
|
||||
|
||||
## CLI
|
||||
|
||||
To make development easier, we've created a CLI that you can use to generate components and locales. You can access it using the `nuxt-ui make` command.
|
||||
|
||||
First, you need to link the CLI to your global environment:
|
||||
|
||||
```sh
|
||||
npm link
|
||||
```
|
||||
|
||||
### Components
|
||||
|
||||
You can create new components using the following command:
|
||||
|
||||
```sh
|
||||
nuxt-ui make component <name> [options]
|
||||
```
|
||||
|
||||
Available options:
|
||||
|
||||
- `--primitive` Create a primitive component
|
||||
- `--pro` Create a pro component
|
||||
- `--prose` Create a prose component (requires `--pro`)
|
||||
- `--content` Create a content component (requires `--pro`)
|
||||
- `--template` Only generate specific template (available templates: `playground`, `docs`, `test`, `theme`, `component`)
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
# Create a basic component
|
||||
nuxt-ui make component my-component
|
||||
|
||||
# Create a pro component
|
||||
nuxt-ui make component page-section --pro
|
||||
|
||||
# Create a pro prose component
|
||||
nuxt-ui make component heading --pro --prose
|
||||
|
||||
# Create a pro content component
|
||||
nuxt-ui make component block --pro --content
|
||||
|
||||
# Generate only documentation template
|
||||
nuxt-ui make component my-component --template=docs
|
||||
```
|
||||
|
||||
::note
|
||||
When creating a new component, the CLI will automatically generate all the necessary files like the component itself, theme, tests, and documentation.
|
||||
::
|
||||
|
||||
### Locales
|
||||
|
||||
You can create new locales using the following command:
|
||||
|
||||
```sh
|
||||
nuxt-ui make locale --code <code> --name <name>
|
||||
```
|
||||
|
||||
::note{to="/getting-started/i18n/nuxt#supported-languages"}
|
||||
Learn more about **i18n** in the documentation.
|
||||
::
|
||||
|
||||
## Submit a Pull Request (PR)
|
||||
|
||||
Before you start, check if there's an existing issue describing the problem or feature request you're working on. If there is, please leave a comment on the issue to let us know you're working on it.
|
||||
|
||||
If there isn't, open a new issue to discuss the problem or feature.
|
||||
|
||||
### Local Development
|
||||
|
||||
To begin local development, follow these steps:
|
||||
|
||||
::steps{level="4"}
|
||||
|
||||
#### Clone the `nuxt/ui` repository to your local machine
|
||||
|
||||
```sh
|
||||
git clone -b v3 https://github.com/nuxt/ui.git
|
||||
```
|
||||
|
||||
#### Enable [Corepack](https://github.com/nodejs/corepack)
|
||||
|
||||
```sh
|
||||
corepack enable
|
||||
```
|
||||
|
||||
#### Install dependencies
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
```
|
||||
|
||||
#### Generate type stubs
|
||||
|
||||
```sh
|
||||
pnpm run dev:prepare
|
||||
```
|
||||
|
||||
#### Start development
|
||||
|
||||
- To work on the **documentation** located in the `docs` folder, run:
|
||||
|
||||
```sh
|
||||
pnpm run docs
|
||||
```
|
||||
|
||||
- To test the Nuxt components using the **playground**, run:
|
||||
|
||||
```sh
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
- To test the Vue components using the **playground**, run:
|
||||
|
||||
```sh
|
||||
pnpm run dev:vue
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
::note{to="#cli"}
|
||||
If you're working on implementing a new component, check the **CLI** section to kickstart the process.
|
||||
::
|
||||
|
||||
### IDE Setup
|
||||
|
||||
We recommend using VSCode alongside the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint). You can enable auto-fix and formatting when saving your code. Here's how:
|
||||
|
||||
```json
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": false,
|
||||
"source.fixAll.eslint": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
::warning
|
||||
Since ESLint is already configured to format the code, there's no need for duplicating functionality with **Prettier**. If you have it installed in your editor, we recommend disabling it to avoid conflicts.
|
||||
::
|
||||
|
||||
### Linting
|
||||
|
||||
You can use the `lint` command to check for linting errors:
|
||||
|
||||
```sh
|
||||
pnpm run lint # check for linting errors
|
||||
pnpm run lint:fix # fix linting errors
|
||||
```
|
||||
|
||||
### Type Checking
|
||||
|
||||
We use TypeScript for type checking. You can use the `typecheck` command to check for type errors:
|
||||
|
||||
```sh
|
||||
pnpm run typecheck
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
Before submitting a PR, ensure that you run the tests for both `nuxt` and `vue`:
|
||||
|
||||
```sh
|
||||
pnpm run test # for Nuxt
|
||||
pnpm run test:vue # for Vue
|
||||
```
|
||||
|
||||
::tip
|
||||
If you have to update the snapshots, press `u` when running the tests.
|
||||
::
|
||||
|
||||
### Commit Conventions
|
||||
|
||||
We use [Conventional Commits](https://www.conventionalcommits.org/) for commit messages, which allows a changelog to be auto-generated based on the commits. Please read the [guide](https://www.conventionalcommits.org/en/v1.0.0/#summary) through if you aren't familiar with it already.
|
||||
|
||||
- Use `fix` and `feat` for code changes that affect functionality or logic
|
||||
- Use `docs` for documentation changes and `chore` for maintenance tasks
|
||||
|
||||
### Making a Pull Request
|
||||
|
||||
- Follow along the [instructions](https://github.com/nuxt/ui/blob/v3/.github/PULL_REQUEST_TEMPLATE.md?plain=1) provided when creating a PR
|
||||
|
||||
- Ensure your PR's title adheres to the [Conventional Commits](https://www.conventionalcommits.org/) since it will be used once the code is merged.
|
||||
|
||||
- Multiple commits are fine; no need to rebase or force push. We'll use `Squash and Merge` when merging.
|
||||
|
||||
- Ensure `lint`, `typecheck` and `tests` work before submitting the PR. Avoid making unrelated changes.
|
||||
|
||||
We'll review it promptly. If assigned to a maintainer, they'll review it carefully. Ignore the red text; it's for tracking purposes.
|
||||
|
||||
## Thanks
|
||||
|
||||
Thank you again for being interested in this project! You are awesome! ❤️
|
||||
@@ -131,7 +131,7 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
You can also pass all the props of the [Button](/components/button) component to customize it.
|
||||
You can pass any property from the [Button](/components/button) component to customize it.
|
||||
|
||||
::component-code
|
||||
---
|
||||
|
||||
@@ -11,13 +11,15 @@ links:
|
||||
|
||||
## Usage
|
||||
|
||||
::tip
|
||||
The Avatar uses the `NuxtImg` component when [`@nuxt/image`](https://github.com/nuxt/image) is installed, falling back to `img` otherwise.
|
||||
The Avatar uses the `<NuxtImg>` component when [`@nuxt/image`](https://github.com/nuxt/image) is installed, falling back to `img` otherwise.
|
||||
|
||||
::note
|
||||
You can pass any property from the HTML `<img>` element such as `alt`, `loading`, etc.
|
||||
::
|
||||
|
||||
### Src
|
||||
|
||||
Use the `src` prop to set the image URL. You can pass any property from HTML `<img>` element such as `alt`, `loading`, etc.
|
||||
Use the `src` prop to set the image URL.
|
||||
|
||||
::component-code
|
||||
---
|
||||
|
||||
@@ -62,7 +62,7 @@ Use the `size` prop to change the size of the Badge.
|
||||
::component-code
|
||||
---
|
||||
props:
|
||||
size: lg
|
||||
size: xl
|
||||
slots:
|
||||
default: Badge
|
||||
---
|
||||
|
||||
@@ -18,7 +18,7 @@ Use the `items` prop as an array of objects with the following properties:
|
||||
- `class?: any`{lang="ts-type"}
|
||||
- [`slot?: string`{lang="ts-type"}](#with-custom-slot)
|
||||
|
||||
You can also pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
You can pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
|
||||
::component-code
|
||||
---
|
||||
|
||||
@@ -4,7 +4,7 @@ description: A calendar component for selecting single dates, multiple dates or
|
||||
links:
|
||||
- label: Calendar
|
||||
icon: i-custom-reka-ui
|
||||
to: https://www.reka-ui.com/components/calendar.html
|
||||
to: https://reka-ui.com/docs/components/calendar
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/Calendar.vue
|
||||
|
||||
@@ -68,9 +68,9 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
### HWB Format
|
||||
### CMYK Format
|
||||
|
||||
Use the `format` prop to set `hwb` value of the ColorPicker.
|
||||
Use the `format` prop to set `cmyk` value of the ColorPicker.
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -80,8 +80,25 @@ ignore:
|
||||
external:
|
||||
- modelValue
|
||||
props:
|
||||
format: hwb
|
||||
modelValue: 'hwb(150, 0%, 24%)'
|
||||
format: cmyk
|
||||
modelValue: 'cmyk(100%, 0%, 45.08%, 24.31%)'
|
||||
---
|
||||
::
|
||||
|
||||
### CIELab Format
|
||||
|
||||
Use the `format` prop to set `lab` value of the ColorPicker.
|
||||
|
||||
::component-code
|
||||
---
|
||||
ignore:
|
||||
- modelValue
|
||||
- format
|
||||
external:
|
||||
- modelValue
|
||||
props:
|
||||
format: lab
|
||||
modelValue: 'lab(68.88% -60.41% 32.55%)'
|
||||
---
|
||||
::
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ title: CommandPalette
|
||||
description: A command palette with full-text search powered by Fuse.js for efficient fuzzy matching.
|
||||
links:
|
||||
- label: Fuse.js
|
||||
icon: i-custom-fuse-js
|
||||
to: https://fusejs.io/
|
||||
target: _blank
|
||||
- label: Combobox
|
||||
@@ -358,7 +359,7 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
You can also pass all the props of the [Button](/components/button) component to customize it.
|
||||
You can pass any property from the [Button](/components/button) component to customize it.
|
||||
|
||||
::component-code
|
||||
---
|
||||
|
||||
@@ -32,7 +32,7 @@ Use the `items` prop as an array of objects with the following properties:
|
||||
- `onSelect?(e: Event): void`{lang="ts-type"}
|
||||
- [`onUpdateChecked?(checked: boolean): void`{lang="ts-type"}](#with-checkbox-items)
|
||||
|
||||
You can also pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
You can pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -104,7 +104,7 @@ slots:
|
||||
::
|
||||
|
||||
::note
|
||||
You can pass an array of arrays to the `items` prop to create separated groups of items.
|
||||
You can also pass an array of arrays to the `items` prop to create separated groups of items.
|
||||
::
|
||||
|
||||
::tip
|
||||
|
||||
@@ -243,6 +243,7 @@ export default defineNuxtConfig({
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
## Examples
|
||||
@@ -266,6 +267,21 @@ In this example, leveraging [`defineShortcuts`](/composables/define-shortcuts),
|
||||
This allows you to move the trigger outside of the Drawer or remove it entirely.
|
||||
::
|
||||
|
||||
### Prevent closing
|
||||
|
||||
Set the `dismissible` prop to `false` to prevent the Drawer from being closed when clicking outside of it or pressing escape.
|
||||
|
||||
::component-example
|
||||
---
|
||||
prettier: true
|
||||
name: 'drawer-dismissible-example'
|
||||
---
|
||||
::
|
||||
|
||||
::note
|
||||
In this example, the `header` slot is used to add a close button which is not done by default.
|
||||
::
|
||||
|
||||
### With footer slot
|
||||
|
||||
Use the `#footer` slot to add content after the Drawer's body.
|
||||
|
||||
@@ -32,7 +32,7 @@ Use the `items` prop as an array of objects with the following properties:
|
||||
- `onSelect?(e: Event): void`{lang="ts-type"}
|
||||
- [`onUpdateChecked?(checked: boolean): void`{lang="ts-type"}](#with-checkbox-items)
|
||||
|
||||
You can also pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
You can pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -103,7 +103,7 @@ slots:
|
||||
::
|
||||
|
||||
::note
|
||||
You can pass an array of arrays to the `items` prop to create separated groups of items.
|
||||
You can also pass an array of arrays to the `items` prop to create separated groups of items.
|
||||
::
|
||||
|
||||
::tip
|
||||
|
||||
@@ -8,21 +8,30 @@ links:
|
||||
|
||||
## Usage
|
||||
|
||||
Use the Form component to validate form data using schema libraries such as [Zod](https://github.com/colinhacks/zod), [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi), [Valibot](https://github.com/fabian-hiller/valibot), [Superstruct](https://github.com/ianstormtaylor/superstruct) or your own validation logic.
|
||||
Use the Form component to validate form data using schema libraries such as [Valibot](https://github.com/fabian-hiller/valibot), [Zod](https://github.com/colinhacks/zod), [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi), [Superstruct](https://github.com/ianstormtaylor/superstruct) or your own validation logic.
|
||||
|
||||
It works with the [FormField](/components/form-field) component to display error messages around form elements automatically.
|
||||
|
||||
### Schema Validation
|
||||
|
||||
It requires two props:
|
||||
|
||||
- `state` - a reactive object holding the form's state.
|
||||
- `schema` - a schema object from a validation library like [Zod](https://github.com/colinhacks/zod), [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi), [Valibot](https://github.com/fabian-hiller/valibot) or [Superstruct](https://github.com/ianstormtaylor/superstruct).
|
||||
- `schema` - a schema object from a validation library like [Valibot](https://github.com/fabian-hiller/valibot), [Zod](https://github.com/colinhacks/zod), [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi) or [Superstruct](https://github.com/ianstormtaylor/superstruct).
|
||||
|
||||
::warning
|
||||
**No validation library is included** by default, ensure you **install the one you need**.
|
||||
::
|
||||
|
||||
::tabs
|
||||
::component-example{label="Valibot"}
|
||||
---
|
||||
name: 'form-example-valibot'
|
||||
props:
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
::component-example{label="Zod"}
|
||||
---
|
||||
name: 'form-example-zod'
|
||||
@@ -47,14 +56,6 @@ It requires two props:
|
||||
---
|
||||
::
|
||||
|
||||
::component-example{label="Valibot"}
|
||||
---
|
||||
name: 'form-example-valibot'
|
||||
props:
|
||||
class: 'w-60'
|
||||
---
|
||||
::
|
||||
|
||||
::component-example{label="Superstruct"}
|
||||
---
|
||||
name: 'form-example-superstruct'
|
||||
@@ -73,6 +74,7 @@ Nested validation rules are handled using dot notation. For example, a rule like
|
||||
Use the `validate` prop to apply your own validation logic.
|
||||
|
||||
The validation function must return a list of errors with the following attributes:
|
||||
|
||||
- `message` - the error message to display.
|
||||
- `name` - the `name` of the `FormField` to send the error to.
|
||||
|
||||
@@ -91,6 +93,7 @@ props:
|
||||
### Input Events
|
||||
|
||||
The Form component automatically triggers validation when an input emits an `input`, `change`, or `blur` event.
|
||||
|
||||
- Validation on `input` occurs **as you type**.
|
||||
- Validation on `change` occurs when you **commit to a value**.
|
||||
- Validation on `blur` happens when an input **loses focus**.
|
||||
@@ -192,7 +195,7 @@ This will give you access to the following:
|
||||
| Name | Type |
|
||||
| ---- | ---- |
|
||||
| `submit()`{lang="ts-type"} | `Promise<void>`{lang="ts-type"} <br> <div class="text-[var(--ui-text-toned)] mt-1"><p>Triggers form submission.</p> |
|
||||
| `validate(path?: string \| string[], opts: { silent?: boolean })`{lang="ts-type"} | `Promise<T>`{lang="ts-type"} <br> <div class="text-[var(--ui-text-toned)] mt-1"><p>Triggers form validation. Will raise any errors unless `opts.silent` is set to true.</p> |
|
||||
| `validate(opts: { name?: string \| string[], silent?: boolean, nested?: boolean, transform?: boolean })`{lang="ts-type"} | `Promise<T>`{lang="ts-type"} <br> <div class="text-[var(--ui-text-toned)] mt-1"><p>Triggers form validation. Will raise any errors unless `opts.silent` is set to true.</p> |
|
||||
| `clear(path?: string)`{lang="ts-type"} | `void` <br> <div class="text-[var(--ui-text-toned)] mt-1"><p>Clears form errors associated with a specific path. If no path is provided, clears all form errors.</p> |
|
||||
| `getErrors(path?: string)`{lang="ts-type"} | `FormError[]`{lang="ts-type"} <br> <div class="text-[var(--ui-text-toned)] mt-1"><p>Retrieves form errors associated with a specific path. If no path is provided, returns all form errors.</p></div> |
|
||||
| `setErrors(errors: FormError[], path?: string)`{lang="ts-type"} | `void` <br> <div class="text-[var(--ui-text-toned)] mt-1"><p>Sets form errors for a given path. If no path is provided, overrides all errors.</p> |
|
||||
|
||||
@@ -8,7 +8,6 @@ links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/InputNumber.vue
|
||||
navigation.badge: New
|
||||
---
|
||||
|
||||
::note
|
||||
|
||||
@@ -13,7 +13,7 @@ The Link component is a wrapper around [`<NuxtLink>`](https://nuxt.com/docs/api/
|
||||
- `inactive-class` prop to set a class when the link is inactive, `active-class` is used when active.
|
||||
- `exact` prop to style with `active-class` when the link is active and the route is exactly the same as the current route.
|
||||
- `exact-query` and `exact-hash` props to style with `active-class` when the link is active and the query or hash is exactly the same as the current query or hash.
|
||||
- use `exact-query="partial"` to style with `active-class` when the link is active and the query partially match the current query.
|
||||
- use `exact-query="partial"` to style with `active-class` when the link is active and the query partially match the current query.
|
||||
|
||||
The incentive behind this is to provide the same API as NuxtLink back in Nuxt 2 / Vue 2. You can read more about it in the Vue Router [migration from Vue 2](https://router.vuejs.org/guide/migration/#removal-of-the-exact-prop-in-router-link) guide.
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ slots:
|
||||
|
||||
Use the `close` prop to customize or hide the close button (with `false` value) displayed in the Modal's header.
|
||||
|
||||
You can pass all the props of the [Button](/components/button) component to customize it.
|
||||
You can pass any property from the [Button](/components/button) component to customize it.
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -253,35 +253,6 @@ slots:
|
||||
:placeholder{class="h-full"}
|
||||
::
|
||||
|
||||
### Prevent close
|
||||
|
||||
Use the `prevent-close` prop to prevent the Modal from being closed when clicking outside of it.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- title
|
||||
- preventClose
|
||||
props:
|
||||
preventClose: true
|
||||
title: 'Modal prevent close'
|
||||
slots:
|
||||
default: |
|
||||
|
||||
<UButton label="Open" color="neutral" variant="subtle" />
|
||||
|
||||
body: |
|
||||
|
||||
<Placeholder class="h-48" />
|
||||
---
|
||||
|
||||
:u-button{label="Open" color="neutral" variant="subtle"}
|
||||
|
||||
#body
|
||||
:placeholder{class="h-48"}
|
||||
::
|
||||
|
||||
## Examples
|
||||
|
||||
### Control open state
|
||||
@@ -302,6 +273,35 @@ In this example, leveraging [`defineShortcuts`](/composables/define-shortcuts),
|
||||
This allows you to move the trigger outside of the Modal or remove it entirely.
|
||||
::
|
||||
|
||||
### Prevent closing
|
||||
|
||||
Set the `dismissible` prop to `false` to prevent the Modal from being closed when clicking outside of it or pressing escape.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- title
|
||||
- dismissible
|
||||
props:
|
||||
dismissible: false
|
||||
title: 'Modal non-dismissible'
|
||||
slots:
|
||||
default: |
|
||||
|
||||
<UButton label="Open" color="neutral" variant="subtle" />
|
||||
|
||||
body: |
|
||||
|
||||
<Placeholder class="h-48" />
|
||||
---
|
||||
|
||||
:u-button{label="Open" color="neutral" variant="subtle"}
|
||||
|
||||
#body
|
||||
:placeholder{class="h-48"}
|
||||
::
|
||||
|
||||
### Programmatic usage
|
||||
|
||||
You can use the [`useModal`](/composables/use-modal) composable to open a Modal programatically.
|
||||
|
||||
@@ -21,13 +21,14 @@ Use the `items` prop as an array of objects with the following properties:
|
||||
- `avatar?: AvatarProps`{lang="ts-type"}
|
||||
- `badge?: string | number | BadgeProps`{lang="ts-type"}
|
||||
- `trailingIcon?: string`{lang="ts-type"}
|
||||
- `type?: 'label' | 'link'`{lang="ts-type"}
|
||||
- `value?: string`{lang="ts-type"}
|
||||
- `disabled?: boolean`{lang="ts-type"}
|
||||
- `class?: any`{lang="ts-type"}
|
||||
- [`slot?: string`{lang="ts-type"}](#with-custom-slot)
|
||||
- `onSelect?(e: Event): void`{lang="ts-type"}
|
||||
|
||||
You can also pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
You can pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -115,12 +116,12 @@ props:
|
||||
- label: Help
|
||||
icon: i-lucide-circle-help
|
||||
disabled: true
|
||||
class: 'justify-center'
|
||||
class: 'w-full justify-center'
|
||||
---
|
||||
::
|
||||
|
||||
::note
|
||||
You can pass an array of arrays to the `items` prop to display groups of items.
|
||||
You can also pass an array of arrays to the `items` prop to display groups of items.
|
||||
::
|
||||
|
||||
::tip
|
||||
@@ -131,13 +132,16 @@ Each item can take a `children` array of objects with the following properties t
|
||||
- `icon?: string`
|
||||
- `class?: any`
|
||||
- `onSelect?(e: Event): void`
|
||||
|
||||
::
|
||||
|
||||
### Orientation
|
||||
|
||||
Use the `orientation` prop to change the orientation of the NavigationMenu.
|
||||
|
||||
::note
|
||||
When orientation is `vertical`, a [Collapsible](/components/collapsible) component is used to display children. You can control the open state of each item using the `open` and `defaultOpen` properties.
|
||||
::
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -150,9 +154,10 @@ external:
|
||||
props:
|
||||
orientation: 'vertical'
|
||||
items:
|
||||
- - label: Guide
|
||||
- - label: Links
|
||||
type: 'label'
|
||||
- label: Guide
|
||||
icon: i-lucide-book-open
|
||||
defaultOpen: true
|
||||
children:
|
||||
- label: Introduction
|
||||
description: Fully styled and customizable components for Nuxt.
|
||||
@@ -190,7 +195,9 @@ props:
|
||||
to: /composables/use-toast
|
||||
- label: Components
|
||||
icon: i-lucide-box
|
||||
to: /components
|
||||
active: true
|
||||
defaultOpen: true
|
||||
children:
|
||||
- label: Link
|
||||
icon: i-lucide-file-text
|
||||
@@ -240,10 +247,10 @@ Use the `highlight-color` prop to change the color of the border. It defaults to
|
||||
|
||||
::component-code
|
||||
---
|
||||
collapse: true
|
||||
prettier: true
|
||||
ignore:
|
||||
- items
|
||||
- highlight
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
@@ -254,25 +261,89 @@ props:
|
||||
items:
|
||||
- - label: Guide
|
||||
icon: i-lucide-book-open
|
||||
to: /getting-started
|
||||
children:
|
||||
- label: Introduction
|
||||
description: Fully styled and customizable components for Nuxt.
|
||||
icon: i-lucide-house
|
||||
- label: Installation
|
||||
description: Learn how to install and configure Nuxt UI in your application.
|
||||
icon: i-lucide-cloud-download
|
||||
- label: 'Icons'
|
||||
icon: 'i-lucide-smile'
|
||||
description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
|
||||
- label: 'Colors'
|
||||
icon: 'i-lucide-swatch-book'
|
||||
description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
|
||||
- label: 'Theme'
|
||||
icon: 'i-lucide-cog'
|
||||
description: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
|
||||
- label: Composables
|
||||
icon: i-lucide-database
|
||||
to: /composables
|
||||
children:
|
||||
- label: defineShortcuts
|
||||
icon: i-lucide-file-text
|
||||
description: Define shortcuts for your application.
|
||||
to: /composables/define-shortcuts
|
||||
- label: useModal
|
||||
icon: i-lucide-file-text
|
||||
description: Display a modal within your application.
|
||||
to: /composables/use-modal
|
||||
- label: useSlideover
|
||||
icon: i-lucide-file-text
|
||||
description: Display a slideover within your application.
|
||||
to: /composables/use-slideover
|
||||
- label: useToast
|
||||
icon: i-lucide-file-text
|
||||
description: Display a toast within your application.
|
||||
to: /composables/use-toast
|
||||
- label: Components
|
||||
icon: i-lucide-box
|
||||
to: /components
|
||||
active: true
|
||||
defaultOpen: true
|
||||
children:
|
||||
- label: Link
|
||||
icon: i-lucide-file-text
|
||||
description: Use NuxtLink with superpowers.
|
||||
to: /components/link
|
||||
- label: Modal
|
||||
icon: i-lucide-file-text
|
||||
description: Display a modal within your application.
|
||||
to: /components/modal
|
||||
- label: NavigationMenu
|
||||
icon: i-lucide-file-text
|
||||
description: Display a list of links.
|
||||
to: /components/navigation-menu
|
||||
- label: Pagination
|
||||
icon: i-lucide-file-text
|
||||
description: Display a list of pages.
|
||||
to: /components/pagination
|
||||
- label: Popover
|
||||
icon: i-lucide-file-text
|
||||
description: Display a non-modal dialog that floats around a trigger element.
|
||||
to: /components/popover
|
||||
- label: Progress
|
||||
icon: i-lucide-file-text
|
||||
description: Show a horizontal bar to indicate task progression.
|
||||
to: /components/progress
|
||||
- - label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
badge: 3.8k
|
||||
to: https://github.com/nuxt/ui
|
||||
target: _blank
|
||||
class: 'data-[orientation=horizontal]:border-b data-[orientation=vertical]:border-l border-[var(--ui-border)]'
|
||||
- label: Help
|
||||
icon: i-lucide-circle-help
|
||||
disabled: true
|
||||
class: 'data-[orientation=horizontal]:border-b border-[var(--ui-border)] data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-48'
|
||||
---
|
||||
::
|
||||
|
||||
::note
|
||||
In this example, the `border-l` and `border-b` classes are applied to display a border, this is not done by default to let you have a clean slate to work with.
|
||||
In this example, the `border-b` class is applied to display a border in `horizontal` orientation, this is not done by default to let you have a clean slate to work with.
|
||||
::
|
||||
|
||||
::caution
|
||||
In `vertical` orientation, the `highlight` prop only highlights the border of active children.
|
||||
::
|
||||
|
||||
### Color
|
||||
@@ -283,6 +354,7 @@ Use the `color` prop to change the color of the NavigationMenu.
|
||||
---
|
||||
ignore:
|
||||
- items
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
@@ -303,6 +375,7 @@ props:
|
||||
badge: 3.8k
|
||||
to: https://github.com/nuxt/ui
|
||||
target: _blank
|
||||
class: 'w-full'
|
||||
---
|
||||
::
|
||||
|
||||
@@ -314,6 +387,7 @@ Use the `variant` prop to change the variant of the NavigationMenu.
|
||||
---
|
||||
ignore:
|
||||
- items
|
||||
- class
|
||||
external:
|
||||
- items
|
||||
props:
|
||||
@@ -336,6 +410,7 @@ props:
|
||||
badge: 3.8k
|
||||
to: https://github.com/nuxt/ui
|
||||
target: _blank
|
||||
class: 'w-full'
|
||||
---
|
||||
::
|
||||
|
||||
@@ -430,7 +505,7 @@ props:
|
||||
icon: i-lucide-file-text
|
||||
description: Show a horizontal bar to indicate task progression.
|
||||
to: /components/progress
|
||||
class: 'justify-center'
|
||||
class: 'w-full justify-center'
|
||||
---
|
||||
::
|
||||
|
||||
@@ -530,7 +605,7 @@ props:
|
||||
icon: i-lucide-file-text
|
||||
description: Show a horizontal bar to indicate task progression.
|
||||
to: /components/progress
|
||||
class: 'justify-center'
|
||||
class: 'w-full justify-center'
|
||||
---
|
||||
::
|
||||
|
||||
@@ -622,7 +697,7 @@ props:
|
||||
icon: i-lucide-file-text
|
||||
description: Show a horizontal bar to indicate task progression.
|
||||
to: /components/progress
|
||||
class: 'justify-center'
|
||||
class: 'w-full justify-center'
|
||||
---
|
||||
::
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/PinInput.vue
|
||||
navigation.badge: New
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -180,6 +180,16 @@ name: 'popover-open-example'
|
||||
In this example, leveraging [`defineShortcuts`](/composables/define-shortcuts), you can toggle the Popover by pressing :kbd{value="O"}.
|
||||
::
|
||||
|
||||
### Prevent closing
|
||||
|
||||
Set the `dismissible` prop to `false` to prevent the Popover from being closed when clicking outside of it or pressing escape.
|
||||
|
||||
::component-example
|
||||
---
|
||||
name: 'popover-dismissible-example'
|
||||
---
|
||||
::
|
||||
|
||||
### With command palette
|
||||
|
||||
You can use a [CommandPalette](/components/command-palette) component inside the Popover's content.
|
||||
|
||||
@@ -202,7 +202,7 @@ props:
|
||||
|
||||
Use the `search-input` prop to customize or hide the search input (with `false` value).
|
||||
|
||||
You can pass all the props of the [Input](/components/input) component to customize it.
|
||||
You can pass any property from the [Input](/components/input) component to customize it.
|
||||
|
||||
::component-code
|
||||
---
|
||||
|
||||
@@ -93,7 +93,7 @@ slots:
|
||||
|
||||
Use the `close` prop to customize or hide the close button (with `false` value) displayed in the Slideover's header.
|
||||
|
||||
You can pass all the props of the [Button](/components/button) component to customize it.
|
||||
You can pass any property from the [Button](/components/button) component to customize it.
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -252,35 +252,6 @@ slots:
|
||||
:placeholder{class="h-full"}
|
||||
::
|
||||
|
||||
### Prevent close
|
||||
|
||||
Use the `prevent-close` prop to prevent the Slideover from being closed when clicking outside of it.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- title
|
||||
- preventClose
|
||||
props:
|
||||
preventClose: true
|
||||
title: 'Slideover prevent close'
|
||||
slots:
|
||||
default: |
|
||||
|
||||
<UButton label="Open" color="neutral" variant="subtle" />
|
||||
|
||||
body: |
|
||||
|
||||
<Placeholder class="h-full" />
|
||||
---
|
||||
|
||||
:u-button{label="Open" color="neutral" variant="subtle"}
|
||||
|
||||
#body
|
||||
:placeholder{class="h-full"}
|
||||
::
|
||||
|
||||
## Examples
|
||||
|
||||
### Control open state
|
||||
@@ -301,6 +272,35 @@ In this example, leveraging [`defineShortcuts`](/composables/define-shortcuts),
|
||||
This allows you to move the trigger outside of the Slideover or remove it entirely.
|
||||
::
|
||||
|
||||
### Prevent closing
|
||||
|
||||
Set the `dismissible` prop to `false` to prevent the Slideover from being closed when clicking outside of it or pressing escape.
|
||||
|
||||
::component-code
|
||||
---
|
||||
prettier: true
|
||||
ignore:
|
||||
- title
|
||||
- dismissible
|
||||
props:
|
||||
dismissible: false
|
||||
title: 'Slideover non-dismissible'
|
||||
slots:
|
||||
default: |
|
||||
|
||||
<UButton label="Open" color="neutral" variant="subtle" />
|
||||
|
||||
body: |
|
||||
|
||||
<Placeholder class="h-full" />
|
||||
---
|
||||
|
||||
:u-button{label="Open" color="neutral" variant="subtle"}
|
||||
|
||||
#body
|
||||
:placeholder{class="h-full"}
|
||||
::
|
||||
|
||||
### Programmatic usage
|
||||
|
||||
You can use the [`useSlideover`](/composables/use-slideover) composable to open a Slideover programatically.
|
||||
|
||||
@@ -110,10 +110,6 @@ export default defineNuxtConfig({
|
||||
}
|
||||
},
|
||||
|
||||
hub: {
|
||||
cache: true
|
||||
},
|
||||
|
||||
componentMeta: {
|
||||
exclude: [
|
||||
'@nuxt/content',
|
||||
@@ -125,7 +121,7 @@ export default defineNuxtConfig({
|
||||
'nuxt/dist',
|
||||
'nuxt-og-image',
|
||||
resolve('./app/components'),
|
||||
process.env.NUXT_UI_PRO_PATH ? resolve(process.env.NUXT_UI_PRO_PATH, 'docs', 'components') : '.c12'
|
||||
process.env.NUXT_UI_PRO_PATH ? resolve(process.env.NUXT_UI_PRO_PATH, 'docs', 'app', 'components') : '.c12'
|
||||
],
|
||||
metaFields: {
|
||||
type: false,
|
||||
@@ -150,5 +146,9 @@ export default defineNuxtConfig({
|
||||
|
||||
image: {
|
||||
provider: 'ipx'
|
||||
},
|
||||
|
||||
uiPro: {
|
||||
license: 'oss'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -3,31 +3,31 @@
|
||||
"name": "@nuxt/ui-docs",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@iconify-json/logos": "^1.2.3",
|
||||
"@iconify-json/lucide": "^1.2.18",
|
||||
"@iconify-json/simple-icons": "^1.2.14",
|
||||
"@iconify-json/vscode-icons": "^1.2.3",
|
||||
"@nuxt/content": "https://pkg.pr.new/@nuxt/content@c5b1a4f",
|
||||
"@nuxt/image": "^1.8.1",
|
||||
"@iconify-json/logos": "^1.2.4",
|
||||
"@iconify-json/lucide": "^1.2.22",
|
||||
"@iconify-json/simple-icons": "^1.2.19",
|
||||
"@iconify-json/vscode-icons": "^1.2.10",
|
||||
"@nuxt/content": "^3.0.0",
|
||||
"@nuxt/image": "^1.9.0",
|
||||
"@nuxt/ui": "latest",
|
||||
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@3fcaf55",
|
||||
"@nuxthub/core": "^0.8.7",
|
||||
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@2dbbff0",
|
||||
"@nuxthub/core": "^0.8.11",
|
||||
"@nuxtjs/plausible": "^1.2.0",
|
||||
"@octokit/rest": "^21.0.2",
|
||||
"@vueuse/nuxt": "^12.0.0",
|
||||
"@octokit/rest": "^21.1.0",
|
||||
"@vueuse/nuxt": "^12.4.0",
|
||||
"joi": "^17.13.3",
|
||||
"nuxt": "^3.14.1592",
|
||||
"nuxt": "^3.15.1",
|
||||
"nuxt-component-meta": "^0.9.0",
|
||||
"nuxt-og-image": "^3.1.1",
|
||||
"nuxt-og-image": "^4.0.2",
|
||||
"prettier": "^3.4.2",
|
||||
"shiki-transformer-color-highlight": "^0.2.0",
|
||||
"superstruct": "^2.0.2",
|
||||
"ufo": "^1.5.4",
|
||||
"valibot": "^0.42.1",
|
||||
"yup": "^1.5.0",
|
||||
"zod": "^3.23.8"
|
||||
"yup": "^1.6.1",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"wrangler": "^3.93.0"
|
||||
"wrangler": "^3.101.0"
|
||||
}
|
||||
}
|
||||
|
||||
96
package.json
96
package.json
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"name": "@nuxt/ui",
|
||||
"description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.",
|
||||
"version": "3.0.0-alpha.10",
|
||||
"packageManager": "pnpm@9.15.0",
|
||||
"version": "3.0.0-alpha.11",
|
||||
"packageManager": "pnpm@9.15.3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nuxt/ui.git"
|
||||
},
|
||||
"homepage": "https://ui.nuxt.com",
|
||||
"homepage": "https://ui3.nuxt.dev",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/module.d.ts",
|
||||
"style": "./dist/runtime/index.css",
|
||||
"import": "./dist/module.mjs",
|
||||
"require": "./dist/module.cjs",
|
||||
"style": "./dist/runtime/index.css"
|
||||
"require": "./dist/module.cjs"
|
||||
},
|
||||
"./unplugin": {
|
||||
"types": "./dist/unplugin.d.ts",
|
||||
@@ -73,81 +73,85 @@
|
||||
"release": "release-it --preRelease=alpha --npm.tag=next"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify/vue": "^4.2.0",
|
||||
"@iconify/vue": "^4.3.0",
|
||||
"@internationalized/date": "^3.6.0",
|
||||
"@internationalized/number": "^3.6.0",
|
||||
"@nuxt/devtools-kit": "^1.6.3",
|
||||
"@nuxt/devtools-kit": "^1.7.0",
|
||||
"@nuxt/fonts": "^0.10.3",
|
||||
"@nuxt/icon": "^1.9.1",
|
||||
"@nuxt/kit": "^3.14.1592",
|
||||
"@nuxt/schema": "^3.14.1592",
|
||||
"@nuxt/icon": "^1.10.3",
|
||||
"@nuxt/kit": "^3.15.1",
|
||||
"@nuxt/schema": "^3.15.1",
|
||||
"@nuxtjs/color-mode": "^3.5.2",
|
||||
"@tailwindcss/postcss": "4.0.0-beta.6",
|
||||
"@tailwindcss/vite": "4.0.0-beta.6",
|
||||
"@tailwindcss/postcss": "4.0.0-beta.9",
|
||||
"@tailwindcss/vite": "4.0.0-beta.9",
|
||||
"@tanstack/vue-table": "^8.20.5",
|
||||
"@types/color": "^4.2.0",
|
||||
"@unhead/vue": "^1.11.13",
|
||||
"@vueuse/core": "^12.0.0",
|
||||
"@vueuse/integrations": "^12.0.0",
|
||||
"color": "^4.2.3",
|
||||
"consola": "^3.2.3",
|
||||
"@unhead/vue": "^1.11.16",
|
||||
"@vueuse/core": "^12.4.0",
|
||||
"@vueuse/integrations": "^12.4.0",
|
||||
"colortranslator": "^4.1.0",
|
||||
"consola": "^3.3.3",
|
||||
"defu": "^6.1.4",
|
||||
"embla-carousel-auto-height": "^8.5.1",
|
||||
"embla-carousel-auto-scroll": "^8.5.1",
|
||||
"embla-carousel-autoplay": "^8.5.1",
|
||||
"embla-carousel-class-names": "^8.5.1",
|
||||
"embla-carousel-fade": "^8.5.1",
|
||||
"embla-carousel-vue": "^8.5.1",
|
||||
"embla-carousel-auto-height": "^8.5.2",
|
||||
"embla-carousel-auto-scroll": "^8.5.2",
|
||||
"embla-carousel-autoplay": "^8.5.2",
|
||||
"embla-carousel-class-names": "^8.5.2",
|
||||
"embla-carousel-fade": "^8.5.2",
|
||||
"embla-carousel-vue": "^8.5.2",
|
||||
"embla-carousel-wheel-gestures": "^8.0.1",
|
||||
"fuse.js": "^7.0.0",
|
||||
"get-port-please": "^3.1.2",
|
||||
"knitwork": "^1.1.0",
|
||||
"magic-string": "^0.30.14",
|
||||
"mlly": "^1.7.3",
|
||||
"knitwork": "^1.2.0",
|
||||
"magic-string": "^0.30.17",
|
||||
"mlly": "^1.7.4",
|
||||
"ohash": "^1.1.4",
|
||||
"reka-ui": "1.0.0-alpha.6",
|
||||
"pathe": "^1.1.2",
|
||||
"pathe": "^2.0.1",
|
||||
"reka-ui": "1.0.0-alpha.8",
|
||||
"scule": "^1.3.0",
|
||||
"sirv": "^3.0.0",
|
||||
"tailwind-variants": "^0.3.0",
|
||||
"tailwindcss": "4.0.0-beta.6",
|
||||
"tailwindcss": "4.0.0-beta.9",
|
||||
"tinyglobby": "^0.2.10",
|
||||
"unplugin": "^1.16.0",
|
||||
"unplugin-auto-import": "^0.18.6",
|
||||
"unplugin-vue-components": "^0.27.5",
|
||||
"unplugin": "^2.1.2",
|
||||
"unplugin-auto-import": "^19.0.0",
|
||||
"unplugin-vue-components": "^28.0.0",
|
||||
"vaul-vue": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint-config": "^0.7.2",
|
||||
"@nuxt/eslint-config": "^0.7.5",
|
||||
"@nuxt/module-builder": "^0.8.4",
|
||||
"@nuxt/test-utils": "^3.15.1",
|
||||
"@release-it/conventional-changelog": "^9.0.3",
|
||||
"@standard-schema/spec": "1.0.0-beta.4",
|
||||
"@nuxt/test-utils": "^3.15.4",
|
||||
"@release-it/conventional-changelog": "^10.0.0",
|
||||
"@standard-schema/spec": "1.0.0-rc.0",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"embla-carousel": "^8.5.1",
|
||||
"eslint": "^9.16.0",
|
||||
"embla-carousel": "^8.5.2",
|
||||
"eslint": "^9.18.0",
|
||||
"happy-dom": "^15.7.4",
|
||||
"joi": "^17.13.3",
|
||||
"knitwork": "^1.1.0",
|
||||
"nuxt": "^3.14.1592",
|
||||
"knitwork": "^1.2.0",
|
||||
"nuxt": "^3.15.1",
|
||||
"nuxt-component-meta": "^0.9.0",
|
||||
"release-it": "^17.10.0",
|
||||
"release-it": "^18.1.1",
|
||||
"superstruct": "^2.0.2",
|
||||
"valibot": "^0.42.1",
|
||||
"vitest": "^2.1.8",
|
||||
"vitest-environment-nuxt": "^1.0.1",
|
||||
"vue-tsc": "^2.1.10",
|
||||
"yup": "^1.5.0",
|
||||
"zod": "^3.23.8"
|
||||
"vue-tsc": "^2.2.0",
|
||||
"yup": "^1.6.1",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"@nuxt/ui": "workspace:*",
|
||||
"chokidar": "3.6.0",
|
||||
"debug": "4.3.7",
|
||||
"happy-dom": "14.12.3",
|
||||
"rollup": "^4.24.0",
|
||||
"typescript": "5.6.3",
|
||||
"chokidar": "3.6.0"
|
||||
"unimport": "3.14.5",
|
||||
"unplugin": "^2.1.2",
|
||||
"vite": "^6.0.7",
|
||||
"vue-tsc": "^2.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"typescript": "^5.7.2",
|
||||
"unplugin-auto-import": "^0.18.6",
|
||||
"unplugin-vue-components": "^0.27.5",
|
||||
"vite": "^5.4.11",
|
||||
"vue-tsc": "^2.1.10"
|
||||
"unplugin-auto-import": "^19.0.0",
|
||||
"unplugin-vue-components": "^28.0.0",
|
||||
"vite": "^6.0.7",
|
||||
"vue-tsc": "^2.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,46 @@ const actions = (color: string) => [{
|
||||
}
|
||||
}]
|
||||
|
||||
const multipleActions = (color: string) => [
|
||||
{
|
||||
label: 'Action',
|
||||
color: color as any,
|
||||
click() {
|
||||
console.log('Action clicked')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Another action',
|
||||
color: color as any,
|
||||
click() {
|
||||
console.log('Another action clicked')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'One more action',
|
||||
color: color as any,
|
||||
click() {
|
||||
console.log('One more action clicked')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'And one more',
|
||||
color: color as any,
|
||||
icon: 'i-lucide-info',
|
||||
click() {
|
||||
console.log('And one more clicked')
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Last one',
|
||||
color: color as any,
|
||||
icon: 'i-lucide-info',
|
||||
click() {
|
||||
console.log('Last one clicked')
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const data = {
|
||||
title: 'Heads up!',
|
||||
description: 'You can change the primary color in your app config.',
|
||||
@@ -28,6 +68,7 @@ const data = {
|
||||
<UAlert :title="data.title" :icon="data.icon" :close="data.close" :actions="actions('neutral')" />
|
||||
<UAlert :title="data.title" :icon="data.icon" :close="data.close" :description="data.description" />
|
||||
<UAlert :title="data.title" :avatar="{ src: 'https://github.com/benjamincanac.png' }" :close="data.close" :description="data.description" />
|
||||
<UAlert :title="data.title" :icon="data.icon" description="example with multiple actions." :actions="multipleActions('neutral')" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { z } from 'zod'
|
||||
import * as z from 'zod'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui'
|
||||
import FormExampleElements from '../../../../docs/app/components/content/examples/form/FormExampleElements.vue'
|
||||
import FormExampleNestedList from '../../../../docs/app/components/content/examples/form/FormExampleNestedList.vue'
|
||||
|
||||
@@ -10,13 +10,16 @@ const highlightColor = ref()
|
||||
const variant = ref(theme.defaultVariants.variant)
|
||||
const orientation = ref('vertical' as const)
|
||||
const highlight = ref(true)
|
||||
const collapsed = ref(false)
|
||||
|
||||
const items = [
|
||||
[{
|
||||
label: 'Link',
|
||||
type: 'label' as const
|
||||
}, {
|
||||
label: 'Documentation',
|
||||
icon: 'i-lucide-book-open',
|
||||
badge: 10,
|
||||
defaultOpen: true,
|
||||
children: [{
|
||||
label: 'Introduction',
|
||||
description: 'Fully styled and customizable components for Nuxt.',
|
||||
@@ -38,35 +41,36 @@ const items = [
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-box',
|
||||
active: true,
|
||||
defaultOpen: true,
|
||||
children: [{
|
||||
label: 'Link',
|
||||
icon: 'i-lucide-file',
|
||||
icon: 'i-lucide-link',
|
||||
description: 'Use NuxtLink with superpowers.',
|
||||
to: '/components/link'
|
||||
}, {
|
||||
label: 'Modal',
|
||||
icon: 'i-lucide-file',
|
||||
description: 'Display a modal within your application.',
|
||||
icon: 'i-lucide-square',
|
||||
description: 'Display a modal dialog overlay for important content.',
|
||||
to: '/components/modal'
|
||||
}, {
|
||||
label: 'NavigationMenu',
|
||||
icon: 'i-lucide-file',
|
||||
icon: 'i-lucide-list',
|
||||
description: 'Display a list of links.',
|
||||
to: '/components/navigation-menu',
|
||||
trailingIcon: 'i-lucide-check'
|
||||
}, {
|
||||
label: 'Pagination',
|
||||
icon: 'i-lucide-file',
|
||||
icon: 'i-lucide-parking-meter',
|
||||
description: 'Display a list of pages.',
|
||||
to: '/components/pagination'
|
||||
}, {
|
||||
label: 'Popover',
|
||||
icon: 'i-lucide-file',
|
||||
icon: 'i-lucide-message-circle',
|
||||
description: 'Display a non-modal dialog that floats around a trigger element.',
|
||||
to: '/components/popover'
|
||||
}, {
|
||||
label: 'Progress',
|
||||
icon: 'i-lucide-file',
|
||||
icon: 'i-lucide-loader',
|
||||
description: 'Show a horizontal bar to indicate task progression.',
|
||||
to: '/components/progress'
|
||||
}]
|
||||
@@ -89,19 +93,22 @@ const items = [
|
||||
<USelect v-model="color" :items="colors" placeholder="Color" />
|
||||
<USelect v-model="variant" :items="variants" placeholder="Variant" />
|
||||
<USelect v-model="orientation" :items="orientations" placeholder="Orientation" />
|
||||
<USwitch v-model="collapsed" label="Collapsed" />
|
||||
<USwitch v-model="highlight" label="Highlight" />
|
||||
<USelect v-model="highlightColor" :items="colors" placeholder="Highlight color" />
|
||||
</div>
|
||||
|
||||
<UNavigationMenu
|
||||
arrow
|
||||
:collapsed="collapsed"
|
||||
:items="items"
|
||||
:color="color"
|
||||
:variant="variant"
|
||||
:orientation="orientation"
|
||||
:highlight="highlight"
|
||||
:highlight-color="highlightColor"
|
||||
:class="highlight && 'data-[orientation=horizontal]:border-b data-[orientation=vertical]:border-s border-[var(--ui-border)]'"
|
||||
:class="highlight && 'data-[orientation=horizontal]:border-b border-[var(--ui-border)]'"
|
||||
class="data-[orientation=vertical]:data-[collapsed=false]:w-48"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,9 +3,14 @@ import { createResolver } from '@nuxt/kit'
|
||||
const { resolve } = createResolver(import.meta.url)
|
||||
|
||||
export default defineNuxtConfig({
|
||||
modules: ['../src/module'],
|
||||
modules: [
|
||||
'../src/module',
|
||||
'@nuxthub/core'
|
||||
],
|
||||
|
||||
devtools: { enabled: true },
|
||||
devtools: {
|
||||
enabled: true
|
||||
},
|
||||
|
||||
ui: {
|
||||
fonts: false
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
"generate": "nuxi generate"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iconify-json/lucide": "^1.2.18",
|
||||
"@iconify-json/simple-icons": "^1.2.14",
|
||||
"@iconify-json/lucide": "^1.2.22",
|
||||
"@iconify-json/simple-icons": "^1.2.19",
|
||||
"@nuxt/ui": "latest",
|
||||
"nuxt": "^3.14.1592"
|
||||
"@nuxthub/core": "^0.8.11",
|
||||
"nuxt": "^3.15.1"
|
||||
}
|
||||
}
|
||||
|
||||
7494
pnpm-lock.yaml
generated
7494
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,8 @@
|
||||
"happy-dom",
|
||||
"valibot30",
|
||||
"valibot31",
|
||||
"typescript"
|
||||
"typescript",
|
||||
"vue-tsc"
|
||||
],
|
||||
"baseBranches": ["dev", "v3"],
|
||||
"packageRules": [{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { UnpluginOptions } from 'unplugin'
|
||||
import { join, normalize } from 'pathe'
|
||||
import { normalize } from 'pathe'
|
||||
import { resolvePathSync } from 'mlly'
|
||||
import MagicString from 'magic-string'
|
||||
|
||||
@@ -9,7 +9,7 @@ import { runtimeDir } from '../unplugin'
|
||||
* This plugin normalises Nuxt environment (#imports) and `import.meta.client` within the Nuxt UI components.
|
||||
*/
|
||||
export default function NuxtEnvironmentPlugin() {
|
||||
const stubPath = resolvePathSync(join(runtimeDir, 'vue/stubs'), { extensions: ['.ts', '.mjs', '.js'] })
|
||||
const stubPath = resolvePathSync('../runtime/vue/stubs', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url })
|
||||
|
||||
return {
|
||||
name: 'nuxt:ui',
|
||||
|
||||
@@ -15,9 +15,9 @@ import type { UnpluginOptions } from 'unplugin'
|
||||
export default function PluginsPlugin(options: NuxtUIOptions) {
|
||||
const plugins = globSync(['**/*', '!*.d.ts'], { cwd: join(runtimeDir, 'plugins'), absolute: true })
|
||||
|
||||
plugins.unshift(resolvePathSync(join(runtimeDir, 'vue/plugins/head'), { extensions: ['.ts', '.mjs', '.js'] }))
|
||||
plugins.unshift(resolvePathSync('../runtime/vue/plugins/head', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url }))
|
||||
if (options.colorMode) {
|
||||
plugins.push(resolvePathSync(join(runtimeDir, 'vue/plugins/color-mode'), { extensions: ['.ts', '.mjs', '.js'] }))
|
||||
plugins.push(resolvePathSync('../runtime/vue/plugins/color-mode', { extensions: ['.ts', '.mjs', '.js'], url: import.meta.url }))
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { tv } from 'tailwind-variants'
|
||||
import type { AccordionRootProps, AccordionRootEmits } from 'reka-ui'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/accordion'
|
||||
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
||||
import { tv } from '../utils/tv'
|
||||
import type { DynamicSlots } from '../types/utils'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { accordion: Partial<typeof theme> } }
|
||||
@@ -98,6 +98,7 @@ import UIcon from './Icon.vue'
|
||||
const props = withDefaults(defineProps<AccordionProps<T>>(), {
|
||||
type: 'single',
|
||||
collapsible: true,
|
||||
unmountOnHide: true,
|
||||
labelKey: 'label'
|
||||
})
|
||||
const emits = defineEmits<AccordionEmits>()
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { tv, type VariantProps } from 'tailwind-variants'
|
||||
import type { VariantProps } from 'tailwind-variants'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/alert'
|
||||
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
||||
import { tv } from '../utils/tv'
|
||||
import type { AvatarProps, ButtonProps } from '../types'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { alert: Partial<typeof theme> } }
|
||||
@@ -34,7 +35,7 @@ export interface AlertProps {
|
||||
/**
|
||||
* Display a close button to dismiss the alert.
|
||||
* `{ size: 'md', color: 'neutral', variant: 'link' }`{lang="ts-type"}
|
||||
* @emits `close`
|
||||
* @emits 'update:open'
|
||||
* @defaultValue false
|
||||
*/
|
||||
close?: ButtonProps | boolean
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { tv, type VariantProps } from 'tailwind-variants'
|
||||
import type { VariantProps } from 'tailwind-variants'
|
||||
import type { AvatarFallbackProps } from 'reka-ui'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/avatar'
|
||||
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
||||
import { tv } from '../utils/tv'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { avatar: Partial<typeof theme> } }
|
||||
|
||||
@@ -83,10 +84,10 @@ const sizePx = computed(() => ({
|
||||
:class="ui.image({ class: props.ui?.image })"
|
||||
/>
|
||||
|
||||
<AvatarFallback as-child v-bind="fallbackProps">
|
||||
<AvatarFallback as-child v-bind="{ ...fallbackProps, ...$attrs }">
|
||||
<slot>
|
||||
<UIcon v-if="icon" :name="icon" :class="ui.icon({ class: props.ui?.icon })" />
|
||||
<span v-else :class="ui.fallback({ class: props.ui?.fallback })">{{ fallback }}</span>
|
||||
<span v-else :class="ui.fallback({ class: props.ui?.fallback })">{{ fallback || ' ' }}</span>
|
||||
</slot>
|
||||
</AvatarFallback>
|
||||
</AvatarRoot>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { tv, type VariantProps } from 'tailwind-variants'
|
||||
import type { VariantProps } from 'tailwind-variants'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/avatar-group'
|
||||
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
||||
import { tv } from '../utils/tv'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { avatarGroup: Partial<typeof theme> } }
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { tv, type VariantProps } from 'tailwind-variants'
|
||||
import type { VariantProps } from 'tailwind-variants'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/badge'
|
||||
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
||||
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
|
||||
import { tv } from '../utils/tv'
|
||||
import type { AvatarProps } from '../types'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { badge: Partial<typeof theme> } }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { tv } from 'tailwind-variants'
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/breadcrumb'
|
||||
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
||||
import { tv } from '../utils/tv'
|
||||
import type { AvatarProps, LinkProps } from '../types'
|
||||
import type { DynamicSlots, PartialString } from '../types/utils'
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user