Compare commits

..

100 Commits

Author SHA1 Message Date
Benjamin Canac
6f6fa6ae4a chore(release): v3.1.1 2025-05-02 18:28:20 +02:00
Jez McKean
c7bb6d4c4b docs(toast): fix toaster example links (#4044) 2025-05-02 18:20:10 +02:00
Daniel Jimenez Gutierrez
c23f85fe33 docs(use-overlay): typo on unMount method (#4047) 2025-05-02 18:18:47 +02:00
Benjamin Canac
591d59fe89 fix(theme): improve app config types for ui object
Resolves #3579
2025-05-02 17:06:20 +02:00
Benjamin Canac
caa3bf9c7e docs(carousel): improve thumbnails example
Resolves #4032
2025-05-02 11:58:55 +02:00
Benjamin Canac
2731011bb7 docs(nuxt.config): put back local module import 2025-05-02 11:52:43 +02:00
Benjamin Canac
aebf0b3dca fix(NavigationMenu): remove sm:w-auto from content slot
Resolves #3987

Reverts abe0859691
2025-05-02 11:48:34 +02:00
renovate[bot]
6651987dc6 chore(deps): update nuxt framework to ^3.17.1 (v3) (#4003)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-02 10:21:32 +02:00
Eugen Istoc
61aabd72e4 chore(deps): add missing vue-component-type-helpers dependency (#4043) 2025-05-01 22:57:50 +02:00
Vitor Camarotto
8dfdd63ce3 fix(Calendar): add place-items-center to grid row (#4034) 2025-05-01 19:02:06 +02:00
renovate[bot]
e6369a6746 chore(deps): update devdependency vite to v6.3.4 [security] (v3) (#4037)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-01 18:49:10 +02:00
Eugen Istoc
a4f3f6d531 feat(useOverlay): add isOpen method to check overlay state (#4041) 2025-05-01 18:48:41 +02:00
Sandro Circi
c5bdec0f64 fix(templates): put back args to watch in dev (#4033) 2025-05-01 18:47:03 +02:00
renovate[bot]
87a7828931 chore(deps): update dependency motion-v to v1 (v3) (#4004)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-30 15:48:32 +02:00
Hugo Richard
501468960b docs(templates): add portfolio template (#4031) 2025-04-30 15:33:06 +02:00
Benjamin Canac
13cd6be679 docs(command-palette): wrong reka-ui link 2025-04-29 22:46:59 +02:00
Benjamin Canac
e421ea57ec docs(pin-input): missing reka-ui link 2025-04-29 22:46:59 +02:00
Malik
799d7ae422 docs(input-number): broken reka-ui link (#4028)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-29 22:44:53 +02:00
Benjamin Canac
be9b1f659a docs(team): update grid 2025-04-29 18:16:59 +02:00
Eugen Istoc
39e29fccf1 fix(useOverlay): improve types and docs (#4012)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-29 18:09:39 +02:00
reslear
195773ec7d fix(RadioGroup): improve items value field type (#3995) 2025-04-29 18:02:38 +02:00
Benjamin Canac
d7710795df chore(github): add playground job in module workflow (#4021) 2025-04-29 17:48:09 +02:00
Benjamin Canac
53f8b34bef chore: use module workspace 2025-04-29 17:21:43 +02:00
Benjamin Canac
df83ab355e chore(deps): update vue-tsc (#4023) 2025-04-29 17:07:24 +02:00
Hugo Richard
e5df026993 fix(theme): add missing ring-offset-* utilities (#3992)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-29 16:10:53 +02:00
Benjamin Canac
6131871a0d fix(theme): use @theme inline to properly reference css variables
Resolves #4018

https://tailwindcss.com/docs/theme#referencing-other-variables
2025-04-29 14:39:08 +02:00
Alain Limoges
9543bce787 docs(form-field/switch): fix typo (#4015) 2025-04-29 14:36:40 +02:00
renovate[bot]
5e345a8a73 chore(deps): update all non-major dependencies (v3) (#4002)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 14:36:40 +02:00
Benjamin Canac
8acf3c51db fix(theme): define default shades for named tailwindcss colors
Resolves #3977
2025-04-29 14:36:31 +02:00
Benjamin Canac
f3b8b17dc5 fix(defineShortcuts): bring back meta to ctrl convert on non macos platforms
Resolves #3869, resolves #3318

Co-Authored-By: Sylvain Marroufin <marroufin.sylvain@gmail.com>
2025-04-29 14:36:31 +02:00
Daniel Roe
bc0a296f9d fix(module): support nuxt-nightly (#3996) 2025-04-29 14:36:31 +02:00
Eugen Istoc
ac4c1946ec feat(useOverlay): add closeAll method (#3984) 2025-04-29 14:36:31 +02:00
Benjamin Canac
82b5f322eb fix(theme): add missing border-bg / divide-bg utilities 2025-04-29 14:36:19 +02:00
Benjamin Canac
fb6cf708a6 chore(deps): update @nuxt/content 2025-04-24 21:35:59 +02:00
Benjamin Canac
8ab1f75e47 chore(github): revert docs trigger 2025-04-24 17:44:30 +02:00
Benjamin Canac
e9b19349ba chore(deps): update @nuxt/ui-pro 2025-04-24 16:16:57 +02:00
Benjamin Canac
b2b206e3f4 docs: update badges 2025-04-24 16:16:29 +02:00
Benjamin Canac
b779064129 docs(radio-group): add missing types on variant 2025-04-24 16:16:29 +02:00
Benjamin Canac
94155258e2 chore(github): prevent docs workflow to run on tags 2025-04-24 16:16:29 +02:00
Maxime Pauvert
c63a6dd133 chore(readme): add pro link (#3970) 2025-04-24 15:43:12 +02:00
Benjamin Canac
79833035de chore(release): v3.1.0 2025-04-24 14:29:07 +02:00
Benjamin Canac
79e7c7b729 chore(deps): update @nuxt/ui-pro 2025-04-24 13:00:11 +02:00
Benjamin Canac
bc06185282 fix(CheckboxGroup): proxy slots & ui prop 2025-04-24 12:38:44 +02:00
Guillaume REMBERT
6e27304d8c fix(Table): improve data reactivity (#3967)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-24 12:10:37 +02:00
Benjamin Canac
b4f8ac7ff7 chore(deps): update nuxt-component-meta 2025-04-24 12:10:29 +02:00
renovate[bot]
a2fa1accaa chore(deps): update all non-major dependencies (v3) (#3946)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 12:03:00 +02:00
kyyy
f486423381 feat(Modal/Popover/Slideover): add close:prevent event (#3958)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-23 17:38:44 +02:00
Romain Hamel
975331a7b1 docs(installation): update instructions for inertia (#3964)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-23 17:36:06 +02:00
Benjamin Canac
75e4792f7f fix(Accordion): use div instead of h3 for header tag
Resolves #3963
2025-04-23 16:12:13 +02:00
Benjamin Canac
4a969a8b9e chore(github): add release workflow on v3* tags 2025-04-23 15:31:30 +02:00
Benjamin Canac
664a8c7524 chore(deps): missing caret on motion-v 2025-04-23 13:08:23 +02:00
Benjamin Canac
fbcc3139a3 chore(Skeleton): remove aria-busy:cursor-progress class 2025-04-23 11:25:43 +02:00
Guillaume Chau
1a46394668 feat(components): add new content-top and content-bottom slots (#3886)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-23 11:02:50 +02:00
Benjamin Canac
9ca213bd33 fix(InputMenu/SelectMenu): remove valueKey string case
Resolves #3949

Regression of #3331
2025-04-23 10:22:28 +02:00
kyyy
3484832822 fix(Skeleton): improve accessibility (#3613)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-22 22:06:05 +02:00
andr35
80dfa88ea4 feat(Table): conditionally apply classes to tr and td (#3866)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-22 21:14:57 +02:00
Benjamin Canac
d710141a1b chore(deps): update nuxt-component-meta 2025-04-22 18:50:45 +02:00
Hugo Richard
d3e2a3f33a docs(checkbox-group): add og images (#3957) 2025-04-22 18:47:55 +02:00
TribeWeb
9c3d53a02d feat(CheckboxGroup): new component (#3862)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
Co-authored-by: Romain Hamel <rom.hml@gmail.com>
2025-04-22 18:03:27 +02:00
Polly
22edfd708a feat(Carousel): add select event (#3678)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-22 16:44:47 +02:00
Kheuval
e25aa78050 docs(table): add infinite scroll example (#3656)
Co-authored-by: Hadrien Hartstein <hadrien@emagma.fr>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-22 16:14:59 +02:00
Igor G
122e8ac8f4 fix(Table): pass header colspan to th (#3926) 2025-04-22 16:07:23 +02:00
Hung Chang
5fc6312ab1 docs(carousel): add thumbnails example (#3740)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-22 15:44:40 +02:00
Stijn Slats
83f0a24704 docs(table): add drag and drop example (#3700)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-22 15:31:57 +02:00
Evan Schleret
13c299533f docs(calendar): add external controls example (#3793)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-22 15:17:17 +02:00
Nathanaël Louison
db11db6ff1 fix(usePortal): adjust portal target resolution logic (#3954) 2025-04-22 12:05:14 +02:00
Benjamin Canac
50863635d6 fix(Alert/Toast): display actions when using slots
Fixes #3950
2025-04-21 18:25:52 +02:00
Nathanaël Louison
29fa46276d feat(App): add global portal prop (#3688)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-21 17:42:55 +02:00
Benjamin Canac
7a35baebc7 chore(templates): wrong theme keys for fill and stroke 2025-04-21 16:52:57 +02:00
Benjamin Canac
b6f6cee1a9 chore(deps): update @nuxt/ui-pro 2025-04-21 16:27:51 +02:00
Benjamin Canac
d49e0dadee feat(module): define neutral utilities (#3629)
Co-authored-by: Sébastien Chopin <atinux@gmail.com>
2025-04-21 15:20:53 +02:00
renovate[bot]
2b315fd855 chore(deps): lock file maintenance (v3) (#3941)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-21 11:48:01 +02:00
Romain Hamel
f42949820b fix(Form): input and output type inference (#3938)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-21 11:04:23 +02:00
renovate[bot]
d2ba99797c chore(deps): update pnpm to v10.9.0 (v3) (#3944)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-21 11:02:27 +02:00
renovate[bot]
fd23038b1a chore(deps): update devdependency release-it to v19 (v3) (#3931)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-21 11:01:51 +02:00
renovate[bot]
fe3ec0c183 chore(deps): update all non-major dependencies (v3) (#3888)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-21 10:42:50 +02:00
Romain Hamel
1a0d7a3103 feat(Form): add attach prop to opt-out of nested form attachement (#3939) 2025-04-20 17:29:36 +02:00
Federico Mameli
c31bffad1b fix(vite): vitest skipping nuxt imports transformations (#3925) 2025-04-18 10:34:21 +02:00
Sébastien Chopin
dd8f7a77a5 docs: don't import color mode from vueuse (#3929) 2025-04-18 09:04:26 +02:00
ExXTreMe315
eb46e31ffb docs(modal): typo in programmatic emit (#3918)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-17 17:49:04 +02:00
Lo
8ea99f0c4f docs(color-mode): fix computed setter logic in ColorModeButton.vue example (#3903) 2025-04-17 17:18:26 +02:00
Hannes Küttner
f6b376110c fix(InputMenu/Select/SelectMenu): add min-w-fit to content slot (#3922) 2025-04-17 14:13:55 +02:00
Hannes Küttner
01d8dc72ad fix(components): respect transform-origin in popper content (#3919)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-17 12:05:04 +02:00
Benjamin Canac
445aac2d57 docs(templates): add chat template 2025-04-16 18:08:11 +02:00
Hugo Richard
391828a2c2 docs(llms): improve llms-full.txt content (#3848)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-16 16:55:42 +02:00
Soryn
02b6b38a56 docs: change favicon color on theme color change (#3917) 2025-04-16 16:50:23 +02:00
Danila Poyarkov
47cdc2e1d8 fix(Link): proxy download property (#3879) 2025-04-16 16:15:13 +02:00
Benjamin Canac
a7d3097f8d chore(locale): order exports 2025-04-16 16:12:44 +02:00
Benjamin Canac
7ac7aa9ba7 feat(module): define default color shades (#3916) 2025-04-16 16:10:54 +02:00
Benjamin Canac
f9737c8f40 feat(module): dynamic rounded-* utilities (#3906) 2025-04-16 15:57:32 +02:00
Benjamin Canac
4e39cc59f8 chore(deps): update @nuxt/ui-pro 2025-04-16 15:47:36 +02:00
renovate[bot]
28accc4aa0 chore(deps): lock file maintenance (v3) (#3812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-16 10:31:03 +02:00
Sandro Circi
5d10f242bd chore(github): separate builds (#3885) 2025-04-16 10:26:10 +02:00
ElshadBeg
2d5c881639 chore(locale): rename Uyghur language code (#3908) 2025-04-16 10:25:44 +02:00
Selemon Brahanu
ad63753b5e docs(installation): improve .vscode/settings.json json (#3881)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2025-04-15 17:53:20 +02:00
Neil Richter
e5a1e26f9d fix(types): allow color identifiers with dashes (#3896) 2025-04-15 10:58:14 +02:00
Maxime Pauvert
113e2e7166 docs(form): fix typo in expose section (#3895) 2025-04-15 10:28:57 +02:00
renovate[bot]
9d4880be35 chore(deps): update tailwindcss to ^4.1.4 (v3) (#3899)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 10:22:42 +02:00
Sandro Circi
8dd9d08209 fix(types): improve dynamic slots (#3857) 2025-04-14 16:09:20 +02:00
Benjamin Canac
f309a46b8d chore(deps): update @nuxt/ui-pro 2025-04-14 14:13:21 +02:00
344 changed files with 23120 additions and 17242 deletions

View File

@@ -18,7 +18,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest] # macos-latest
os: ${{ github.event_name == 'pull_request' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest", "windows-latest"]') }} # macos-latest
node: [22]
env:
@@ -65,9 +65,57 @@ jobs:
run: pnpm run dev:vue:build
- name: Publish
if: matrix.os != 'windows-latest'
# Only publish preview package on ubuntu during PRs
if: matrix.os == 'ubuntu-latest'
run: pnpx pkg-pr-new publish --compact --no-template --pnpm
playground:
needs: build
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: ./playground
permissions:
contents: read
pull-requests: read
strategy:
matrix:
os: [ubuntu-latest] # macos-latest, windows-latest
node: [22]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Store commit SHA
run: |
echo "COMMIT_SHA=$(echo ${{ github.workflow_sha }} | cut -c1-7)" >> $GITHUB_ENV
- name: Install pnpm
uses: pnpm/action-setup@v4
- name: Install node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install latest nuxt/ui
run: pnpm install https://pkg.pr.new/@nuxt/ui@${{ env.COMMIT_SHA }} --lockfile-only
- name: Install dependencies
run: pnpm install --ignore-workspace
- name: Prepare
run: pnpm nuxi prepare
- name: Typecheck
run: pnpm run typecheck
starter-nuxt:
needs: build

54
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: release
on:
push:
tags:
- 'v3*'
jobs:
publish:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest] # macos-latest, windows-latest
node: [22]
env:
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
steps:
- name: Checkout
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
run: pnpm run dev:prepare
- name: Lint
run: pnpm run lint
- name: Typecheck
run: pnpm run typecheck
- name: Test
run: pnpm run test run
- name: Test (vue)
run: pnpm run test:vue run
- name: Publish
run: ./scripts/release.sh
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}

View File

@@ -3,6 +3,9 @@
"commitMessage": "chore(release): v${version}",
"tagName": "v${version}"
},
"npm": {
"publish": false
},
"github": {
"release": true,
"releaseName": "v${version}",

View File

@@ -1,5 +1,96 @@
# Changelog
## [3.1.1](https://github.com/nuxt/ui/compare/v3.1.0...v3.1.1) (2025-05-02)
### Features
* **useOverlay:** add `closeAll` method ([#3984](https://github.com/nuxt/ui/issues/3984)) ([ac4c194](https://github.com/nuxt/ui/commit/ac4c1946ec399aec59b4bce9d538e3ff67868abf))
* **useOverlay:** add `isOpen` method to check overlay state ([#4041](https://github.com/nuxt/ui/issues/4041)) ([a4f3f6d](https://github.com/nuxt/ui/commit/a4f3f6d531f9c0281f99085a6688d296f8f13f2f))
### Bug Fixes
* **Calendar:** add `place-items-center` to grid row ([#4034](https://github.com/nuxt/ui/issues/4034)) ([8dfdd63](https://github.com/nuxt/ui/commit/8dfdd63ce3b3a0e904f7c013c774cf9aaf46b240))
* **defineShortcuts:** bring back `meta` to `ctrl` convert on non macos platforms ([f3b8b17](https://github.com/nuxt/ui/commit/f3b8b17dc5f43936ef7ffb11c1ed7f9a5f94d0bb)), closes [#3869](https://github.com/nuxt/ui/issues/3869) [#3318](https://github.com/nuxt/ui/issues/3318)
* **module:** support `nuxt-nightly` ([#3996](https://github.com/nuxt/ui/issues/3996)) ([bc0a296](https://github.com/nuxt/ui/commit/bc0a296f9d68ca72cd991b11cd3489b63c7b13db))
* **NavigationMenu:** remove `sm:w-auto` from content slot ([aebf0b3](https://github.com/nuxt/ui/commit/aebf0b3dca50c51c093cb6abf16c4fd995fc1b39)), closes [#3987](https://github.com/nuxt/ui/issues/3987)
* **RadioGroup:** improve items `value` field type ([#3995](https://github.com/nuxt/ui/issues/3995)) ([195773e](https://github.com/nuxt/ui/commit/195773ec7dac12ccc3a0a67867751e8ca634cc04))
* **templates:** put back args to watch in dev ([#4033](https://github.com/nuxt/ui/issues/4033)) ([c5bdec0](https://github.com/nuxt/ui/commit/c5bdec0f64963ef602975270a09a1ee795cdacf9))
* **theme:** add missing `border-bg` / `divide-bg` utilities ([82b5f32](https://github.com/nuxt/ui/commit/82b5f322ebd8a08e63588122bd4ef567dcb8ba8c))
* **theme:** add missing `ring-offset-*` utilities ([#3992](https://github.com/nuxt/ui/issues/3992)) ([e5df026](https://github.com/nuxt/ui/commit/e5df0269935be59df759fe0e1378acb2b0d9014a))
* **theme:** define default shades for named tailwindcss colors ([8acf3c5](https://github.com/nuxt/ui/commit/8acf3c51db6c2f9443d04be6ba7d9f062c5cf8ab)), closes [#3977](https://github.com/nuxt/ui/issues/3977)
* **theme:** improve app config types for `ui` object ([591d59f](https://github.com/nuxt/ui/commit/591d59fe89f1d9bf016c121bf9160f73fe0a290d)), closes [#3579](https://github.com/nuxt/ui/issues/3579)
* **theme:** use `[@theme](https://github.com/theme) inline` to properly reference css variables ([6131871](https://github.com/nuxt/ui/commit/6131871a0d124c5942d60dc5dff20981e8542e51)), closes [#4018](https://github.com/nuxt/ui/issues/4018)
* **useOverlay:** improve types and docs ([#4012](https://github.com/nuxt/ui/issues/4012)) ([39e29fc](https://github.com/nuxt/ui/commit/39e29fccf1840c723a13237d65002501b2829b70))
## [3.1.0](https://github.com/nuxt/ui/compare/v3.0.2...v3.1.0) (2025-04-24)
### ⚠ BREAKING CHANGES
* **OverlayProvider:** return an overlay instance from `.open()` (#3829)
### Features
* **App:** add global `portal` prop ([#3688](https://github.com/nuxt/ui/issues/3688)) ([29fa462](https://github.com/nuxt/ui/commit/29fa46276d6bf69b5b87880c476c6f778c2820bf))
* **Carousel:** add `select` event ([#3678](https://github.com/nuxt/ui/issues/3678)) ([22edfd7](https://github.com/nuxt/ui/commit/22edfd708ae3eeadbd4ff6c830cdfd5632948286))
* **CheckboxGroup:** new component ([#3862](https://github.com/nuxt/ui/issues/3862)) ([9c3d53a](https://github.com/nuxt/ui/commit/9c3d53a02d6254f6b5c90e5fed826b8aefcdb042))
* **components:** add new `content-top` and `content-bottom` slots ([#3886](https://github.com/nuxt/ui/issues/3886)) ([1a46394](https://github.com/nuxt/ui/commit/1a463946681e152aa18372118d0fef4a7d8055a5))
* **Form:** add `attach` prop to opt-out of nested form attachement ([#3939](https://github.com/nuxt/ui/issues/3939)) ([1a0d7a3](https://github.com/nuxt/ui/commit/1a0d7a3103cf7591b019ef3ad685e2f3786ef6f2))
* **Form:** export loading state ([#3861](https://github.com/nuxt/ui/issues/3861)) ([fdee252](https://github.com/nuxt/ui/commit/fdee2522bb9d8361ff3e9fdd4aa2350be8e49b05))
* **InputMenu/SelectMenu:** handle `resetSearchTermOnSelect` ([cea881a](https://github.com/nuxt/ui/commit/cea881abdc139b39df89b503cf2ab872f4246c8f)), closes [#3782](https://github.com/nuxt/ui/issues/3782)
* **InputNumber:** add support for `stepSnapping` & `disableWheelChange` props ([#3731](https://github.com/nuxt/ui/issues/3731)) ([f5e6284](https://github.com/nuxt/ui/commit/f5e62849c9313063396ab0e3a9b7d22d98ef69bc))
* **locale:** add Bulgarian language ([#3783](https://github.com/nuxt/ui/issues/3783)) ([a0c9731](https://github.com/nuxt/ui/commit/a0c9731f634020e76aa98a9a68d673591d35e8c9))
* **locale:** add Kazakh language ([#3875](https://github.com/nuxt/ui/issues/3875)) ([43153c4](https://github.com/nuxt/ui/commit/43153c4e91034b728059e7a9bed05888e48f8890))
* **locale:** add Tajik language ([#3850](https://github.com/nuxt/ui/issues/3850)) ([f42a79b](https://github.com/nuxt/ui/commit/f42a79b5efe8dc65430a83799ebb0ee737773820))
* **locale:** add Uyghur language ([#3878](https://github.com/nuxt/ui/issues/3878)) ([b7fc69b](https://github.com/nuxt/ui/commit/b7fc69baa718ff65b3988d0fa9f143306fa8fac4))
* **Modal/Popover/Slideover:** add `close:prevent` event ([#3958](https://github.com/nuxt/ui/issues/3958)) ([f486423](https://github.com/nuxt/ui/commit/f4864233812eac0ed37e0a2d076a95c285a22c01))
* **module:** define default color shades ([#3916](https://github.com/nuxt/ui/issues/3916)) ([7ac7aa9](https://github.com/nuxt/ui/commit/7ac7aa9ba73b6aca1bc29b0de2e95c60b2700135))
* **module:** define neutral utilities ([#3629](https://github.com/nuxt/ui/issues/3629)) ([d49e0da](https://github.com/nuxt/ui/commit/d49e0dadeea2a58e05e60b2c461b29ce1d334d2b))
* **module:** dynamic `rounded-*` utilities ([#3906](https://github.com/nuxt/ui/issues/3906)) ([f9737c8](https://github.com/nuxt/ui/commit/f9737c8f401bf8bc5307674fad6defe2aeeeb907))
* **OverlayProvider:** return an overlay instance from `.open()` ([#3829](https://github.com/nuxt/ui/issues/3829)) ([f3098df](https://github.com/nuxt/ui/commit/f3098df84a3b7f58f7ccc1233bc8b45eab99ee10))
* **PinInput:** add `autofocus` / `autofocus-delay` props ([0456670](https://github.com/nuxt/ui/commit/0456670dac1153340220603c8c116e3b71f72ae7)), closes [#3717](https://github.com/nuxt/ui/issues/3717)
* **RadioGroup:** add `card` and `table` variants ([#3178](https://github.com/nuxt/ui/issues/3178)) ([4d138ad](https://github.com/nuxt/ui/commit/4d138ad6719a074f5f994006d12745ca05bec9c4))
* **Select:** handle `onSelect` field in items ([8640831](https://github.com/nuxt/ui/commit/864083156a79dfb5d0be868658b7f9fc77570178))
* **Table:** conditionally apply classes to `tr` and `td` ([#3866](https://github.com/nuxt/ui/issues/3866)) ([80dfa88](https://github.com/nuxt/ui/commit/80dfa88ea442571ee1dc673317cc7baa8cacd8a3))
* **Tabs:** add `list-leading` and `list-trailing` slots ([#3837](https://github.com/nuxt/ui/issues/3837)) ([3447a06](https://github.com/nuxt/ui/commit/3447a062b636a469089d6e9bdcfcb3dce9063ee5))
* **Textarea:** add `autoresize-delay` prop ([06414d3](https://github.com/nuxt/ui/commit/06414d344b151ad6e1a3225a9f5f1f76d58d319c)), closes [#3730](https://github.com/nuxt/ui/issues/3730)
* **Textarea:** add `icon`, `loading`, etc. props to match Input ([cb193f1](https://github.com/nuxt/ui/commit/cb193f1d25b5c73ca03dcf10864800350dd1c290))
* **Textarea:** add `resize-none` class with `autoresize` prop ([ffafd81](https://github.com/nuxt/ui/commit/ffafd81e1ed25074430668c792e5e1c6afc22bd0))
* **unplugin:** routing support for inertia ([#3845](https://github.com/nuxt/ui/issues/3845)) ([d059efc](https://github.com/nuxt/ui/commit/d059efca258da7ae5116e829189a492824ac1d87))
### Bug Fixes
* **Accordion:** use `div` instead of `h3` for header tag ([75e4792](https://github.com/nuxt/ui/commit/75e4792f7f00c55229253289c4f806f2b6fc9854)), closes [#3963](https://github.com/nuxt/ui/issues/3963)
* **Alert/Toast:** display actions when using slots ([5086363](https://github.com/nuxt/ui/commit/50863635d653c8083772046ddc5b828fba7047d0)), closes [#3950](https://github.com/nuxt/ui/issues/3950)
* **Carousel:** move arrows inside container on mobile ([d339dcb](https://github.com/nuxt/ui/commit/d339dcbfb8fe244bd198d247d8448e3ef856dfef)), closes [#3813](https://github.com/nuxt/ui/issues/3813)
* **CheckboxGroup:** proxy slots & `ui` prop ([bc06185](https://github.com/nuxt/ui/commit/bc061852822edd2dfb832a46dd6388123ec5771e))
* **CommandPalette:** consistent alignement with other components ([d25265c](https://github.com/nuxt/ui/commit/d25265c8b7d34e01af8827d9af5eccb98bf30e9e))
* **CommandPalette:** increase input font size to avoid zoom ([d227a10](https://github.com/nuxt/ui/commit/d227a105d8d409ea0753153afaecf639ddb80fed))
* **CommandPalette:** prevent hover background on disabled items ([ba534f1](https://github.com/nuxt/ui/commit/ba534f18b94383c97b2654d892ee4b8b024b3fab))
* **components:** refactor types after `@nuxt/module-builder` upgrade ([#3855](https://github.com/nuxt/ui/issues/3855)) ([39c861a](https://github.com/nuxt/ui/commit/39c861a64bbd452256ebd1a14a257b94c35855d4))
* **components:** respect `transform-origin` in popper content ([#3919](https://github.com/nuxt/ui/issues/3919)) ([01d8dc7](https://github.com/nuxt/ui/commit/01d8dc72adb0b32ad68bb4a98bf24b17f435a89c))
* **ContextMenu/DropdownMenu:** handle RTL mode ([#3744](https://github.com/nuxt/ui/issues/3744)) ([1ae5cc0](https://github.com/nuxt/ui/commit/1ae5cc09cb2eca6b6f53eb04db9dcc731b696cae))
* **ContextMenuContent/DropdownMenuContent:** remove unwanted `any` ([#3741](https://github.com/nuxt/ui/issues/3741)) ([97274f1](https://github.com/nuxt/ui/commit/97274f15b8bfe457e7e206f81b32e3febf0f875d))
* **Form:** input and output type inference ([#3938](https://github.com/nuxt/ui/issues/3938)) ([f429498](https://github.com/nuxt/ui/commit/f42949820be9be9fca41abc653dc12c033e1eeec))
* **Form:** loses focus on submit ([#3796](https://github.com/nuxt/ui/issues/3796)) ([8e78eb1](https://github.com/nuxt/ui/commit/8e78eb15c85beef1c814206c4a192d4eb00a7e86))
* **InputMenu/Select/SelectMenu:** add `min-w-fit` to `content` slot ([#3922](https://github.com/nuxt/ui/issues/3922)) ([f6b3761](https://github.com/nuxt/ui/commit/f6b376110c8bee2c41ae3137bb972aad402ebff1))
* **InputMenu/SelectMenu:** correctly call `onSelect` events ([#3735](https://github.com/nuxt/ui/issues/3735)) ([f25fed5](https://github.com/nuxt/ui/commit/f25fed58e988b304e79cdb536d544d257395cf89))
* **InputMenu/SelectMenu:** prevent `disabled` items to be selected ([8435a0f](https://github.com/nuxt/ui/commit/8435a0fe1622eb5b6863b6e4751c9d2d1be36db9)), closes [#3474](https://github.com/nuxt/ui/issues/3474)
* **InputMenu/SelectMenu:** remove `valueKey` string case ([9ca213b](https://github.com/nuxt/ui/commit/9ca213bd3340492d7503a34bd142e1f79a697050)), closes [#3949](https://github.com/nuxt/ui/issues/3949) [#3331](https://github.com/nuxt/ui/issues/3331)
* **InputMenu/SelectMenu:** support arbitrary `value` ([#3779](https://github.com/nuxt/ui/issues/3779)) ([52a97e2](https://github.com/nuxt/ui/commit/52a97e2df7903f91e3134931eb0d6bd4c528f71f))
* **InputMenu:** emit `change` on multiple item removal ([9d2fed1](https://github.com/nuxt/ui/commit/9d2fed125013e3bbfbf9435678729cd05254a5e8)), closes [#3756](https://github.com/nuxt/ui/issues/3756)
* **Link:** proxy `download` property ([#3879](https://github.com/nuxt/ui/issues/3879)) ([47cdc2e](https://github.com/nuxt/ui/commit/47cdc2e1d8cd9803ebc954ccae110d62b9a08779))
* **NavigationMenu:** add `sm:w-auto` content slot ([abe0859](https://github.com/nuxt/ui/commit/abe0859691e06564f68335bd82dcd121e976408e)), closes [#3788](https://github.com/nuxt/ui/issues/3788)
* **Skeleton:** improve accessibility ([#3613](https://github.com/nuxt/ui/issues/3613)) ([3484832](https://github.com/nuxt/ui/commit/3484832822015a224ce6fbeae5132018875557e6))
* **Stepper:** ui prop override on `icon` and `content` slots ([1d45980](https://github.com/nuxt/ui/commit/1d459803dc052a16b8966ee89c71646bf6ef1c16)), closes [#3785](https://github.com/nuxt/ui/issues/3785)
* **Table:** improve `data` reactivity ([#3967](https://github.com/nuxt/ui/issues/3967)) ([6e27304](https://github.com/nuxt/ui/commit/6e27304d8ca459a04667bac404084264a8cf58fd))
* **Table:** pass header `colspan` to `th` ([#3926](https://github.com/nuxt/ui/issues/3926)) ([122e8ac](https://github.com/nuxt/ui/commit/122e8ac8f41ba093cd350c3ce642263263f77296))
* **Tree:** simplify reusable template types ([#3836](https://github.com/nuxt/ui/issues/3836)) ([3deed4c](https://github.com/nuxt/ui/commit/3deed4c271cad4adc2a4c47d5dd02e95a14ce11a))
* **types:** allow color identifiers with dashes ([#3896](https://github.com/nuxt/ui/issues/3896)) ([e5a1e26](https://github.com/nuxt/ui/commit/e5a1e26f9db763b54caed4ca313f44d1b5fe269d))
* **types:** handle `ClassValue` in `ui` prop ([eea1415](https://github.com/nuxt/ui/commit/eea14155aa612649bc969d806ec5df4295945c70)), closes [#3860](https://github.com/nuxt/ui/issues/3860)
* **types:** improve dynamic slots ([#3857](https://github.com/nuxt/ui/issues/3857)) ([8dd9d08](https://github.com/nuxt/ui/commit/8dd9d08209e47a7d9a5654db4fb936b4cbcfc021))
* **usePortal:** adjust portal target resolution logic ([#3954](https://github.com/nuxt/ui/issues/3954)) ([db11db6](https://github.com/nuxt/ui/commit/db11db6ff1ce4b27a66aaa03f07870ba36426181))
* **vite:** vitest skipping nuxt imports transformations ([#3925](https://github.com/nuxt/ui/issues/3925)) ([c31bffa](https://github.com/nuxt/ui/commit/c31bffad1b8afeda584bca8c73bb7f790eb12a9f))
## [3.0.2](https://github.com/nuxt/ui/compare/v3.0.1...v3.0.2) (2025-03-28)
### Features

View File

@@ -16,6 +16,10 @@ Nuxt UI harnesses the combined strengths of [Reka UI](https://reka-ui.com/), [Ta
> [!NOTE]
> You are on the `v3` development branch, check out the [v2 branch](https://github.com/nuxt/ui/tree/v2) for Nuxt UI v2.
> [!TIP]
> **Looking for more components ?**
> Check out [Nuxt UI Pro](https://ui.nuxt.com/pro), a collection of premium Vue components, composables, and utilities built on top of Nuxt UI for faster and more powerful app development.
## Documentation
Visit https://ui.nuxt.com to explore the documentation.

View File

@@ -11,7 +11,7 @@ export default defineBuildConfig({
delimiters: ['', ''],
values: {
// Used in development to import directly from theme
'const isUiDev = true': 'const isUiDev = false'
'process.argv.includes(\'--uiDev\')': 'false'
}
}
},

View File

@@ -23,7 +23,7 @@ useHead({
{ key: 'theme-color', name: 'theme-color', content: color }
],
link: [
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' },
// { rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' },
{ rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
],
style: [
@@ -40,6 +40,8 @@ useServerSeoMeta({
twitterCard: 'summary_large_image'
})
useFaviconFromTheme()
const { frameworks, modules } = useSharedData()
const { mappedNavigation, filteredNavigation } = useContentNavigation(navigation)

View File

@@ -1,7 +1,7 @@
@import "tailwindcss" theme(static) source("../../../..");
@import "@nuxt/ui-pro";
@source "../../../content";
@source "../../../content/**/*";
@source "../../../node_modules/.c12";
@theme static {

View File

@@ -23,27 +23,27 @@ onMounted(() => {
@reference "../assets/css/main.css";
.carbon :deep(#carbonads) {
@apply relative border border-(--ui-border) rounded-[calc(var(--ui-radius)*1.5)] hover:bg-(--ui-bg-elevated)/50 w-full transition-colors min-h-[220px] p-2;
@apply relative border border-default rounded-md hover:bg-elevated/50 w-full transition-colors min-h-[220px] p-2;
.carbon-img {
@apply flex justify-center w-full;
& > img {
@apply !max-w-full w-full rounded-(--ui-radius);
@apply !max-w-full w-full rounded-sm;
}
}
.carbon-text {
@apply text-sm text-(--ui-text-muted) transition-colors text-center text-pretty flex pt-2;
@apply text-sm text-muted transition-colors text-center text-pretty flex pt-2;
}
.carbon-poweredby {
@apply block text-xs text-center text-(--ui-text-muted) pt-2;
@apply block text-xs text-center text-muted pt-2;
}
&:hover {
.carbon-text {
@apply text-(--ui-text);
@apply text-default;
}
}
}

View File

@@ -22,8 +22,8 @@ const links = [{
<UFooter>
<template #left>
<NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="text-sm text-(--ui-text-muted)">
Published under <span class="text-(--ui-text-highlighted)">MIT License</span>
<NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="text-sm text-muted">
Published under <span class="text-highlighted">MIT License</span>
</NuxtLink>
</template>

View File

@@ -19,8 +19,8 @@ watch(framework, () => {
:content="false"
color="neutral"
:ui="{
indicator: 'bg-(--ui-bg)',
trigger: 'px-1 data-[state=active]:text-(--ui-text-highlighted)'
indicator: 'bg-default',
trigger: 'px-1 data-[state=active]:text-highlighted'
}"
size="xs"
@update:model-value="(framework = $event as string)"

View File

@@ -41,7 +41,7 @@ const mobileLinks = computed(() => [
<template>
<UHeader :ui="{ left: 'min-w-0' }" :menu="{ shouldScaleBackground: true }">
<template #left>
<NuxtLink to="/" class="flex items-end gap-2 font-bold text-xl text-(--ui-text-highlighted) min-w-0 focus-visible:outline-(--ui-primary) shrink-0" aria-label="Nuxt UI">
<NuxtLink to="/" class="flex items-end gap-2 font-bold text-xl text-highlighted min-w-0 focus-visible:outline-primary shrink-0" aria-label="Nuxt UI">
<Logo v-if="route.path === '/'" class="w-auto h-6 shrink-0" />
<LogoPro v-else-if="route.path.startsWith('/pro')" class="w-auto h-6 shrink-0" />
<template v-else>
@@ -63,7 +63,7 @@ const mobileLinks = computed(() => [
trailing-icon="i-lucide-chevron-down"
size="xs"
class="-mb-[6px] font-semibold rounded-full truncate"
:class="[open && 'bg-(--ui-primary)/15 ']"
:class="[open && 'bg-primary/15 ']"
:ui="{
trailingIcon: ['transition-transform duration-200', open ? 'rotate-180' : undefined].filter(Boolean).join(' ')
}"
@@ -108,7 +108,7 @@ const mobileLinks = computed(() => [
<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>
<sup v-if="link.module === 'ui-pro'" class="text-[8px] font-medium text-primary">PRO</sup>
</span>
</template>
</UContentNavigation>

View File

@@ -19,8 +19,8 @@ watch(module, () => {
:content="false"
color="neutral"
:ui="{
indicator: 'bg-(--ui-bg)',
trigger: 'px-1 data-[state=active]:text-(--ui-text-highlighted)'
indicator: 'bg-default',
trigger: 'px-1 data-[state=active]:text-highlighted'
}"
size="xs"
@update:model-value="(module = $event as string)"

View File

@@ -153,7 +153,8 @@ const options = computed(() => {
const items = propItems.length
? propItems.map((item: any) => ({
value: item,
label: String(item)
label: String(item),
chip: key.toLowerCase().endsWith('color') ? { color: item } : undefined
}))
: prop?.type === 'boolean' || prop?.type === 'boolean | undefined'
? [{ value: true, label: 'true' }, { value: false, label: 'false' }]
@@ -329,15 +330,15 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
<template>
<div class="my-5">
<div class="relative">
<div v-if="options.length" class="flex flex-wrap items-center gap-2.5 border border-(--ui-border-muted) border-b-0 relative rounded-t-[calc(var(--ui-radius)*1.5)] px-4 py-2.5 overflow-x-auto">
<div v-if="options.length" class="flex flex-wrap items-center gap-2.5 border border-muted border-b-0 relative rounded-t-md px-4 py-2.5 overflow-x-auto">
<template v-for="option in options" :key="option.name">
<UFormField
:label="option.label"
size="sm"
class="inline-flex ring ring-(--ui-border-accented) rounded-(--ui-radius)"
class="inline-flex ring ring-accented rounded-sm"
:ui="{
wrapper: 'bg-(--ui-bg-elevated)/50 rounded-l-(--ui-radius) flex border-r border-(--ui-border-accented)',
label: 'text-(--ui-text-muted) px-2 py-1.5',
wrapper: 'bg-elevated/50 rounded-l-sm flex border-r border-accented',
label: 'text-muted px-2 py-1.5',
container: 'mt-0'
}"
>
@@ -348,7 +349,7 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
value-key="value"
color="neutral"
variant="soft"
class="rounded-(--ui-radius) rounded-l-none min-w-12"
class="rounded-sm rounded-l-none min-w-12"
:class="[option.name.toLowerCase().endsWith('color') && 'pl-6']"
:ui="{ itemLeadingChip: 'size-2' }"
@update:model-value="setComponentProp(option.name, $event)"
@@ -370,14 +371,14 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
:model-value="getComponentProp(option.name)"
color="neutral"
variant="soft"
:ui="{ base: 'rounded-(--ui-radius) rounded-l-none min-w-12' }"
:ui="{ base: 'rounded-sm rounded-l-none min-w-12' }"
@update:model-value="setComponentProp(option.name, $event)"
/>
</UFormField>
</template>
</div>
<div v-if="component" class="flex justify-center border border-b-0 border-(--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 }]">
<div v-if="component" class="flex justify-center border border-b-0 border-muted relative p-4 z-[1]" :class="[!options.length && 'rounded-t-md', 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">

View File

@@ -150,8 +150,8 @@ const urlSearchParams = computed(() => {
<template>
<div ref="el" class="my-5">
<template v-if="preview">
<div class="border border-(--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-(--ui-border-muted)">
<div class="border border-muted relative z-[1]" :class="[{ 'border-b-0 rounded-t-md': props.source, 'rounded-md': !props.source, 'overflow-hidden': props.overflowHidden }]">
<div v-if="props.options?.length || !!slots.options" class="flex gap-4 p-4 border-b border-muted">
<slot name="options" />
<UFormField
@@ -160,10 +160,10 @@ const urlSearchParams = computed(() => {
:label="option.label"
:name="option.name"
size="sm"
class="inline-flex ring ring-(--ui-border-accented) rounded-(--ui-radius)"
class="inline-flex ring ring-accented rounded-sm"
:ui="{
wrapper: 'bg-(--ui-bg-elevated)/50 rounded-l-(--ui-radius) flex border-r border-(--ui-border-accented)',
label: 'text-(--ui-text-muted) px-2 py-1.5',
wrapper: 'bg-elevated/50 rounded-l-sm flex border-r border-accented',
label: 'text-muted px-2 py-1.5',
container: 'mt-0'
}"
>
@@ -175,7 +175,7 @@ const urlSearchParams = computed(() => {
:value-key="option.name.toLowerCase().endsWith('color') ? 'value' : undefined"
color="neutral"
variant="soft"
class="rounded-(--ui-radius) rounded-l-none min-w-12"
class="rounded-sm rounded-l-none min-w-12"
:multiple="option.multiple"
:class="[option.name.toLowerCase().endsWith('color') && 'pl-6']"
:ui="{ itemLeadingChip: 'size-2' }"
@@ -196,7 +196,7 @@ const urlSearchParams = computed(() => {
:model-value="get(optionsValues, option.name)"
color="neutral"
variant="soft"
:ui="{ base: 'rounded-(--ui-radius) rounded-l-none min-w-12' }"
:ui="{ base: 'rounded-sm rounded-l-none min-w-12' }"
@update:model-value="set(optionsValues, option.name, $event)"
/>
</UFormField>

View File

@@ -112,7 +112,7 @@ const metaProps: ComputedRef<ComponentMeta['props']> = computed(() => {
<ProseTd>
<HighlightInlineType v-if="prop.type" :type="prop.type" />
<MDC v-if="prop.description" :value="prop.description" class="text-(--ui-text-toned) mt-1" :cache-key="`${kebabCase(route.path)}-${prop.name}-description`" />
<MDC v-if="prop.description" :value="prop.description" class="text-toned mt-1" :cache-key="`${kebabCase(route.path)}-${prop.name}-description`" />
<ComponentPropsLinks v-if="prop.tags?.length" :prop="prop" />
<ComponentPropsSchema v-if="prop.schema" :prop="prop" :ignore="ignore" />

View File

@@ -43,7 +43,7 @@ const schemaProps = computed(() => {
<ProseLi v-for="schemaProp in schemaProps" :key="schemaProp.name">
<HighlightInlineType :type="`${schemaProp.name}${schemaProp.required === false ? '?' : ''}: ${schemaProp.type}`" />
<MDC v-if="schemaProp.description" :value="schemaProp.description" class="text-(--ui-text-muted) my-1" :cache-key="`${kebabCase(route.path)}-${prop.name}-${schemaProp.name}-description`" />
<MDC v-if="schemaProp.description" :value="schemaProp.description" class="text-muted my-1" :cache-key="`${kebabCase(route.path)}-${prop.name}-${schemaProp.name}-description`" />
</ProseLi>
</ProseUl>
</ProseCollapsible>

View File

@@ -36,7 +36,7 @@ const meta = await fetchComponentMeta(name as any)
<ProseTd>
<HighlightInlineType v-if="slot.type" :type="slot.type" />
<MDC v-if="slot.description" :value="slot.description" class="text-(--ui-text-toned) mt-1" :cache-key="`${kebabCase(route.path)}-${slot.name}-description`" />
<MDC v-if="slot.description" :value="slot.description" class="text-toned mt-1" :cache-key="`${kebabCase(route.path)}-${slot.name}-description`" />
</ProseTd>
</ProseTr>
</ProseTbody>

View File

@@ -1,6 +1,6 @@
<template>
<div class="relative overflow-hidden rounded-(--ui-radius) border border-dashed border-(--ui-border-accented) opacity-75 px-4 flex items-center justify-center">
<svg class="absolute inset-0 h-full w-full stroke-(--ui-border-inverted)/10" fill="none">
<div class="relative overflow-hidden rounded-sm border border-dashed border-accented opacity-75 px-4 flex items-center justify-center">
<svg class="absolute inset-0 h-full w-full stroke-inverted/10" fill="none">
<defs>
<pattern
id="pattern-5c1e4f0e-62d5-498b-8ff0-cf77bb448c8e"

View File

@@ -20,7 +20,7 @@ const items: AccordionItem[] = [
<template>
<UAccordion :items="items">
<template #content="{ item }">
<p class="pb-3.5 text-sm text-(--ui-text-muted)">
<p class="pb-3.5 text-sm text-muted">
This is the {{ item.label }} panel.
</p>
</template>

View File

@@ -24,7 +24,7 @@ const items = [
<template>
<UAccordion :items="items">
<template #colors="{ item }">
<p class="text-sm pb-3.5 text-(--ui-primary)">
<p class="text-sm pb-3.5 text-primary">
{{ item.content }}
</p>
</template>

View File

@@ -3,7 +3,7 @@
<ULink
to="https://github.com/benjamincanac"
target="_blank"
class="hover:ring-(--ui-primary) transition"
class="hover:ring-primary transition"
raw
>
<UAvatar
@@ -15,7 +15,7 @@
<ULink
to="https://github.com/romhml"
target="_blank"
class="hover:ring-(--ui-primary) transition"
class="hover:ring-primary transition"
raw
>
<UAvatar
@@ -27,7 +27,7 @@
<ULink
to="https://github.com/noook"
target="_blank"
class="hover:ring-(--ui-primary) transition"
class="hover:ring-primary transition"
raw
>
<UAvatar

View File

@@ -20,7 +20,7 @@ const items: BreadcrumbItem[] = [
<template>
<UBreadcrumb :items="items">
<template #separator>
<span class="mx-2 text-(--ui-text-muted)">/</span>
<span class="mx-2 text-muted">/</span>
</template>
</UBreadcrumb>
</template>

View File

@@ -0,0 +1,21 @@
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const date = shallowRef(new CalendarDate(2025, 4, 2))
</script>
<template>
<div class="flex flex-col gap-4">
<UCalendar v-model="date" :month-controls="false" :year-controls="false" />
<div class="flex justify-between gap-4">
<UButton color="neutral" variant="outline" @click="date = date.subtract({ months: 1 })">
Prev
</UButton>
<UButton color="neutral" variant="outline" @click="date = date.add({ months: 1 })">
Next
</UButton>
</div>
</div>
</template>

View File

@@ -0,0 +1,58 @@
<script setup lang="ts">
const items = [
'https://picsum.photos/640/640?random=1',
'https://picsum.photos/640/640?random=2',
'https://picsum.photos/640/640?random=3',
'https://picsum.photos/640/640?random=4',
'https://picsum.photos/640/640?random=5',
'https://picsum.photos/640/640?random=6'
]
const carousel = useTemplateRef('carousel')
const activeIndex = ref(0)
function onClickPrev() {
activeIndex.value--
}
function onClickNext() {
activeIndex.value++
}
function onSelect(index: number) {
activeIndex.value = index
}
function select(index: number) {
activeIndex.value = index
carousel.value?.emblaApi?.scrollTo(index)
}
</script>
<template>
<div class="flex-1 w-full">
<UCarousel
ref="carousel"
v-slot="{ item }"
arrows
:items="items"
:prev="{ onClick: onClickPrev }"
:next="{ onClick: onClickNext }"
class="w-full max-w-xs mx-auto"
@select="onSelect"
>
<img :src="item" width="320" height="320" class="rounded-lg">
</UCarousel>
<div class="flex gap-1 justify-between pt-4 max-w-xs mx-auto">
<div
v-for="(item, index) in items"
:key="index"
class="size-11 opacity-25 hover:opacity-100 transition-opacity"
:class="{ 'opacity-100': activeIndex === index }"
@click="select(index)"
>
<img :src="item" width="44" height="44" class="rounded-lg">
</div>
</div>
</div>
</template>

View File

@@ -35,7 +35,7 @@ const items = computed<ContextMenuItem[]>(() => [{
<template>
<UContextMenu :items="items" :ui="{ content: 'w-48' }">
<div class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72">
<div class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72">
Right click here
</div>
</UContextMenu>

View File

@@ -28,7 +28,7 @@ const items: ContextMenuItem[][] = [
<template>
<UContextMenu :items="items" :ui="{ content: 'w-48' }">
<div class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72">
<div class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72">
Right click here
</div>
</UContextMenu>

View File

@@ -19,7 +19,7 @@ const items = [
<template>
<UContextMenu :items="items" :ui="{ content: 'w-48' }">
<div class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72">
<div class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72">
Right click here
</div>
@@ -28,7 +28,7 @@ const items = [
</template>
<template #refresh-trailing>
<UIcon v-if="loading" name="i-lucide-refresh-cw" class="shrink-0 size-5 text-(--ui-primary) animate-spin" />
<UIcon v-if="loading" name="i-lucide-refresh-cw" class="shrink-0 size-5 text-primary animate-spin" />
</template>
</UContextMenu>
</template>

View File

@@ -7,7 +7,7 @@ const open = ref(false)
<UButton label="Open" color="neutral" variant="subtle" trailing-icon="i-lucide-chevron-up" />
<template #header>
<h2 class="text-(--ui-text-highlighted) font-semibold">
<h2 class="text-highlighted font-semibold">
Drawer non-dismissible
</h2>

View File

@@ -21,7 +21,7 @@ const items = [
<UButton label="Open" color="neutral" variant="outline" icon="i-lucide-menu" />
<template #profile-trailing>
<UIcon name="i-lucide-badge-check" class="shrink-0 size-5 text-(--ui-primary)" />
<UIcon name="i-lucide-badge-check" class="shrink-0 size-5 text-primary" />
</template>
</UDropdownMenu>
</template>

View File

@@ -30,14 +30,16 @@ const schema = z.object({
radioGroup: z.string().refine(value => value === 'option-2', {
message: 'Select Option 2'
}),
checkboxGroup: z.any().refine(values => !!values?.find((option: any) => option === 'option-2'), {
message: 'Include Option 2'
}),
slider: z.number().max(20, { message: 'Must be less than 20' }),
pin: z.string().regex(/^\d$/).array().length(5)
})
type Input = z.input<typeof schema>
type Output = z.output<typeof schema>
type Schema = z.input<typeof schema>
const state = reactive<Partial<Input>>({})
const state = reactive<Partial<Schema>>({})
const form = useTemplateRef('form')
@@ -48,7 +50,7 @@ const items = [
]
const toast = useToast()
async function onSubmit(event: FormSubmitEvent<Output>) {
async function onSubmit(event: FormSubmitEvent<Schema>) {
toast.add({ title: 'Success', description: 'The form has been submitted.', color: 'success' })
console.log(event.data)
}
@@ -102,11 +104,14 @@ async function onSubmit(event: FormSubmitEvent<Output>) {
<UFormField label="Textarea" name="textarea">
<UTextarea v-model="state.textarea" class="w-full" />
</UFormField>
<UFormField name="radioGroup">
<URadioGroup v-model="state.radioGroup" legend="Radio group" :items="items" />
</UFormField>
<div class="flex gap-4">
<UFormField name="radioGroup">
<URadioGroup v-model="state.radioGroup" legend="Radio group" :items="items" />
</UFormField>
<UFormField name="checkboxGroup">
<UCheckboxGroup v-model="state.checkboxGroup" legend="Checkbox group" :items="items" />
</UFormField>
</div>
<UFormField name="pin" label="Pin Input" :error-pattern="/(pin)\..*/">
<UPinInput v-model="state.pin" />
</UFormField>

View File

@@ -39,7 +39,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
<UCheckbox v-model="state.news" name="news" label="Register to our newsletter" @update:model-value="state.email = undefined" />
</div>
<UForm v-if="state.news" :state="state" :schema="nestedSchema" nested>
<UForm v-if="state.news" :state="state" :schema="nestedSchema" attach>
<UFormField label="Email" name="email">
<UInput v-model="state.email" placeholder="john@lennon.com" />
</UFormField>

View File

@@ -56,7 +56,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
:key="count"
:state="item"
:schema="itemSchema"
nested
attach
class="flex gap-2"
>
<UFormField :label="!count ? 'Description' : undefined" name="description">

View File

@@ -36,7 +36,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<template #item-label="{ item }">
{{ item.label }}
<span class="text-(--ui-text-muted)">
<span class="text-muted">
{{ item.email }}
</span>
</template>

View File

@@ -15,7 +15,7 @@ const domain = ref(domains[0])
}"
>
<template #leading>
<p class="text-sm text-(--ui-text-muted)">
<p class="text-sm text-muted">
https://
</p>
</template>

View File

@@ -13,7 +13,7 @@ const maxLength = 15
<template #trailing>
<div
id="character-count"
class="text-xs text-(--ui-text-muted) tabular-nums"
class="text-xs text-muted tabular-nums"
aria-live="polite"
role="status"
>

View File

@@ -4,8 +4,8 @@ const value = ref('')
<template>
<UInput v-model="value" placeholder="" :ui="{ base: 'peer' }">
<label class="pointer-events-none absolute left-0 -top-2.5 text-(--ui-text-highlighted) text-xs font-medium px-1.5 transition-all peer-focus:-top-2.5 peer-focus:text-(--ui-text-highlighted) peer-focus:text-xs peer-focus:font-medium peer-placeholder-shown:text-sm peer-placeholder-shown:text-(--ui-text-dimmed) peer-placeholder-shown:top-1.5 peer-placeholder-shown:font-normal">
<span class="inline-flex bg-(--ui-bg) px-1">Email address</span>
<label class="pointer-events-none absolute left-0 -top-2.5 text-highlighted text-xs font-medium px-1.5 transition-all peer-focus:-top-2.5 peer-focus:text-highlighted peer-focus:text-xs peer-focus:font-medium peer-placeholder-shown:text-sm peer-placeholder-shown:text-dimmed peer-placeholder-shown:top-1.5 peer-placeholder-shown:font-normal">
<span class="inline-flex bg-default px-1">Email address</span>
</label>
</UInput>
</template>

View File

@@ -77,7 +77,7 @@ const text = computed(() => {
v-for="(req, index) in strength"
:key="index"
class="flex items-center gap-0.5"
:class="req.met ? 'text-(--ui-success)' : 'text-(--ui-text-muted)'"
:class="req.met ? 'text-success' : 'text-muted'"
>
<UIcon :name="req.met ? 'i-lucide-circle-check' : 'i-lucide-circle-x'" class="size-4 shrink-0" />

View File

@@ -13,7 +13,9 @@ const modal = overlay.create(LazyModalExample, {
})
async function open() {
const shouldIncrement = await modal.open()
const instance = modal.open()
const shouldIncrement = await instance.result
if (shouldIncrement) {
count.value++

View File

@@ -65,6 +65,7 @@ const items = [
class="w-full justify-center"
:ui="{
viewport: 'sm:w-(--reka-navigation-menu-viewport-width)',
content: 'sm:w-auto',
childList: 'sm:w-96',
childLinkDescription: 'text-balance line-clamp-2'
}"
@@ -76,11 +77,11 @@ const items = [
</li>
<li v-for="child in item.children" :key="child.label">
<ULink class="text-sm text-left rounded-md p-3 transition-colors hover:bg-(--ui-bg-elevated)/50">
<p class="font-medium text-(--ui-text-highlighted)">
<ULink class="text-sm text-left rounded-md p-3 transition-colors hover:bg-elevated/50">
<p class="font-medium text-highlighted">
{{ child.label }}
</p>
<p class="text-(--ui-text-muted) line-clamp-2">
<p class="text-muted line-clamp-2">
{{ child.description }}
</p>
</ULink>

View File

@@ -8,7 +8,7 @@ const open = ref(false)
<template #content>
<div class="flex items-center gap-4 mb-4">
<h2 class="text-(--ui-text-highlighted) font-semibold">
<h2 class="text-highlighted font-semibold">
Popover non-dismissible
</h2>

View File

@@ -36,7 +36,7 @@ const { data: users, status } = await useFetch('https://jsonplaceholder.typicode
<template #item-label="{ item }">
{{ item.label }}
<span class="text-(--ui-text-muted)">
<span class="text-muted">
{{ item.email }}
</span>
</template>

View File

@@ -13,7 +13,9 @@ const slideover = overlay.create(LazySlideoverExample, {
})
async function open() {
const shouldIncrement = await slideover.open()
const instance = slideover.open()
const shouldIncrement = await instance.result
if (shouldIncrement) {
count.value++

View File

@@ -100,7 +100,7 @@ const columnFilters = ref([{
<template>
<div class="flex flex-col flex-1 w-full">
<div class="flex px-4 py-3.5 border-b border-(--ui-border-accented)">
<div class="flex px-4 py-3.5 border-b border-accented">
<UInput
:model-value="(table?.tableApi?.getColumn('email')?.getFilterValue() as string)"
class="max-w-sm"

View File

@@ -131,7 +131,7 @@ function getHeader(column: Column<Payment>, label: string) {
'variant': 'ghost',
label,
'icon': isSorted ? (isSorted === 'asc' ? 'i-lucide-arrow-up-narrow-wide' : 'i-lucide-arrow-down-wide-narrow') : 'i-lucide-arrow-up-down',
'class': '-mx-2.5 data-[state=open]:bg-(--ui-bg-elevated)',
'class': '-mx-2.5 data-[state=open]:bg-elevated',
'aria-label': `Sort by ${isSorted === 'asc' ? 'descending' : 'ascending'}`
}))
}

View File

@@ -100,7 +100,7 @@ const columnVisibility = ref({
<template>
<div class="flex flex-col flex-1 w-full">
<div class="flex justify-end px-4 py-3.5 border-b border-(--ui-border-accented)">
<div class="flex justify-end px-4 py-3.5 border-b border-accented">
<UDropdownMenu
:items="table?.tableApi?.getAllColumns().filter(column => column.getCanHide()).map(column => ({
label: upperFirst(column.id),

View File

@@ -0,0 +1,82 @@
<script setup lang="ts">
import type { TableColumn } from '@nuxt/ui'
import { useSortable } from '@vueuse/integrations/useSortable.mjs'
type Payment = {
id: string
date: string
email: string
amount: number
}
const data = ref<Payment[]>([{
id: '4600',
date: '2024-03-11T15:30:00',
email: 'james.anderson@example.com',
amount: 594
}, {
id: '4599',
date: '2024-03-11T10:10:00',
email: 'mia.white@example.com',
amount: 276
}, {
id: '4598',
date: '2024-03-11T08:50:00',
email: 'william.brown@example.com',
amount: 315
}, {
id: '4597',
date: '2024-03-10T19:45:00',
email: 'emma.davis@example.com',
amount: 529
}])
const columns: TableColumn<Payment>[] = [{
accessorKey: 'id',
header: '#',
cell: ({ row }) => `#${row.getValue('id')}`
}, {
accessorKey: 'date',
header: 'Date',
cell: ({ row }) => {
return new Date(row.getValue('date')).toLocaleString('en-US', {
day: 'numeric',
month: 'short',
hour: '2-digit',
minute: '2-digit',
hour12: false
})
}
}, {
accessorKey: 'email',
header: 'Email'
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
cell: ({ row }) => {
const amount = Number.parseFloat(row.getValue('amount'))
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'EUR'
}).format(amount)
return h('div', { class: 'text-right font-medium' }, formatted)
}
}]
useSortable('.my-table-tbody', data, {
animation: 150
})
</script>
<template>
<div class="w-full">
<UTable
ref="table"
:data="data"
:columns="columns"
:ui="{
tbody: 'my-table-tbody'
}"
/>
</div>
</template>

View File

@@ -265,7 +265,7 @@ function randomize() {
</script>
<template>
<div class="flex-1 divide-y divide-(--ui-border-accented) w-full">
<div class="flex-1 divide-y divide-accented w-full">
<div class="flex items-center gap-2 px-4 py-3.5 overflow-x-auto">
<UInput
:model-value="(table?.tableApi?.getColumn('email')?.getFilterValue() as string)"
@@ -313,7 +313,7 @@ function randomize() {
</template>
</UTable>
<div class="px-4 py-3.5 text-sm text-(--ui-text-muted)">
<div class="px-4 py-3.5 text-sm text-muted">
{{ table?.tableApi?.getFilteredSelectedRowModel().rows.length || 0 }} of
{{ table?.tableApi?.getFilteredRowModel().rows.length || 0 }} row(s) selected.
</div>

View File

@@ -36,7 +36,7 @@ const columns: TableColumn<User>[] = [{
size: 'lg'
}),
h('div', undefined, [
h('p', { class: 'font-medium text-(--ui-text-highlighted)' }, row.original.name),
h('p', { class: 'font-medium text-highlighted' }, row.original.name),
h('p', { class: '' }, `@${row.original.username}`)
])
])

View File

@@ -95,7 +95,7 @@ const globalFilter = ref('45')
<template>
<div class="flex flex-col flex-1 w-full">
<div class="flex px-4 py-3.5 border-b border-(--ui-border-accented)">
<div class="flex px-4 py-3.5 border-b border-accented">
<UInput
v-model="globalFilter"
class="max-w-sm"

View File

@@ -0,0 +1,88 @@
<script setup lang="ts">
import type { TableColumn } from '@nuxt/ui'
import { useInfiniteScroll } from '@vueuse/core'
const UAvatar = resolveComponent('UAvatar')
type User = {
id: number
firstName: string
username: string
email: string
image: string
}
type UserResponse = {
users: User[]
total: number
skip: number
limit: number
}
const skip = ref(0)
const { data, status, execute } = await useFetch('https://dummyjson.com/users?limit=10&select=firstName,username,email,image', {
key: 'table-users-infinite-scroll',
params: { skip },
transform: (data?: UserResponse) => {
return data?.users
},
lazy: true,
immediate: false
})
const columns: TableColumn<User>[] = [{
accessorKey: 'id',
header: 'ID'
}, {
accessorKey: 'image',
header: 'Avatar',
cell: ({ row }) => h(UAvatar, { src: row.original.image })
}, {
accessorKey: 'firstName',
header: 'First name'
}, {
accessorKey: 'email',
header: 'Email'
}, {
accessorKey: 'username',
header: 'Username'
}]
const users = ref<User[]>([])
watch(data, () => {
users.value = [
...users.value,
...(data.value || [])
]
})
execute()
const table = useTemplateRef<ComponentPublicInstance>('table')
onMounted(() => {
useInfiniteScroll(table.value?.$el, () => {
skip.value += 10
}, {
distance: 200,
canLoadMore: () => {
return status.value !== 'pending'
}
})
})
</script>
<template>
<div class="w-full">
<UTable
ref="table"
:data="users"
:columns="columns"
:loading="status === 'pending'"
sticky
class="flex-1 h-80"
/>
</div>
</template>

View File

@@ -162,7 +162,7 @@ const pagination = ref({
class="flex-1"
/>
<div class="flex justify-center border-t border-(--ui-border) pt-4">
<div class="flex justify-center border-t border-default pt-4">
<UPagination
:default-page="(table?.tableApi?.getState().pagination.pageIndex || 0) + 1"
:items-per-page="table?.tableApi?.getState().pagination.pageSize"

View File

@@ -112,7 +112,7 @@ const expanded = ref({ 1: true })
v-model:expanded="expanded"
:data="data"
:columns="columns"
:ui="{ tr: 'data-[expanded=true]:bg-(--ui-bg-elevated)/50' }"
:ui="{ tr: 'data-[expanded=true]:bg-elevated/50' }"
class="flex-1"
>
<template #expanded="{ row }">

View File

@@ -122,7 +122,7 @@ function onSelect(row: TableRow<Payment>, e?: Event) {
@select="onSelect"
/>
<div class="px-4 py-3.5 border-t border-[var(--ui-border-accented)] text-sm text-[var(--ui-text-muted)]">
<div class="px-4 py-3.5 border-t border-accented text-sm text-muted">
{{ table?.tableApi?.getFilteredSelectedRowModel().rows.length || 0 }} of
{{ table?.tableApi?.getFilteredRowModel().rows.length || 0 }} row(s) selected.
</div>

View File

@@ -113,7 +113,7 @@ const rowSelection = ref({ 1: true })
:columns="columns"
/>
<div class="px-4 py-3.5 border-t border-(--ui-border-accented) text-sm text-(--ui-text-muted)">
<div class="px-4 py-3.5 border-t border-accented text-sm text-muted">
{{ table?.tableApi?.getFilteredSelectedRowModel().rows.length || 0 }} of
{{ table?.tableApi?.getFilteredRowModel().rows.length || 0 }} row(s) selected.
</div>

View File

@@ -97,7 +97,7 @@ function getDropdownActions(user: User): DropdownMenuItem[][] {
<div class="flex items-center gap-3">
<UAvatar :src="`https://i.pravatar.cc/120?img=${row.original.id}`" size="lg" :alt="`${row.original.name} avatar`" />
<div>
<p class="font-medium text-(--ui-text-highlighted)">
<p class="font-medium text-highlighted">
{{ row.original.name }}
</p>
<p>

View File

@@ -28,7 +28,7 @@ const state = reactive({
<template>
<UTabs :items="items" variant="link" class="gap-4 w-full" :ui="{ trigger: 'flex-1' }">
<template #account="{ item }">
<p class="text-(--ui-text-muted) mb-4">
<p class="text-muted mb-4">
{{ item.description }}
</p>
@@ -45,7 +45,7 @@ const state = reactive({
</template>
<template #password="{ item }">
<p class="text-(--ui-text-muted) mb-4">
<p class="text-muted mb-4">
{{ item.description }}
</p>

View File

@@ -7,10 +7,10 @@ const appConfig = useAppConfig()
<UFormField
label="toaster.duration"
size="sm"
class="inline-flex ring ring-(--ui-border-accented) rounded-(--ui-radius)"
class="inline-flex ring ring-accented rounded-sm"
:ui="{
wrapper: 'bg-(--ui-bg-elevated)/50 rounded-l-(--ui-radius) flex border-r border-(--ui-border-accented)',
label: 'text-(--ui-text-muted) px-2 py-1.5',
wrapper: 'bg-elevated/50 rounded-l-sm flex border-r border-accented',
label: 'text-muted px-2 py-1.5',
container: 'mt-0'
}"
>
@@ -18,7 +18,7 @@ const appConfig = useAppConfig()
v-model="appConfig.toaster.duration"
color="neutral"
variant="soft"
:ui="{ base: 'rounded-(--ui-radius) rounded-l-none min-w-12' }"
:ui="{ base: 'rounded-sm rounded-l-none min-w-12' }"
/>
</UFormField>
</div>

View File

@@ -7,10 +7,10 @@ const appConfig = useAppConfig()
<UFormField
label="toaster.expand"
size="sm"
class="inline-flex ring ring-(--ui-border-accented) rounded-(--ui-radius)"
class="inline-flex ring ring-accented rounded-sm"
:ui="{
wrapper: 'bg-(--ui-bg-elevated)/50 rounded-l-(--ui-radius) flex border-r border-(--ui-border-accented)',
label: 'text-(--ui-text-muted) px-2 py-1.5',
wrapper: 'bg-elevated/50 rounded-l-sm flex border-r border-accented',
label: 'text-muted px-2 py-1.5',
container: 'mt-0'
}"
>
@@ -19,7 +19,7 @@ const appConfig = useAppConfig()
:items="[true, false]"
color="neutral"
variant="soft"
class="rounded-(--ui-radius) rounded-l-none min-w-12"
class="rounded-sm rounded-l-none min-w-12"
:search-input="false"
/>
</UFormField>

View File

@@ -10,10 +10,10 @@ const appConfig = useAppConfig()
<UFormField
label="toaster.position"
size="sm"
class="inline-flex ring ring-(--ui-border-accented) rounded-(--ui-radius)"
class="inline-flex ring ring-accented rounded-sm"
:ui="{
wrapper: 'bg-(--ui-bg-elevated)/50 rounded-l-(--ui-radius) flex border-r border-(--ui-border-accented)',
label: 'text-(--ui-text-muted) px-2 py-1.5',
wrapper: 'bg-elevated/50 rounded-l-sm flex border-r border-accented',
label: 'text-muted px-2 py-1.5',
container: 'mt-0'
}"
>
@@ -22,7 +22,7 @@ const appConfig = useAppConfig()
:items="positions"
color="neutral"
variant="soft"
class="rounded-(--ui-radius) rounded-l-none min-w-12"
class="rounded-sm rounded-l-none min-w-12"
:search-input="false"
/>
</UFormField>

View File

@@ -20,7 +20,7 @@ const { width } = useElementSize(el)
<template>
<div
class="isolate rounded-full relative circle w-full aspect-[1/1] p-8 sm:p-12 md:p-14 lg:p-10 xl:p-16 before:absolute before:inset-px before:bg-(--ui-bg) before:rounded-full z-(--level)"
class="isolate rounded-full relative circle w-full aspect-[1/1] p-8 sm:p-12 md:p-14 lg:p-10 xl:p-16 before:absolute before:inset-px before:bg-default before:rounded-full z-(--level)"
:class="{ 'animation-paused': paused }"
:style="{
'--duration': `${((level + 1) * 8)}s`,
@@ -65,7 +65,7 @@ const { width } = useElementSize(el)
:src="`https://ipx.nuxt.com/s_56x56/gh_avatar/${contributor.username}`"
:srcset="`https://ipx.nuxt.com/s_112x112/gh_avatar/${contributor.username} 2x`"
:alt="contributor.username"
class="ring-2 ring-(--ui-border) lg:hover:ring-(--ui-border-inverted) transition rounded-full size-7"
class="ring-2 ring-default lg:hover:ring-inverted transition rounded-full size-7"
loading="lazy"
>
</NuxtLink>

View File

@@ -69,7 +69,7 @@ function setBlackAsPrimary(value: boolean) {
:variant="open ? 'soft' : 'ghost'"
square
aria-label="Color picker"
:ui="{ leadingIcon: 'text-(--ui-primary)' }"
:ui="{ leadingIcon: 'text-primary' }"
/>
</template>

View File

@@ -18,8 +18,8 @@ const slots = defineSlots<{
variant="outline"
:icon="icon"
:label="label"
class="capitalize ring-(--ui-border) rounded-[calc(var(--ui-radius))] text-[11px]"
:class="[selected ? 'bg-(--ui-bg-elevated)' : 'hover:bg-(--ui-bg-elevated)/50']"
class="capitalize ring-default rounded-sm text-[11px]"
:class="[selected ? 'bg-elevated' : 'hover:bg-elevated/50']"
>
<template v-if="chip || !!slots.leading" #leading>
<slot name="leading">

View File

@@ -0,0 +1,54 @@
import { onMounted, watch } from 'vue'
import FaviconSvg from 'public/icon.svg?raw'
export function useFaviconFromTheme() {
const colorMode = useColorMode()
function generateFaviconSvg(color: string) {
const parser = new DOMParser()
const doc = parser.parseFromString(FaviconSvg, 'image/svg+xml')
const svg = doc.documentElement
svg.querySelectorAll('path').forEach((path) => {
path.setAttribute('fill', color)
})
return new XMLSerializer().serializeToString(svg)
}
function updateFavicon() {
const root = document.documentElement
const color = getComputedStyle(root).getPropertyValue('--ui-primary').trim() || '#00DC82'
const svg = generateFaviconSvg(color)
const encoded = `data:image/svg+xml,${encodeURIComponent(svg)}`
useFavicon(encoded)
}
function setupMutationObserver() {
const styleTag = document.getElementById('nuxt-ui-colors')
if (!styleTag) return
const observer = new MutationObserver(() => {
updateFavicon()
})
observer.observe(styleTag, {
characterData: true,
subtree: true,
childList: true
})
}
onMounted(() => {
watch(colorMode, () => {
updateFavicon()
}, {
immediate: true,
flush: 'post'
})
setupMutationObserver()
})
}

View File

@@ -26,7 +26,7 @@ useHead({
{ key: 'theme-color', name: 'theme-color', content: color }
],
link: [
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' }
// { rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' }
],
style: [
{ innerHTML: radius, id: 'nuxt-ui-radius', tagPriority: -2 },
@@ -47,6 +47,8 @@ useServerSeoMeta({
twitterCard: 'summary_large_image'
})
useFaviconFromTheme()
const { frameworks, modules } = useSharedData()
const { mappedNavigation, filteredNavigation } = useContentNavigation(navigation)

View File

@@ -22,7 +22,7 @@ const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
<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>
<sup v-if="link.module === 'ui-pro'" class="text-[8px] font-medium text-primary">PRO</sup>
</span>
</template>
</UContentNavigation>

View File

@@ -101,7 +101,7 @@ design_system:
@import "@nuxt/ui";
:root {
--ui-radius: var(--radius-sm);
--ui-radius: 0.25rem;
--ui-container: 90rem;
--ui-bg: var(--ui-color-neutral-50);
--ui-text: var(--ui-color-neutral-900);

View File

@@ -130,7 +130,7 @@ const communityLinks = computed(() => [{
</template>
<template #title>
{{ page.title }}<sup v-if="page.module === 'ui-pro'" class="ml-1 text-xs align-super font-medium text-(--ui-primary)">PRO</sup>
{{ page.title }}<sup v-if="page.module === 'ui-pro'" class="ml-1 text-xs align-super font-medium text-primary">PRO</sup>
</template>
<template #description>

View File

@@ -82,7 +82,7 @@ onMounted(() => {
:ui="{ title: 'text-balance', container: 'relative' }"
>
<template #top>
<div class="absolute z-[-1] rounded-full bg-(--ui-primary) blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
<div class="absolute z-[-1] rounded-full bg-primary blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
</template>
<template #headline>
@@ -97,7 +97,7 @@ onMounted(() => {
/>
</template>
<template #title>
Build beautiful UI with <span class="text-(--ui-primary)">{{ components!.length }}+</span> powerful components
Build beautiful UI with <span class="text-primary">{{ components!.length }}+</span> powerful components
</template>
<template #links>
@@ -121,22 +121,22 @@ onMounted(() => {
<LazyStarsBg />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
</UPageHero>
<div v-for="category in categories" :key="category.id">
<div data-track-sticky class="group mb-4 sm:mb-6 lg:mb-8 sticky top-[calc(var(--ui-header-height)-1px)] bg-(--ui-bg)/75 backdrop-blur z-[1]">
<div class="relative border-y border-(--ui-border) py-4 sm:not-group-[[data-stuck]]:py-6 lg:not-group-[[data-stuck]]:py-8 transition-all duration-300">
<div data-track-sticky class="group mb-4 sm:mb-6 lg:mb-8 sticky top-[calc(var(--ui-header-height)-1px)] bg-default/75 backdrop-blur z-[1]">
<div class="relative border-y border-default py-4 sm:not-group-[[data-stuck]]:py-6 lg:not-group-[[data-stuck]]:py-8 transition-all duration-300">
<UContainer>
<h2 class="relative text-pretty font-bold text-(--ui-text-highlighted) text-base sm:not-group-[[data-stuck]]:text-xl lg:not-group-[[data-stuck]]:text-2xl transition-all duration-300 ">
<h2 class="relative text-pretty font-bold text-highlighted text-base sm:not-group-[[data-stuck]]:text-xl lg:not-group-[[data-stuck]]:text-2xl transition-all duration-300 ">
<a :href="`#${category.id}`" class="group lg:not-group-[[data-stuck]]:ps-2 lg:not-group-[[data-stuck]]:-ms-2">
<span class="absolute -ms-8 top-1 opacity-0 group-hover:opacity-100 group-focus:opacity-100 p-1 bg-(--ui-bg-elevated) hover:text-(--ui-primary) rounded-[calc(var(--ui-radius)*1.5)] hidden lg:not-group-[[data-stuck]]:flex text-(--ui-text-muted) transition">
<span class="absolute -ms-8 top-1 opacity-0 group-hover:opacity-100 group-focus:opacity-100 p-1 bg-elevated hover:text-primary rounded-md hidden lg:not-group-[[data-stuck]]:flex text-muted transition">
<UIcon name="i-lucide-hash" class="size-4 shrink-0" />
</span>
{{ category.title }}
</a>
</h2>
<p class="text-pretty text-(--ui-text-muted) text-sm sm:not-group-[[data-stuck]]:text-base lg:not-group-[[data-stuck]]:text-lg mt-1 sm:not-group-[[data-stuck]]:mt-2 line-clamp-1 transition-all duration-300">
<p class="text-pretty text-muted text-sm sm:not-group-[[data-stuck]]:text-base lg:not-group-[[data-stuck]]:text-lg mt-1 sm:not-group-[[data-stuck]]:mt-2 line-clamp-1 transition-all duration-300">
{{ category.description }}
</p>
</UContainer>
@@ -157,11 +157,11 @@ onMounted(() => {
<template #title>
<div class="flex items-center gap-0.5">
<span>{{ component.title }}</span>
<sup v-if="component.module === 'ui-pro'" class="text-[8px] font-medium text-(--ui-primary)">PRO</sup>
<sup v-if="component.module === 'ui-pro'" class="text-[8px] font-medium text-primary">PRO</sup>
</div>
</template>
<div class="rounded-[calc(var(--ui-radius)*1.5)] border border-(--ui-border-muted) overflow-hidden aspect-[16/9]">
<div class="rounded-md border border-muted overflow-hidden aspect-[16/9]">
<UColorModeImage
:light="`${component.path.replace('/components/', '/components/light/')}.png`"
:dark="`${component.path.replace('/components/', '/components/dark/')}.png`"

View File

@@ -27,7 +27,7 @@ features1:
description: Start with essential components, or unlock Pro for complete blocks and templates.
icon: i-lucide-files
cta1:
title: Everything you need in a [single file]{class="text-(--ui-primary)"}.
title: Everything you need in a [single file]{class="text-primary"}.
description: Design and development in perfect sync with our [Free](https://www.figma.com/community/file/1288455405058138934/nuxt-ui-v3-official-design-kit-free) and Pro files. Developers can implement designs faster, while designers work with production-ready components.
section1:
title: Customize in a few clicks to fit your needs
@@ -181,7 +181,7 @@ pricing:
# discount: $119
billing_period: one-time payment
billing_cycle: plus local taxes
class: bg-(--ui-bg-elevated)/50
class: bg-elevated/50
features:
- '**1 Designer**'
- Nuxt UI & Nuxt UI Pro Components
@@ -203,7 +203,7 @@ pricing:
# discount: $279
billing_period: one-time payment
billing_cycle: plus local taxes
class: bg-(--ui-bg-elevated)/50
class: bg-elevated/50
features:
- '**Up to 20 Designers**'
- Nuxt UI & Nuxt UI Pro Components

View File

@@ -57,7 +57,7 @@ onMounted(async () => {
<template>
<div class="relative">
<div id="cursor1" class="absolute z-10 pointer-events-none" :style="{ opacity: 0 }">
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" class="absolute top-0 left-0 drop-shadow-[0_1px_2px_rgb(0,0,0,0.25)] text-white dark:text-(--ui-bg)">
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" class="absolute top-0 left-0 drop-shadow-[0_1px_2px_rgb(0,0,0,0.25)] text-inverted">
<path
fill="var(--ui-info)"
stroke="currentColor"
@@ -72,7 +72,7 @@ onMounted(async () => {
</UBadge>
</div>
<div id="cursor2" class="absolute z-10 pointer-events-none" :style="{ opacity: 0 }">
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" class="absolute top-0 left-0 drop-shadow-[0_1px_2px_rgb(0,0,0,0.25)] text-white dark:text-(--ui-bg)">
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" class="absolute top-0 left-0 drop-shadow-[0_1px_2px_rgb(0,0,0,0.25)] text-inverted">
<path
fill="var(--ui-success)"
stroke="currentColor"
@@ -99,7 +99,7 @@ onMounted(async () => {
<template #description>
<MDC :value="page.hero.description" unwrap="p" cache-key="figma-hero-description" />
</template>
<!-- <img src="/pro/figma/nuxt-ui-figma.png" alt="Screnshot of the Nuxt UI Figma design kit" class="w-full h-auto border border-(--ui-border) border-b-0"> -->
<!-- <img src="/pro/figma/nuxt-ui-figma.png" alt="Screnshot of the Nuxt UI Figma design kit" class="w-full h-auto border border-default border-b-0"> -->
<div class="relative">
<video
ref="video"
@@ -126,10 +126,10 @@ onMounted(async () => {
</div>
</div>
<Motion as-child :initial="{ height: 0 }" :animate="{ height: 'auto' }" :transition="{ delay: 0.2, duration: 1 }">
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
</Motion>
</UPageHero>
<UPageSection v-bind="page.features1" :ui="{ container: 'py-16 sm:py-16 lg:py-16', features: 'mt-0' }" class="border-y border-(--ui-border)" />
<UPageSection v-bind="page.features1" :ui="{ container: 'py-16 sm:py-16 lg:py-16', features: 'mt-0' }" class="border-y border-default" />
<UPageCTA
v-if="page.cta1"
variant="naked"
@@ -138,7 +138,7 @@ onMounted(async () => {
wrapper: 'grid grid-cols-1 lg:grid-cols-2',
description: 'lg:mt-0' }"
orientation="horizontal"
class="rounded-none bg-gradient-to-b from-(--ui-bg-muted) to-(--ui-bg)"
class="rounded-none bg-gradient-to-b from-elevated/50 to-default"
>
<template #title>
<MDC :value="page.cta1.title" unwrap="p" cache-key="figma-cta-1-title" />
@@ -155,7 +155,7 @@ onMounted(async () => {
:height="item.height"
:src="item.src"
:alt="item.alt"
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
class="w-full h-auto rounded-lg"
loading="lazy"
/>
</template>
@@ -165,7 +165,7 @@ onMounted(async () => {
<NuxtImg
v-if="page.section2.image"
v-bind="page.section2.image"
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
class="w-full h-auto rounded-lg"
loading="lazy"
/>
</UPageSection>
@@ -173,7 +173,7 @@ onMounted(async () => {
<NuxtImg
v-if="page.section3.image"
v-bind="page.section3.image"
class="w-full h-auto rounded-[calc(var(--ui-radius)*2)]"
class="w-full h-auto rounded-lg"
loading="lazy"
/>
</UPageSection>
@@ -192,27 +192,27 @@ onMounted(async () => {
<template #description>
<MDC :value="page.section4.description" unwrap="p" cache-key="figma-section-4-description" />
</template>
<div aria-hidden="true" class="absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 items-start justify-center border border-(--ui-border) border-b-0 sm:divide-x divide-y lg:divide-y-0 divide-(--ui-border)">
<div aria-hidden="true" class="absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 items-start justify-center border border-default border-b-0 sm:divide-x divide-y lg:divide-y-0 divide-default">
<li v-for="(step, index) in page?.section4.steps" :key="step.title" class="flex flex-col gap-y-4 justify-start group h-full p-4">
<NuxtImg
v-if="step.image"
v-bind="step.image"
class="rounded-(--ui-radius)"
class="rounded-sm"
loading="lazy"
/>
<div>
<h2 class="font-semibold inline-flex items-center gap-x-1">
<UBadge :label="index + 1" size="sm" color="neutral" variant="subtle" class="rounded-full tabular-nums" /> {{ step.title }}
</h2>
<p class="text-(--ui-text-muted) text-sm">
<p class="text-muted text-sm">
{{ step.description }}
</p>
</div>
</li>
</ul>
</UPageSection>
<UPageSection v-bind="page.features2" :ui="{ container: 'py-16 sm:py-16 lg:py-16', features: 'mt-0' }" class="border-y border-(--ui-border)" />
<UPageSection v-bind="page.features2" :ui="{ container: 'py-16 sm:py-16 lg:py-16', features: 'mt-0' }" class="border-y border-default" />
<UPageSection
v-if="page.pricing"
:title="page.pricing.title"
@@ -226,7 +226,7 @@ onMounted(async () => {
wrapper: 'sm:pl-8'
}"
>
<div aria-hidden="true" class="absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<UPricingPlans compact class="-space-x-px">
<UPricingPlan
v-for="(plan, index) in page.pricing.plans"
@@ -246,8 +246,8 @@ onMounted(async () => {
>
<template #features>
<li v-for="(feature, i) in plan.features" :key="i" class="flex items-center gap-2 min-w-0">
<UIcon name="i-lucide-circle-check" class="size-5 shrink-0 text-(--ui-primary)" />
<MDC :value="feature" unwrap="p" tag="span" class="text-sm truncate text-(--ui-text-accented)" :cache-key="`figma-pricing-plan-${index}-feature-${i}`" />
<UIcon name="i-lucide-circle-check" class="size-5 shrink-0 text-primary" />
<MDC :value="feature" unwrap="p" tag="span" class="text-sm truncate text-accented" :cache-key="`figma-pricing-plan-${index}-feature-${i}`" />
</li>
</template>
<template #button>
@@ -278,7 +278,7 @@ onMounted(async () => {
</UPageMarquee>
</UPageCTA>
<UPageSection v-bind="page.faq" :ui="{ container: 'relative' }">
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<UPageAccordion
multiple
:items="(page.faq.items as any[])"

View File

@@ -48,7 +48,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
}"
>
<template #title>
The Intuitive <br> <span class="text-(--ui-primary)">Vue UI Library</span>
The Intuitive <br> <span class="text-primary">Vue UI Library</span>
</template>
<template #description>
{{ page.hero.description }}
@@ -81,14 +81,14 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
pause-on-hover
:overlay="false"
:ui="{
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full left-0 border-y lg:border-x lg:border-y-0 lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:flex-col',
root: '[--gap:--spacing(4)] [--duration:40s] border-default absolute w-full left-0 border-y lg:border-x lg:border-y-0 lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:flex-col',
content: 'lg:w-auto lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content]'
}"
>
<ULink
v-for="component of components?.slice(0, 10)"
:key="component.path"
class="relative group/link aspect-video border-(--ui-border) w-[290px] xl:w-[330px] 2xl:w-[320px] 2xl:p-2 2xl:border-y"
class="relative group/link aspect-video border-default w-[290px] xl:w-[330px] 2xl:w-[320px] 2xl:p-2 2xl:border-y"
:to="component.path"
>
<UColorModeImage
@@ -98,7 +98,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
width="290"
height="163"
format="webp"
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-(--ui-border) 2xl:border-y-0"
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-default 2xl:border-y-0"
loading="lazy"
/>
<UBadge color="neutral" variant="outline" size="md" :label="component.title" class="hidden lg:block absolute mx-auto top-4 left-6 xl:left-4 group-hover/link:opacity-100 opacity-0 transition-all duration-300 pointer-events-none -translate-y-2 group-hover/link:translate-y-0" />
@@ -110,14 +110,14 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
reverse
:overlay="false"
:ui="{
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full mt-[180px] left-0 border-y lg:mt-auto lg:left-auto lg:border-y-0 lg:border-x lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:right-0 lg:flex-col',
root: '[--gap:--spacing(4)] [--duration:40s] border-default absolute w-full mt-[180px] left-0 border-y lg:mt-auto lg:left-auto lg:border-y-0 lg:border-x lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:right-0 lg:flex-col',
content: 'lg:w-auto lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content] lg:[animation-direction:reverse]'
}"
>
<ULink
v-for="component of components?.slice(10, 20)"
:key="component.path"
class="relative group/link aspect-video border-(--ui-border) w-[290px] xl:w-[330px] 2xl:w-[320px] 2xl:p-2 2xl:border-y"
class="relative group/link aspect-video border-default w-[290px] xl:w-[330px] 2xl:w-[320px] 2xl:p-2 2xl:border-y"
:to="component.path"
>
<UColorModeImage
@@ -127,7 +127,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
width="290"
height="163"
format="webp"
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-(--ui-border) 2xl:border-y-0"
class="hover:scale-105 lg:hover:scale-110 transition-transform aspect-video w-full border-x lg:border-x-0 lg:border-y border-default 2xl:border-y-0"
loading="lazy"
/>
<UBadge color="neutral" variant="outline" size="md" :label="component.title" class="hidden lg:block absolute mx-auto top-4 left-6 xl:left-4 group-hover/link:opacity-100 opacity-0 transition-all duration-300 pointer-events-none -translate-y-2 group-hover/link:translate-y-0" />
@@ -168,11 +168,11 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
<UIcon :name="feature.icon" class="size-5 shrink-0" />
</div>
<div class="flex flex-col">
<h2 class="font-medium text-(--ui-text-highlighted) inline-flex items-center gap-x-1">
<h2 class="font-medium text-highlighted inline-flex items-center gap-x-1">
{{ feature.title }}
<UIcon v-if="feature.to" name="i-lucide-arrow-right" class="size-4 shrink-0 opacity-0 group-hover:opacity-100 transition-all duration-200 -translate-x-1 group-hover:translate-x-0" />
</h2>
<p class="text-sm text-(--ui-text-muted)">
<p class="text-sm text-muted">
{{ feature.description }}
</p>
</div>
@@ -215,33 +215,33 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
:links="page.community.links"
orientation="horizontal"
:ui="{ features: 'flex items-center gap-4 lg:gap-8' }"
class="border-b border-(--ui-border)"
class="border-b border-default"
>
<template #features>
<li>
<NuxtLink to="https://npm.chart.dev/@nuxt/ui" target="_blank" class="min-w-0">
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
<p class="text-4xl font-semibold text-highlighted truncate">
{{ format(module?.stats?.downloads ?? 0) }}+
</p>
<p class="text-(--ui-text-muted) text-sm truncate">monthly downloads</p>
<p class="text-muted text-sm truncate">monthly downloads</p>
</NuxtLink>
</li>
<li>
<NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="min-w-0">
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
<p class="text-4xl font-semibold text-highlighted truncate">
{{ format(module?.stats?.stars ?? 0) }}+
</p>
<p class="text-(--ui-text-muted) text-sm truncate">GitHub stars</p>
<p class="text-muted text-sm truncate">GitHub stars</p>
</NuxtLink>
</li>
<li>
<NuxtLink to="https://github.com/nuxt/ui/graphs/contributors" target="_blank" class="min-w-0">
<p class="text-4xl font-semibold text-(--ui-text-highlighted) truncate">
<p class="text-4xl font-semibold text-highlighted truncate">
175+
</p>
<p class="text-(--ui-text-muted) text-sm truncate">Contributors</p>
<p class="text-muted text-sm truncate">Contributors</p>
</NuxtLink>
</li>
</template>
@@ -253,10 +253,10 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
<UPageSection :ui="{ container: 'relative !pb-0 overflow-hidden' }">
<template #title>
Build faster with Nuxt UI <span class="text-(--ui-primary)">Pro</span>.
Build faster with Nuxt UI <span class="text-primary">Pro</span>.
</template>
<template #description>
A collection of premium Vue components, composables and utils built on top of Nuxt UI. <br> Focused on structure and layout, these <span class="text-(--ui-text)">responsive components</span> are designed to be the perfect <span class="text-(--ui-text)">building blocks for your next idea</span>.
A collection of premium Vue components, composables and utils built on top of Nuxt UI. <br> Focused on structure and layout, these <span class="text-default">responsive components</span> are designed to be the perfect <span class="text-default">building blocks for your next idea</span>.
</template>
<template #links>
<UButton to="/pro" size="lg">
@@ -269,8 +269,8 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
<LazyStarsBg />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div class="relative h-[400px] border border-(--ui-border) bg-(--ui-bg-muted) overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div class="relative h-[400px] border border-default bg-muted overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">
<UPageMarquee reverse orientation="vertical" :overlay="false" :ui="{ root: '[--duration:40s] absolute w-[460px] -left-[100px] -top-[300px] h-[940px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
<img
v-for="i in 4"
@@ -280,7 +280,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
height="258"
loading="lazy"
:alt="`Nuxt UI Pro Screenshot ${i}`"
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
class="aspect-video border border-default rounded-lg bg-white"
>
</UPageMarquee>
<UPageMarquee orientation="vertical" :overlay="false" :ui="{ root: '[--duration:40s] absolute w-[460px] -top-[400px] left-[480px] h-[1160px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
@@ -292,7 +292,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
height="258"
loading="lazy"
:alt="`Nuxt UI Pro Screenshot ${i}`"
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
class="aspect-video border border-default rounded-lg bg-white"
>
</UPageMarquee>
<UPageMarquee reverse orientation="vertical" :overlay="false" :ui="{ root: 'hidden md:flex [--duration:40s] absolute w-[460px] -top-[300px] left-[1020px] h-[1060px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
@@ -304,7 +304,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
height="258"
loading="lazy"
:alt="`Nuxt UI Pro Screenshot ${i}`"
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
class="aspect-video border border-default rounded-lg bg-white"
>
</UPageMarquee>
</div>

View File

@@ -2,7 +2,7 @@ title: Nuxt UI Pro Pricing
description: Start for free in development mode, then upgrade to a paid plan to unlock the full features of Nuxt UI Pro when you are ready to launch.
pricing:
headline: Pricing
title: Upgrade to Nuxt UI [Pro]{class="text-(--ui-primary)"}.
title: Upgrade to Nuxt UI [Pro]{class="text-primary"}.
description: On top of 40+ open source components from Nuxt UI, Pro gives you access to 50+ premium Vue components to create beautiful & responsive Nuxt applications in minutes. It includes all primitives to build landing pages, documentations, blogs, dashboards or entire SaaS products.
freePlan:
title: Free in development

View File

@@ -1,8 +1,8 @@
title: Build faster with Nuxt UI Pro.
description: A collection of premium Vue components, composables and utils built on top of Nuxt UI, oriented on structure and layout and designed to be used as building blocks for your application.
hero:
title: Build faster with Nuxt UI [Pro]{class="text-(--ui-primary)"}.
description: A collection of premium Vue components, composables and utils built on top of Nuxt UI. :br Focused on structure and layout, these [responsive components]{class="text-(--ui-text)"} are designed to be the perfect [building blocks for your next idea]{class="text-(--ui-text)"}.
title: Build faster with Nuxt UI [Pro]{class="text-primary"}.
description: A collection of premium Vue components, composables and utils built on top of Nuxt UI. :br Focused on structure and layout, these [responsive components]{class="text-default"} are designed to be the perfect [building blocks for your next idea]{class="text-default"}.
links:
- label: Buy a license
size: xl
@@ -62,7 +62,7 @@ testimonial:
# avatar:
# src: https://github.com/benjamincanac.png
mainSection:
title: Meet the [Pro Components]{class="text-(--ui-primary)"}.
title: Meet the [Pro Components]{class="text-primary"}.
description: Code with 50+ components and sections of Nuxt UI Pro to build your next application by reducing the amount of code you need to write.
sections:
- title: The freedom to build anything

View File

@@ -1,7 +1,7 @@
title: Official Nuxt UI Pro Templates
description: 'Ready to use templates powered by our premium Vue components and Nuxt Content. The templates are responsive, accessible and easy to customize so you can get started in no time.'
hero:
title: Ship [in minutes]{.text-(--ui-primary)} with :br Nuxt UI Pro Templates
title: Ship [in minutes]{.text-primary} with :br Nuxt UI Pro Templates
description: 'Ready to use templates powered by our premium Vue components and Nuxt Content.<br class="hidden lg:block"> The templates are responsive, accessible and easy to customize so you can get started in no time.'
navigation: false
links:
@@ -16,8 +16,60 @@ links:
variant: outline
trailingIcon: i-lucide-arrow-right
templates:
- title: 'Portfolio'
description: "A sleek, modern portfolio template to showcase your work, skills, blog posts, speaking engagements, and provide contact information. Which can customized easily from the `content/` directory."
icon: i-lucide-user
thumbnail:
dark: https://assets.hub.nuxt.com/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL3BvcnRmb2xpby10ZW1wbGF0ZS5udXh0LmRldiIsImlhdCI6MTc0NTkzNDczMX0.XDWnQoyVy3XVtKQD6PLQ8RFUwr4yr1QnVwPxRrjCrro.jpg?theme=dark
light: https://assets.hub.nuxt.com/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL3BvcnRmb2xpby10ZW1wbGF0ZS5udXh0LmRldiIsImlhdCI6MTc0NTkzNDczMX0.XDWnQoyVy3XVtKQD6PLQ8RFUwr4yr1QnVwPxRrjCrro.jpg?theme=light
features:
- title: Sections for Projects, Blog, Speaking & About
icon: i-lucide-layout-list
- title: Easily editable content via Markdown & YAML
icon: i-simple-icons-markdown
- title: Fully responsive design
icon: i-lucide-smartphone
links:
- label: Preview
to: https://portfolio-template.nuxt.dev
target: _blank
leadingIcon: i-logos-nuxt-icon
trailingIcon: i-lucide-arrow-up-right
color: neutral
- label: Nuxt Template
to: https://github.com/nuxt-ui-pro/portfolio
target: _blank
icon: i-simple-icons-github
color: neutral
variant: outline
- title: 'Chat'
description: "An AI chatbot template designed to help you build your own chatbot with Nuxt UI Pro components and deployed on [NuxtHub](https://hub.nuxt.com)."
icon: i-lucide-message-circle
thumbnail:
dark: https://assets.hub.nuxt.com/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2NoYXQtdGVtcGxhdGUubnV4dC5kZXYiLCJpYXQiOjE3NDI4NDY2ODB9.n4YCsoNz8xatox7UMoYZFNo7iS1mC_DT0h0A9cKRoTw.jpg?theme=dark
light: https://assets.hub.nuxt.com/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2NoYXQtdGVtcGxhdGUubnV4dC5kZXYiLCJpYXQiOjE3NDI4NDY2ODB9.n4YCsoNz8xatox7UMoYZFNo7iS1mC_DT0h0A9cKRoTw.jpg?theme=light
features:
- title: Powered by Cloudflare AI models
icon: i-simple-icons-cloudflare
- title: GitHub OAuth authentication
icon: i-lucide-lock
- title: Saved chats and messages
icon: i-lucide-database
links:
- label: Preview
to: https://chat-template.nuxt.dev
target: _blank
leadingIcon: i-logos-nuxt-icon
trailingIcon: i-lucide-arrow-up-right
color: neutral
- label: Nuxt Template
to: https://github.com/nuxt-ui-pro/chat
target: _blank
icon: i-simple-icons-github
color: neutral
variant: outline
- title: 'Dashboard'
description: "A template to illustrate how to build your own dashboard with the 15+ latest Nuxt UI Pro components, designed specifically to create a consistent look and feel."
description: "A template to illustrate how to build your own dashboard with 15+ Nuxt UI Pro components, designed specifically to create a consistent look and feel."
icon: i-lucide-bar-chart-big
thumbnail:
dark: https://assets.hub.nuxt.com/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2Rhc2hib2FyZC10ZW1wbGF0ZS5udXh0LmRldiIsImlhdCI6MTczOTQ2MzU2N30._VElt4uvLjvAMdnTLytCInOajMElzWDKbmvOaMZhZUI.jpg?theme=dark

View File

@@ -73,9 +73,9 @@ onMounted(() => {
<UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative overflow-hidden', wrapper: 'lg:px-12', description: 'text-pretty' }">
<LazyStarsBg />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div class="px-4 py-10 lg:border border-(--ui-border) bg-(--ui-bg)">
<div class="px-4 py-10 lg:border border-default bg-default">
<div class="max-w-xl mx-auto">
<UForm
:schema="schema"

View File

@@ -35,9 +35,9 @@ useSeoMeta({
<LazyStarsBg />
<Motion as-child :initial="{ height: 0 }" :animate="{ height: 'auto' }" :transition="{ delay: 0.2, duration: 1 }">
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
</Motion>
<div class="relative h-[400px] border border-(--ui-border) bg-(--ui-bg-muted) overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">
<div class="relative h-[400px] border border-default bg-muted overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">
<UPageMarquee reverse orientation="vertical" :overlay="false" :ui="{ root: '[--duration:40s] absolute w-[460px] -left-[100px] -top-[300px] h-[940px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
<img
v-for="i in 4"
@@ -46,7 +46,7 @@ useSeoMeta({
width="460"
height="258"
:alt="`Nuxt UI Pro Screenshot ${i}`"
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
class="aspect-video border border-default rounded-lg bg-white"
>
</UPageMarquee>
<UPageMarquee orientation="vertical" :overlay="false" :ui="{ root: '[--duration:40s] absolute w-[460px] -top-[400px] left-[480px] h-[1160px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
@@ -57,7 +57,7 @@ useSeoMeta({
width="460"
height="258"
:alt="`Nuxt UI Pro Screenshot ${i}`"
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
class="aspect-video border border-default rounded-lg bg-white"
>
</UPageMarquee>
<UPageMarquee reverse orientation="vertical" :overlay="false" :ui="{ root: 'hidden md:flex [--duration:40s] absolute w-[460px] -top-[300px] left-[1020px] h-[1060px] transform-3d rotate-x-55 rotate-y-0 rotate-z-30' }">
@@ -68,7 +68,7 @@ useSeoMeta({
width="460"
height="258"
:alt="`Nuxt UI Pro Screenshot ${i}`"
class="aspect-video border border-(--ui-border) rounded-[calc(var(--ui-radius)*2)] bg-white"
class="aspect-video border border-default rounded-lg bg-white"
>
</UPageMarquee>
</div>
@@ -101,10 +101,10 @@ useSeoMeta({
container: 'relative',
wrapper: 'sm:px-8'
}"
class="border-t border-(--ui-border)"
class="border-t border-default"
>
<Motion as-child :initial="{ height: 0 }" :while-in-view="{ height: 'auto' }" :transition="{ delay: 0.4, duration: 1 }">
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
</Motion>
</UPageSection>
@@ -116,7 +116,7 @@ useSeoMeta({
wrapper: 'grid grid-cols-1 lg:grid-cols-2',
description: 'lg:mt-0' }"
orientation="horizontal"
class="rounded-none border-t border-(--ui-border) bg-gradient-to-b from-(--ui-bg-elevated)/50 to-(--ui-bg)"
class="rounded-none border-t border-default bg-gradient-to-b from-elevated/50 to-default"
>
<template #title>
<MDC :value="page.mainSection.title" tag="span" unwrap="p" cache-key="pro-main-section-title" />
@@ -134,7 +134,7 @@ useSeoMeta({
:reverse="section.reverse"
:features="section.features"
orientation="horizontal"
:class="{ 'border-b border-(--ui-border)': index === page.sections.length - 1 }"
:class="{ 'border-b border-default': index === page.sections.length - 1 }"
:ui="{
container: index === 0 ? 'pb-0 sm:pb-0 lg:pb-0 py-16 sm:py-16 lg:py-16' : ''
}"
@@ -145,10 +145,10 @@ useSeoMeta({
<UPageSection
id="templates"
v-bind="page.templates"
class="overflow-hidden border-x border-(--ui-border)"
class="overflow-hidden border-x border-default"
:ui="{ container: 'relative' }"
>
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<UCarousel
v-slot="{ item }"
loop
@@ -160,7 +160,7 @@ useSeoMeta({
:ui="{
item: 'basis-1/2',
container: 'py-2',
viewport: 'border-x border-(--ui-border)',
viewport: 'border-x border-default',
arrows: 'hidden 2xl:block'
}"
>
@@ -181,7 +181,7 @@ useSeoMeta({
:light="item.thumbnail.light"
:dark="item.thumbnail.dark"
:alt="item.title"
class="rounded-lg w-full border border-(--ui-border) aspect-video"
class="rounded-lg w-full border border-default aspect-video"
loading="lazy"
/>
</UPageCard>
@@ -199,7 +199,7 @@ useSeoMeta({
<LazyStarsBg />
<video
class="rounded-[var(--ui-radius)] z-10"
class="rounded-sm z-10"
preload="none"
poster="https://res.cloudinary.com/nuxt/video/upload/so_3.3/v1708511800/ui-pro/video-nuxt-ui-pro_kwfbdh.jpg"
:controls="true"

View File

@@ -29,13 +29,13 @@ useSeoMeta({
<LazyStarsBg />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div class="flex flex-col bg-(--ui-bg) gap-8 lg:gap-0">
<div class="flex flex-col bg-default gap-8 lg:gap-0">
<UPricingPlan
v-bind="page.pricing.freePlan"
variant="naked"
class="lg:rounded-none border-x border-(--ui-border) border-t border-b lg:border-b-0"
class="lg:rounded-none border-x border-default border-t border-b lg:border-b-0"
/>
<UPricingPlans compact>
<UPricingPlan
@@ -48,7 +48,7 @@ useSeoMeta({
:billing-period="plan.billing_period"
:billing-cycle="plan.billing_cycle"
:variant="plan.highlight ? 'soft' : 'outline'"
:class="['lg:rounded-none', { 'border-2 lg:border lg:border-x-0 border-(--ui-primary) lg:border-(--ui-border)': plan.highlight }]"
:class="['lg:rounded-none', { 'border-2 lg:border lg:border-x-0 border-primary lg:border-default': plan.highlight }]"
:features="plan.features"
:button="plan.button"
/>
@@ -58,12 +58,12 @@ useSeoMeta({
variant="naked"
:billing-period="page.pricing.figma.billing_period"
:billing-cycle="page.pricing.figma.billing_cycle"
class="lg:rounded-none border lg:border-y-0 border-(--ui-border)"
class="lg:rounded-none border lg:border-y-0 border-default"
>
<template #features>
<li v-for="(feature, index) in page.pricing.figma.features" :key="index" class="flex items-center gap-2 min-w-0">
<UIcon name="i-lucide-circle-check" class="size-5 text-(--ui-primary) shrink-0" />
<MDC :value="feature" unwrap="p" class="text-sm truncate text-(--ui-text-toned)" :cache-key="`pro-pricing-figma-feature-${index}`" />
<UIcon name="i-lucide-circle-check" class="size-5 text-primary shrink-0" />
<MDC :value="feature" unwrap="p" class="text-sm truncate text-toned" :cache-key="`pro-pricing-figma-feature-${index}`" />
</li>
</template>
</UPricingPlan>
@@ -73,7 +73,7 @@ useSeoMeta({
<UPageSection
id="testimonials"
v-bind="page.testimonials"
class="border-y border-(--ui-border)"
class="border-y border-default"
>
<UPageMarquee pause-on-hover :ui="{ root: '[--duration:40s]' }">
<img
@@ -110,7 +110,7 @@ useSeoMeta({
class="scroll-mt-(--ui-header-height)"
:ui="{ container: 'relative' }"
>
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<UPageAccordion
multiple
:items="(page.faq.items as any[])"

View File

@@ -20,7 +20,7 @@ useSeoMeta({
<UPageHero :links="page.links" :ui="{ container: 'relative' }">
<LazyStarsBg />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<template #title>
<MDC :value="page.hero.title" unwrap="p" cache-key="pro-templates-hero-title" />
@@ -38,10 +38,10 @@ useSeoMeta({
:links="template.links"
:features="template.features"
orientation="horizontal"
class="lg:border-t border-(--ui-border)"
class="lg:border-t border-default"
:ui="{
title: 'lg:text-4xl',
wrapper: 'lg:py-16 lg:border-r border-(--ui-border) order-last lg:pr-16',
wrapper: 'lg:py-16 lg:border-r border-default order-last lg:pr-16',
container: 'lg:py-0',
links: 'gap-x-3'
}"
@@ -50,12 +50,12 @@ useSeoMeta({
<MDC :value="template.description" unwrap="p" :cache-key="`pro-templates-${index}-description`" />
</template>
<div class="lg:border-x border-(--ui-border) h-full flex items-center lg:bg-(--ui-bg-muted)/20">
<div class="lg:border-x border-default h-full flex items-center lg:bg-muted/20">
<Motion class="flex-1" :initial="{ opacity: 0, transform: 'translateY(10px)' }" :while-in-view="{ opacity: 1, transform: 'translateY(0px)' }" :in-view-options="{ once: true }" :transition="{ duration: 0.5, delay: 0.2 }">
<UColorModeImage
v-if="template.thumbnail"
v-bind="template.thumbnail"
class="w-full h-auto border lg:border-y lg:border-x-0 border-(--ui-border) rounded-(--ui-radius) lg:rounded-none"
class="w-full h-auto border lg:border-y lg:border-x-0 border-default rounded-sm lg:rounded-none"
:alt="`Template ${index} thumbnail`"
width="656"
height="369"

View File

@@ -29,19 +29,19 @@ defineOgImageComponent('Docs', {
}"
>
<template #top>
<div class="absolute z-[-1] rounded-full bg-(--ui-primary) blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
<div class="absolute z-[-1] rounded-full bg-primary blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
</template>
<LazyStarsBg />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-default inset-0 mx-4 sm:mx-6 lg:mx-8" />
<div class="border-l border-t border-(--ui-border)">
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 items-start justify-center divide-y divide-x divide-(--ui-border)">
<div class="border-l border-t border-default">
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 items-start justify-center divide-y divide-x divide-default">
<li
v-for="item in page.items"
:key="item.name"
class="group relative flex items-center justify-center flex-1 size-full p-2 last:border-r last:border-b border-(--ui-border) overflow-hidden"
class="group relative flex items-center justify-center flex-1 size-full p-2 last:border-r last:border-b border-default overflow-hidden"
>
<NuxtLink class="inset-0 absolute" :to="item.url" target="_blank">
<span class="sr-only">Go to {{ item.name }}</span>

View File

@@ -41,14 +41,14 @@ const icons = {
:ui="{ title: 'text-balance', container: 'relative' }"
>
<template #top>
<div class="absolute z-[-1] rounded-full bg-(--ui-primary) blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
<div class="absolute z-[-1] rounded-full bg-primary blur-[300px] size-60 sm:size-80 transform -translate-x-1/2 left-1/2 -translate-y-80" />
</template>
<LazyStarsBg />
</UPageHero>
<UPageSection :ui="{ container: '!pt-0' }">
<UPageGrid class="xl:grid-cols-4">
<UPageGrid class="xl:grid-cols-5">
<UPageCard
v-for="(user, index) in module?.team"
:key="index"
@@ -58,7 +58,7 @@ const icons = {
container: 'gap-y-4 lg:p-8',
leading: 'flex justify-center',
title: 'text-center',
description: 'text-center text-(--ui-text-muted)'
description: 'text-center text-muted'
}"
variant="subtle"
>
@@ -126,7 +126,7 @@ const icons = {
container: 'gap-y-2',
leading: 'flex justify-center',
title: 'text-center',
description: 'text-center text-(--ui-text-muted)'
description: 'text-center text-muted'
}"
>
<template #leading>

View File

@@ -4,7 +4,7 @@ description: 'Nuxt UI harnesses the combined strengths of Reka UI, Tailwind CSS,
navigation.icon: i-lucide-house
---
<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;" class="rounded-[calc(var(--ui-radius)*1.5)]"></iframe>
<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;" class="rounded-md"></iframe>
## Reka UI

View File

@@ -76,16 +76,18 @@ export default defineNuxtConfig({
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 [.vscode/settings.json]
"files.associations": {
"*.css": "tailwindcss"
},
"editor.quickSuggestions": {
"strings": "on"
},
"tailwindCSS.classAttributes": ["class", "ui"],
"tailwindCSS.experimental.classRegex": [
["ui:\\s*{([^)]*)\\s*}", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
{
"files.associations": {
"*.css": "tailwindcss"
},
"editor.quickSuggestions": {
"strings": "on"
},
"tailwindCSS.classAttributes": ["class", "ui"],
"tailwindCSS.experimental.classRegex": [
["ui:\\s*{([^)]*)\\s*}", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
}
```
::

View File

@@ -99,6 +99,10 @@ app.use(ui)
app.mount('#app')
```
::note{to="#inertia"}
If you're using [Inertia.js](https://inertiajs.com/), you can skip the `vue-router` setup as Inertia provides its own routing system.
::
#### Import Tailwind CSS and Nuxt UI in your CSS
```css [assets/main.css]
@@ -136,16 +140,18 @@ app.mount('#app')
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 [.vscode/settings.json]
"files.associations": {
"*.css": "tailwindcss"
},
"editor.quickSuggestions": {
"strings": "on"
},
"tailwindCSS.classAttributes": ["class", "ui"],
"tailwindCSS.experimental.classRegex": [
["ui:\\s*{([^)]*)\\s*}", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
{
"files.associations": {
"*.css": "tailwindcss"
},
"editor.quickSuggestions": {
"strings": "on"
},
"tailwindCSS.classAttributes": ["class", "ui"],
"tailwindCSS.experimental.classRegex": [
["ui:\\s*{([^)]*)\\s*}", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
}
```
::
@@ -311,6 +317,29 @@ export default defineConfig({
This option adds the `transition-colors` class on components with hover or active states.
::
### `inertia`
Use the `inertia` option to enable compatibility with [Inertia.js](https://inertiajs.com/).
```ts [vite.config.ts]
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
inertia: true
})
]
})
```
::note
When using this option, `vue-router` is not required as Inertia.js provides its own routing system. The components that would normally use `RouterLink` will automatically use Inertia's `InertiaLink` component instead.
::
## Continuous Releases
Nuxt UI uses [pkg.pr.new](https://github.com/stackblitz-labs/pkg.pr.new) for continuous preview releases, providing developers with instant access to the latest features and bug fixes without waiting for official releases.

View File

@@ -195,23 +195,14 @@ You can also use the new [design tokens](/getting-started/theme#neutral-palette)
```diff
<template>
- <p class="text-gray-500 dark:text-gray-400" />
+ <p class="text-(--ui-text-muted)" />
+ <p class="text-muted" />
- <p class="text-gray-900 dark:text-white" />
+ <p class="text-(--ui-text-highlighted)" />
+ <p class="text-highlighted" />
</template>
```
::
- The `DEFAULT` shade that let you write `text-primary` no longer exists, you can use [color shades](/getting-started/theme#color-shades) instead:
```diff
<template>
- <p class="text-primary">Hello</p>
+ <p class="text-(--ui-primary)">Hello</p>
</template>
```
- The `gray`, `black` and `white` in the `color` props have been removed in favor of `neutral`:
```diff
@@ -513,7 +504,7 @@ const count = ref(0)
</script>
```
Closing a modal is now done through the `close` event. The `modal.open` method now returns a promise that resolves to the result of the modal whenever the modal is close:
Closing a modal is now done through the `close` event. The `modal.open` method now returns an instance that can be used to await for the result of the modal whenever the modal is closed:
```diff
<script setup lang="ts">
@@ -532,10 +523,12 @@ import { ModalExampleComponent } from '#components'
- })
- }
+ async function openModal() {
+ const result = await modal.open(ModalExampleComponent, {
+ const instance = modal.open(ModalExampleComponent, {
+ count: count.value
+ })
+
+ const result = await instance.result
+
+ if (result) {
+ toast.add({ title: 'Success!' })
+ }

View File

@@ -118,17 +118,7 @@ Learn more about automatic content detection in the detecting classes in source
## Design system
Nuxt UI extends Tailwind CSS's theming capabilities, providing a flexible design system with pre-configured color aliases and CSS variables. This allows for easy customization and quick adaptation of the UI to your brand's aesthetic.
### Colors
::framework-only
#nuxt
Nuxt UI leverages Nuxt [App Config](https://nuxt.com/docs/guide/directory-structure/app-config#app-config-file) to provide customizable color aliases based on [Tailwind CSS colors](https://tailwindcss.com/docs/customizing-colors#color-palette-reference):
#vue
Nuxt UI leverages Vite config to provide customizable color aliases based on [Tailwind CSS colors](https://tailwindcss.com/docs/customizing-colors#color-palette-reference):
::
Nuxt UI extends Tailwind CSS's theming capabilities, providing a flexible design system with pre-configured color aliases based on [Tailwind CSS colors](https://tailwindcss.com/docs/customizing-colors#color-palette-reference). This allows for easy customization and quick adaptation of the UI to your brand's aesthetic.
| Color | Default | Description |
| --- | --- | --- |
@@ -140,10 +130,27 @@ Nuxt UI leverages Vite config to provide customizable color aliases based on [Ta
| `error`{color="error"} | `red` | Used for form error validation states. |
| `neutral` | `slate` | Neutral color for backgrounds, text, etc. |
These colors are used to style the components but also to generate the `color` props:
::component-code{slug="button"}
---
props:
color: primary
slots:
default: Button
---
::
::note
Try the :prose-icon{name="i-lucide-swatch-book" class="text-primary"} theme picker in the header above to change `primary` and `neutral` colors.
::
### Configuration
::framework-only
#nuxt
:::div
You can configure these color aliases at runtime in your `app.config.ts` file under the `ui.colors` key, allowing for dynamic theme customization without requiring an application rebuild:
You can configure these color aliases at runtime in your [`app.config.ts`](https://nuxt.com/docs/guide/directory-structure/app-config#app-config-file) file under the `ui.colors` key, allowing for dynamic theme customization without requiring an application rebuild:
```ts [app.config.ts]
export default defineAppConfig({
@@ -222,27 +229,14 @@ export default defineConfig({
::
::note
Try the :prose-icon{name="i-lucide-swatch-book" class="text-(--ui-primary)"} theme picker in the header above to change `primary` and `neutral` colors.
::
These colors are used to style the components but also to generate the `color` variants:
::component-code{slug="button"}
---
props:
color: primary
slots:
default: Button
---
::
### Extend colors
::framework-only
#nuxt
:::tip
You can add you own dynamic color aliases in your `app.config.ts`, you just have to make sure to define them in the [`ui.theme.colors`](/getting-started/installation/nuxt#themecolors) option in your `nuxt.config.ts` file.
:::div
You can add you own dynamic color aliases in your `app.config.ts`, you just have to make sure to define them in the [`ui.theme.colors`](/getting-started/installation/nuxt#themecolors) option in your `nuxt.config.ts` file:
```ts [app.config.ts]
```ts [app.config.ts]{4}
export default defineAppConfig({
ui: {
colors: {
@@ -252,11 +246,19 @@ export default defineAppConfig({
})
```
```ts [nuxt.config.ts]
```ts [nuxt.config.ts]{7}
export default defineNuxtConfig({
ui: {
theme: {
colors: ['primary', 'secondary', 'tertiary', 'info', 'success', 'warning', 'error']
colors: [
'primary',
'secondary',
'tertiary',
'info',
'success',
'warning',
'error'
]
}
}
})
@@ -266,9 +268,9 @@ export default defineNuxtConfig({
#vue
:::tip
:::div
You can add you own dynamic color aliases in your `vite.config.ts`, you just have to make sure to also define them in the [`theme.colors`](/getting-started/installation/vue#themecolors) option of the `ui` plugin.
You can add you own dynamic color aliases in your `vite.config.ts`, you just have to make sure to also define them in the [`theme.colors`](/getting-started/installation/vue#themecolors) option of the `ui` plugin:
::::module-only
@@ -276,7 +278,7 @@ You can add you own dynamic color aliases in your `vite.config.ts`, you just hav
:::::div
```ts [vite.config.ts]
```ts [vite.config.ts]{11,18}
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
@@ -291,7 +293,15 @@ export default defineConfig({
}
},
theme: {
colors: ['primary', 'secondary', 'tertiary', 'info', 'success', 'warning', 'error']
colors: [
'primary',
'secondary',
'tertiary',
'info',
'success',
'warning',
'error'
]
}
})
]
@@ -304,7 +314,7 @@ export default defineConfig({
:::::div
```ts [vite.config.ts]
```ts [vite.config.ts]{11,18}
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'
@@ -316,10 +326,18 @@ export default defineConfig({
ui: {
colors: {
tertiary: 'indigo'
},
}
},
theme: {
colors: ['primary', 'secondary', 'tertiary', 'info', 'success', 'warning', 'error']
colors: [
'primary',
'secondary',
'tertiary',
'info',
'success',
'warning',
'error'
]
}
})
]
@@ -334,13 +352,13 @@ export default defineConfig({
::
### Tokens
## CSS Variables
Nuxt UI leverages a robust system of CSS variables as design tokens to ensure consistent and flexible component styling. These tokens form the foundation of the theming system, offering smooth support for both light and dark modes.
#### Color Shades
### Colors
Nuxt UI automatically creates a CSS variable for each color alias you define which represent the default shade used in both light and dark modes:
Nuxt UI provides a CSS variable for each color alias you define which represent the default shade used in both light and dark modes:
::code-group
@@ -368,12 +386,125 @@ Nuxt UI automatically creates a CSS variable for each color alias you define whi
::
::note
You can use these variables in classes like `text-(--ui-primary)`, it will automatically adapt to the current color scheme.
These CSS variables are defined in Tailwind CSS's `@theme` so you can use them as classes:
::code-preview
[Primary]{class="text-primary text-sm px-4"}
[Secondary]{class="text-secondary text-sm px-4"}
[Success]{class="text-success text-sm px-4"}
[Info]{class="text-info text-sm px-4"}
[Warning]{class="text-warning text-sm px-4"}
[Error]{class="text-error text-sm px-4"}
#code
```vue
<template>
<span class="text-primary">Primary</span>
<span class="text-secondary">Secondary</span>
<span class="text-success">Success</span>
<span class="text-info">Info</span>
<span class="text-warning">Warning</span>
<span class="text-error">Error</span>
</template>
```
::
::tip
You can change which shade is used for each color on light and dark mode:
::note
This is how the `@theme` is generated for each color alias:
:::code-collapse{class="[&>div]:!my-0"}
```scss
@theme default {
--color-primary: var(--ui-primary);
--color-primary-50: var(--ui-color-primary-50);
--color-primary-100: var(--ui-color-primary-100);
--color-primary-200: var(--ui-color-primary-200);
--color-primary-300: var(--ui-color-primary-300);
--color-primary-400: var(--ui-color-primary-400);
--color-primary-500: var(--ui-color-primary-500);
--color-primary-600: var(--ui-color-primary-600);
--color-primary-700: var(--ui-color-primary-700);
--color-primary-800: var(--ui-color-primary-800);
--color-primary-900: var(--ui-color-primary-900);
--color-primary-950: var(--ui-color-primary-950);
--color-secondary: var(--ui-secondary);
--color-secondary-50: var(--ui-color-secondary-50);
--color-secondary-100: var(--ui-color-secondary-100);
--color-secondary-200: var(--ui-color-secondary-200);
--color-secondary-300: var(--ui-color-secondary-300);
--color-secondary-400: var(--ui-color-secondary-400);
--color-secondary-500: var(--ui-color-secondary-500);
--color-secondary-600: var(--ui-color-secondary-600);
--color-secondary-700: var(--ui-color-secondary-700);
--color-secondary-800: var(--ui-color-secondary-800);
--color-secondary-900: var(--ui-color-secondary-900);
--color-secondary-950: var(--ui-color-secondary-950);
--color-success: var(--ui-success);
--color-success-50: var(--ui-color-success-50);
--color-success-100: var(--ui-color-success-100);
--color-success-200: var(--ui-color-success-200);
--color-success-300: var(--ui-color-success-300);
--color-success-400: var(--ui-color-success-400);
--color-success-500: var(--ui-color-success-500);
--color-success-600: var(--ui-color-success-600);
--color-success-700: var(--ui-color-success-700);
--color-success-800: var(--ui-color-success-800);
--color-success-900: var(--ui-color-success-900);
--color-success-950: var(--ui-color-success-950);
--color-info: var(--ui-info);
--color-info-50: var(--ui-color-info-50);
--color-info-100: var(--ui-color-info-100);
--color-info-200: var(--ui-color-info-200);
--color-info-300: var(--ui-color-info-300);
--color-info-400: var(--ui-color-info-400);
--color-info-500: var(--ui-color-info-500);
--color-info-600: var(--ui-color-info-600);
--color-info-700: var(--ui-color-info-700);
--color-info-800: var(--ui-color-info-800);
--color-info-900: var(--ui-color-info-900);
--color-info-950: var(--ui-color-info-950);
--color-warning: var(--ui-warning);
--color-warning-50: var(--ui-color-warning-50);
--color-warning-100: var(--ui-color-warning-100);
--color-warning-200: var(--ui-color-warning-200);
--color-warning-300: var(--ui-color-warning-300);
--color-warning-400: var(--ui-color-warning-400);
--color-warning-500: var(--ui-color-warning-500);
--color-warning-600: var(--ui-color-warning-600);
--color-warning-700: var(--ui-color-warning-700);
--color-warning-800: var(--ui-color-warning-800);
--color-warning-900: var(--ui-color-warning-900);
--color-warning-950: var(--ui-color-warning-950);
--color-error: var(--ui-error);
--color-error-50: var(--ui-color-error-50);
--color-error-100: var(--ui-color-error-100);
--color-error-200: var(--ui-color-error-200);
--color-error-300: var(--ui-color-error-300);
--color-error-400: var(--ui-color-error-400);
--color-error-500: var(--ui-color-error-500);
--color-error-600: var(--ui-color-error-600);
--color-error-700: var(--ui-color-error-700);
--color-error-800: var(--ui-color-error-800);
--color-error-900: var(--ui-color-error-900);
--color-error-950: var(--ui-color-error-950);
--color-neutral-50: var(--ui-color-neutral-50);
--color-neutral-100: var(--ui-color-neutral-100);
--color-neutral-200: var(--ui-color-neutral-200);
--color-neutral-300: var(--ui-color-neutral-300);
--color-neutral-400: var(--ui-color-neutral-400);
--color-neutral-500: var(--ui-color-neutral-500);
--color-neutral-600: var(--ui-color-neutral-600);
--color-neutral-700: var(--ui-color-neutral-700);
--color-neutral-800: var(--ui-color-neutral-800);
--color-neutral-900: var(--ui-color-neutral-900);
--color-neutral-950: var(--ui-color-neutral-950);
}
```
:::
::
You can change which shade is used for each color on light and dark mode in your `main.css` file:
::module-only
#ui
@@ -413,10 +544,6 @@ You can change which shade is used for each color on light and dark mode:
:::
::
::
#### Black as Primary Color
::framework-only
#nuxt
:::p
@@ -467,7 +594,7 @@ You cannot set `primary: 'black'`{lang="ts-type"} in your [`vite.config.ts`](#co
:::
::
#### Neutral Palette
### Neutral
Nuxt UI provides a comprehensive set of design tokens for the `neutral` color palette, ensuring consistent and accessible UI styling across both light and dark modes. These tokens offer fine-grained control over text, background, and border colors:
@@ -475,150 +602,269 @@ Nuxt UI provides a comprehensive set of design tokens for the `neutral` color pa
```css [Light]
:root {
/* Least prominent text */
--ui-text-dimmed: var(--ui-color-neutral-400);
/* Slightly muted text */
--ui-text-muted: var(--ui-color-neutral-500);
/* Moderately prominent text */
--ui-text-toned: var(--ui-color-neutral-600);
/* Default text color */
--ui-text: var(--ui-color-neutral-700);
/* Most prominent text */
--ui-text-highlighted: var(--ui-color-neutral-900);
--ui-text-inverted: var(--color-white);
/* Main background color */
--ui-bg: var(--color-white);
/* Subtle background */
--ui-bg-muted: var(--ui-color-neutral-50);
/* Slightly elevated background */
--ui-bg-elevated: var(--ui-color-neutral-100);
/* More prominent background */
--ui-bg-accented: var(--ui-color-neutral-200);
/* Inverted background color */
--ui-bg-inverted: var(--ui-color-neutral-900);
/* Default border color */
--ui-border: var(--ui-color-neutral-200);
/* Subtle border */
--ui-border-muted: var(--ui-color-neutral-200);
/* More prominent border */
--ui-border-accented: var(--ui-color-neutral-300);
/* Inverted border color */
--ui-border-inverted: var(--ui-color-neutral-900);
}
```
```css [Dark]
.dark {
/* Least prominent text */
--ui-text-dimmed: var(--ui-color-neutral-500);
/* Slightly muted text */
--ui-text-muted: var(--ui-color-neutral-400);
/* Moderately prominent text */
--ui-text-toned: var(--ui-color-neutral-300);
/* Default text color */
--ui-text: var(--ui-color-neutral-200);
/* Most prominent text */
--ui-text-highlighted: var(--color-white);
--ui-text-inverted: var(--ui-color-neutral-900);
/* Main background color */
--ui-bg: var(--ui-color-neutral-900);
/* Subtle background */
--ui-bg-muted: var(--ui-color-neutral-800);
/* Slightly elevated background */
--ui-bg-elevated: var(--ui-color-neutral-800);
/* More prominent background */
--ui-bg-accented: var(--ui-color-neutral-700);
/* Inverted background color */
--ui-bg-inverted: var(--color-white);
/* Default border color */
--ui-border: var(--ui-color-neutral-800);
/* Subtle border */
--ui-border-muted: var(--ui-color-neutral-700);
/* More prominent border */
--ui-border-accented: var(--ui-color-neutral-700);
/* Inverted border color */
--ui-border-inverted: var(--color-white);
}
```
::
These CSS variables are defined in Tailwind CSS's `@theme` so you can use them as classes:
::code-preview
[Dimmed]{class="text-dimmed text-sm px-4 py-1.5 inline-block rounded-md"}
[Muted]{class="text-muted text-sm px-4 py-1.5 inline-block rounded-md"}
[Toned]{class="text-toned text-sm px-4 py-1.5 inline-block rounded-md"}
[Text]{class="text-default text-sm px-4 py-1.5 inline-block rounded-md"}
[Highlighted]{class="text-highlighted text-sm px-4 py-1.5 inline-block rounded-md"}
[Inverted]{class="text-inverted bg-inverted text-sm px-4 py-1.5 inline-block rounded-md"}
#code
```vue
<template>
<span class="text-dimmed">Dimmed</span>
<span class="text-muted">Muted</span>
<span class="text-toned">Toned</span>
<span class="text-default">Text</span>
<span class="text-highlighted">Highlighted</span>
<span class="text-inverted bg-inverted">Inverted</span>
</template>
```
::
::code-preview
[Default]{class="bg-default text-sm px-4 py-1.5 inline-block rounded-md mr-2"}
[Muted]{class="bg-muted text-sm px-4 py-1.5 inline-block rounded-md mr-2"}
[Elevated]{class="bg-elevated text-sm px-4 py-1.5 inline-block rounded-md mr-2"}
[Accented]{class="bg-accented text-sm px-4 py-1.5 inline-block rounded-md mr-2"}
[Inverted]{class="bg-inverted text-inverted text-sm px-4 py-1.5 inline-block rounded-md"}
#code
```vue
<template>
<div class="bg-default">Default</div>
<div class="bg-muted">Muted</div>
<div class="bg-elevated">Elevated</div>
<div class="bg-accented">Accented</div>
<div class="bg-inverted text-inverted">Inverted</div>
</template>
```
::
::code-preview
[Default]{class="border-2 border-default text-sm px-4 py-1.5 inline-block rounded-md mr-2"}
[Muted]{class="border-2 border-muted text-sm px-4 py-1.5 inline-block rounded-md mr-2"}
[Accented]{class="border-2 border-accented text-sm px-4 py-1.5 inline-block rounded-md mr-2"}
[Inverted]{class="border-2 border-inverted text-sm px-4 py-1.5 inline-block rounded-md"}
#code
```vue
<template>
<div class="border border-default">Default</div>
<div class="border border-muted">Muted</div>
<div class="border border-accented">Accented</div>
<div class="border border-inverted">Inverted</div>
</template>
```
::
::note
Nuxt UI automatically applies a text and background color on the `<body>` element of your app:
This is how the `@theme` is generated for each design token:
:::code-collapse{class="[&>div]:!my-0"}
```scss
@theme default {
--text-color-dimmed: var(--ui-text-dimmed);
--text-color-muted: var(--ui-text-muted);
--text-color-toned: var(--ui-text-toned);
--text-color-default: var(--ui-text);
--text-color-highlighted: var(--ui-text-highlighted);
--text-color-inverted: var(--ui-text-inverted);
--background-color-default: var(--ui-bg);
--background-color-muted: var(--ui-bg-muted);
--background-color-elevated: var(--ui-bg-elevated);
--background-color-accented: var(--ui-bg-accented);
--background-color-inverted: var(--ui-bg-inverted);
--background-color-border: var(--ui-border);
--border-color-default: var(--ui-border);
--border-color-muted: var(--ui-border-muted);
--border-color-accented: var(--ui-border-accented);
--border-color-inverted: var(--ui-border-inverted);
--border-color-bg: var(--ui-bg);
--ring-color-default: var(--ui-border);
--ring-color-muted: var(--ui-border-muted);
--ring-color-accented: var(--ui-border-accented);
--ring-color-inverted: var(--ui-border-inverted);
--ring-color-bg: var(--ui-bg);
--ring-offset-color-default: var(--ui-border);
--ring-offset-color-muted: var(--ui-border-muted);
--ring-offset-color-accented: var(--ui-border-accented);
--ring-offset-color-inverted: var(--ui-border-inverted);
--ring-offset-color-bg: var(--ui-bg);
--divide-color-default: var(--ui-border);
--divide-color-muted: var(--ui-border-muted);
--divide-color-accented: var(--ui-border-accented);
--divide-color-inverted: var(--ui-border-inverted);
--divide-color-bg: var(--ui-bg);
--outline-color-default: var(--ui-border);
--outline-color-inverted: var(--ui-border-inverted);
--stroke-color-default: var(--ui-border);
--stroke-color-inverted: var(--ui-border-inverted);
--fill-color-default: var(--ui-border);
--fill-color-inverted: var(--ui-border-inverted);
}
```
:::
::
You can customize these CSS variables to tailor the appearance of your application in your `main.css` file:
::module-only
#ui
:::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css]
@import "tailwindcss";
@import "@nuxt/ui";
:root {
--ui-bg: var(--ui-color-neutral-50);
--ui-text: var(--ui-color-neutral-900);
}
.dark {
--ui-bg: var(--ui-color-neutral-950);
--ui-border: var(--ui-color-neutral-900);
}
```
:::
#ui-pro
:::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css]
@import "tailwindcss";
@import "@nuxt/ui-pro";
:root {
--ui-bg: var(--ui-color-neutral-50);
--ui-text: var(--ui-color-neutral-900);
}
.dark {
--ui-bg: var(--ui-color-neutral-950);
--ui-border: var(--ui-color-neutral-900);
}
```
:::
::
::note
Nuxt UI applies a text and background color on the `<body>` element of your app:
```css
body {
@apply antialiased text-(--ui-text) bg-(--ui-bg);
@apply antialiased text-default bg-default scheme-light dark:scheme-dark;
}
```
::
::tip
You can customize these CSS variables to tailor the appearance of your application:
### Radius
::module-only
#ui
:::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css]
@import "tailwindcss";
@import "@nuxt/ui";
:root {
--ui-bg: var(--ui-color-neutral-50);
--ui-text: var(--ui-color-neutral-900);
}
.dark {
--ui-bg: var(--ui-color-neutral-950);
--ui-border: var(--ui-color-neutral-900);
}
```
:::
#ui-pro
:::div{class="*:!mb-0 *:!mt-2.5"}
```css [app/assets/css/main.css]
@import "tailwindcss";
@import "@nuxt/ui-pro";
:root {
--ui-bg: var(--ui-color-neutral-50);
--ui-text: var(--ui-color-neutral-900);
}
.dark {
--ui-bg: var(--ui-color-neutral-950);
--ui-border: var(--ui-color-neutral-900);
}
```
:::
::
::
#### Border Radius
Nuxt UI uses a global `--ui-radius` CSS variable for consistent border rounding. Components use variations of this base value, like `rounded-[calc(var(--ui-radius)*2)]`, to create different levels of roundness throughout the UI:
Nuxt UI provides a centralized border radius system through the `--ui-radius` CSS variable.
```css
:root {
--ui-radius: var(--radius-sm);
--ui-radius: 0.25rem;
}
```
::note
Try the :prose-icon{name="i-lucide-swatch-book" class="text-(--ui-primary)"} theme picker in the header above to change the base radius value.
This CSS variable replaces Tailwind CSS's default `rounded-*` utilities so you can use the same class names:
::code-preview
[xs]{class="border-2 border-accented text-sm px-4 py-1.5 inline-block rounded-xs mr-2"}
[sm]{class="border-2 border-accented text-sm px-4 py-1.5 inline-block rounded-sm mr-2"}
[md]{class="border-2 border-accented text-sm px-4 py-1.5 inline-block rounded-md mr-2"}
[lg]{class="border-2 border-accented text-sm px-4 py-1.5 inline-block rounded-lg mr-2"}
[xl]{class="border-2 border-accented text-sm px-4 py-1.5 inline-block rounded-xl mr-2"}
[2xl]{class="border-2 border-accented text-sm px-4 py-1.5 inline-block rounded-2xl mr-2"}
[3xl]{class="border-2 border-accented text-sm px-4 py-1.5 inline-block rounded-3xl mr-2"}
#code
```vue
<template>
<div class="rounded-xs">xs</div>
<div class="rounded-sm">sm</div>
<div class="rounded-md">md</div>
<div class="rounded-lg">lg</div>
<div class="rounded-xl">xl</div>
<div class="rounded-2xl">2xl</div>
<div class="rounded-3xl">3xl</div>
</template>
```
::
::tip
You can customize the default radius value using the default Tailwind CSS variables or a value of your choice:
::note
This is how the `@theme` is generated for each radius value:
:::code-collapse{class="[&>div]:!my-0"}
```scss
@theme default {
--radius-xs: calc(var(--ui-radius) * 0.5); /* 0.125rem */
--radius-sm: var(--ui-radius); /* 0.25rem */
--radius-md: calc(var(--ui-radius) * 1.5); /* 0.375rem */
--radius-lg: calc(var(--ui-radius) * 2); /* 0.5rem */
--radius-xl: calc(var(--ui-radius) * 3); /* 0.75rem */
--radius-2xl: calc(var(--ui-radius) * 4); /* 1rem */
--radius-3xl: calc(var(--ui-radius) * 6); /* 1.5rem */
}
```
:::
::
You can customize the base radius value in your `main.css` file:
::module-only
#ui
@@ -629,7 +875,7 @@ You can customize the default radius value using the default Tailwind CSS variab
@import "@nuxt/ui";
:root {
--ui-radius: var(--radius-sm);
--ui-radius: 0.5rem;
}
```
@@ -643,18 +889,20 @@ You can customize the default radius value using the default Tailwind CSS variab
@import "@nuxt/ui-pro";
:root {
--ui-radius: var(--radius-sm);
--ui-radius: 0.5rem;
}
```
:::
::
::note
Try the :prose-icon{name="i-lucide-swatch-book" class="text-primary"} theme picker in the header above to change the base radius value.
::
#### Container
### Container
Nuxt UI uses a global `--ui-container` CSS variable to define the width of the container:
Nuxt UI provides a `--ui-container` CSS variable that controls the maximum width of the [Container](/components/container) component.
```css
:root {
@@ -662,8 +910,7 @@ Nuxt UI uses a global `--ui-container` CSS variable to define the width of the c
}
```
::tip
You can customize the default container width using the default Tailwind CSS variables or a value of your choice:
You can customize this value in your `main.css` file to adjust container widths consistently throughout your application:
::module-only
#ui
@@ -703,8 +950,6 @@ You can customize the default container width using the default Tailwind CSS var
:::
::
::
## Components theme
Nuxt UI components are styled using the [Tailwind Variants](https://www.tailwind-variants.org/) API, which provides a powerful way to create variants and manage component styles. Let's explore the key features of this API:
@@ -718,7 +963,7 @@ Components in Nuxt UI can have multiple `slots`, each representing a distinct HT
```ts [src/theme/card.ts]
export default {
slots: {
root: 'bg-(--ui-bg) ring ring-(--ui-border) divide-y divide-(--ui-border) rounded-[calc(var(--ui-radius)*2)]',
root: 'bg-default ring ring-default divide-y divide-default rounded-lg',
header: 'p-4 sm:px-6',
body: 'p-4 sm:p-6',
footer: 'p-4 sm:px-6'
@@ -777,7 +1022,7 @@ Nuxt UI components use `variants` to change the `slots` styles based on props. H
```ts [src/theme/avatar.ts]
export default {
slots: {
root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-(--ui-bg-elevated)',
root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-elevated',
image: 'h-full w-full rounded-[inherit] object-cover'
},
variants: {

View File

@@ -26,8 +26,8 @@ const isDark = computed({
get() {
return colorMode.value === 'dark'
},
set() {
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
set(_isDark) {
colorMode.preference = _isDark ? 'dark' : 'light'
}
})
</script>

View File

@@ -19,6 +19,7 @@ defineShortcuts({
</script>
```
- Shortcuts are automatically adjusted for non-macOS platforms, converting `meta` to `ctrl`.
- The composable uses VueUse's [`useEventListener`](https://vueuse.org/core/useEventListener/) to handle keydown events.
- For a complete list of available shortcut keys, refer to the [`KeyboardEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values) API documentation. Note that the key should be written in lowercase.
@@ -46,7 +47,7 @@ Shortcuts are defined using the following format:
#### Modifiers
- `meta`: Represents `⌘ Command` on macOS and `⊞ Windows` on Windows
- `meta`: Represents `⌘ Command` on macOS and `Ctrl` on other platforms
- `ctrl`: Represents `Ctrl` on all platforms
- `shift`: Used for alphabetic keys when Shift is required

View File

@@ -22,14 +22,14 @@ async function openModal() {
- The `useOverlay` composable is created using `createSharedComposable`, ensuring that the same overlay state is shared across your entire application.
::note
In order to return a value from the overlay, the `overlay.open()` can be awaited. In order for this to work, however, the **overlay component must emit a `close` event**. See example below for details.
In order to return a value from the overlay, the `overlay.open().instance.result` can be awaited. In order for this to work, however, the **overlay component must emit a `close` event**. See example below for details.
::
## API
### `create(component: T, options: OverlayOptions): OverlayInstance`
Creates an overlay, and returns its instance
Creates an overlay, and returns a factory instance
- Parameters:
- `component`: The overlay component
@@ -38,7 +38,7 @@ Creates an overlay, and returns its instance
- `props?: ComponentProps`: An optional object of props to pass to the rendered component.
- `destroyOnClose?: boolean` Removes the overlay from memory when closed `default: false`
### `open(id: symbol, props?: ComponentProps<T>): Promise<any>`
### `open(id: symbol, props?: ComponentProps<T>): OpenedOverlay<T>`
Opens the overlay using its `id`
@@ -62,10 +62,17 @@ Update an overlay using its `id`
- `id`: The identifier of the overlay
- `props`: An object of props to update on the rendered component.
### `unmount(id: symbol): void`
### `unMount(id: symbol): void`
Removes the overlay from the DOM using its `id`
- Parameters:
- `id`: The identifier of the overlay
### `isOpen(id: symbol): boolean`
Checks if an overlay its open using its `id`
- Parameters:
- `id`: The identifier of the overlay
@@ -75,7 +82,7 @@ In-memory list of overlays that were created
## Overlay Instance API
### `open(props?: ComponentProps<T>): Promise<any>`
### `open(props?: ComponentProps<T>): Promise<OpenedOverlay<T>>`
Opens the overlay
@@ -138,7 +145,7 @@ const overlay = useOverlay()
// Create with default props
const modalA = overlay.create(ModalA, { title: 'Welcome' })
const modalB = overlay.create(modalB)
const modalB = overlay.create(ModalB)
const slideoverA = overlay.create(SlideoverA)
@@ -149,7 +156,9 @@ const openModalA = () => {
const openModalB = async () => {
// Open modalB, and wait for its result
const input = await modalB.open()
const modalBInstance = modalB.open()
const input = await modalBInstance.result
// Pass the result from modalB to the slideover, and open it.
slideoverA.open({ input })

View File

@@ -247,6 +247,16 @@ You can also pass the `value` of one of the items if provided.
When `type="multiple"`, ensure to pass an array to the `default-value` prop or the `v-model` directive.
::
### With drag and drop
Use the [`useSortable`](https://vueuse.org/integrations/useSortable/) composable from [`@vueuse/integrations`](https://vueuse.org/integrations/README.html) to enable drag and drop functionality on the Accordion. This integration wraps [Sortable.js](https://sortablejs.github.io/Sortable/) to provide a seamless drag and drop experience.
::component-example
---
name: 'accordion-drag-and-drop-example'
---
::
### With body slot
Use the `#body` slot to customize the body of each item.
@@ -292,18 +302,6 @@ props:
---
::
### With drag and drop
Use the [`useSortable`](https://vueuse.org/integrations/useSortable/) composable from [`@vueuse/integrations`](https://vueuse.org/integrations/README.html) to enable drag and drop functionality on the accordion. This integration wraps [Sortable.js](https://sortablejs.github.io/Sortable/) to provide a seamless drag and drop experience.
The `useSortable` composable accepts various options, see the [Usage](https://vueuse.org/integrations/useSortable/#usage) for more examples.
::component-example
---
name: 'accordion-drag-and-drop-example'
---
::
## API
### Props

View File

@@ -330,7 +330,7 @@ props:
color: neutral
variant: outline
ui:
leadingIcon: 'text-(--ui-primary)'
leadingIcon: 'text-primary'
slots:
default: |

View File

@@ -223,6 +223,16 @@ name: 'calendar-other-system-example'
You can check all the available calendars on `@internationalized/date` docs.
::
### With external controls
You can control the calendar with external controls by manipulating the date passed in the `v-model`.
::component-example
---
name: 'calendar-external-controls-example'
---
::
### As a DatePicker
Use a [Button](/components/button) and a [Popover](/components/popover) component to create a date picker.

View File

@@ -229,6 +229,19 @@ class: 'p-8 px-16'
---
::
## Examples
### With thumbnails
You can use the [`emblaApi`](#expose) function [scrollTo](https://www.embla-carousel.com/api/methods/#scrollto) to display thumbnails under the carousel that allows you to navigate to a specific slide.
::component-example
---
name: 'carousel-thumbnails-example'
class: 'p-8 px-16'
---
::
## API
### Props
@@ -239,6 +252,10 @@ class: 'p-8 px-16'
:component-slots
### Emits
:component-emits
### Expose
You can access the typed component instance using [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref).

View File

@@ -0,0 +1,349 @@
---
title: CheckboxGroup
description: A set of checklist buttons to select multiple option from a list.
category: form
links:
- label: CheckboxGroup
icon: i-custom-reka-ui
to: https://reka-ui.com/docs/components/checkbox#group-root
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/CheckboxGroup.vue
navigation.badge: New
---
## Usage
Use the `v-model` directive to control the value of the CheckboxGroup or the `default-value` prop to set the initial value when you do not need to control its state.
### Items
Use the `items` prop as an array of strings or numbers:
::component-code
---
prettier: true
ignore:
- modelValue
- items
external:
- items
- modelValue
externalTypes:
- CheckboxGroupItem[]
- CheckboxGroupValue[]
props:
modelValue:
- 'System'
items:
- 'System'
- 'Light'
- 'Dark'
---
::
You can also pass an array of objects with the following properties:
- `label?: string`{lang="ts-type"}
- `description?: string`{lang="ts-type"}
- [`value?: string`{lang="ts-type"}](#value-key)
- `disabled?: boolean`{lang="ts-type"}
::component-code
---
ignore:
- modelValue
- items
external:
- items
- modelValue
externalTypes:
- CheckboxGroupItem[]
- CheckboxGroupValue[]
props:
modelValue:
- 'system'
items:
- label: 'System'
description: 'This is the first option.'
value: 'system'
- label: 'Light'
description: 'This is the second option.'
value: 'light'
- label: 'Dark'
description: 'This is the third option.'
value: 'dark'
---
::
::caution
When using objects, you need to reference the `value` property of the object in the `v-model` directive or the `default-value` prop.
::
### Value Key
You can change the property that is used to set the value by using the `value-key` prop. Defaults to `value`.
::component-code
---
ignore:
- modelValue
- items
- valueKey
external:
- items
- modelValue
externalTypes:
- CheckboxGroupItem[]
- CheckboxGroupValue[]
props:
modelValue:
- 'light'
valueKey: 'id'
items:
- label: 'System'
description: 'This is the first option.'
id: 'system'
- label: 'Light'
description: 'This is the second option.'
id: 'light'
- label: 'Dark'
description: 'This is the third option.'
id: 'dark'
---
::
### Legend
Use the `legend` prop to set the legend of the CheckboxGroup.
::component-code
---
prettier: true
ignore:
- defaultValue
- items
external:
- items
externalTypes:
- CheckboxGroupItem[]
props:
legend: 'Theme'
defaultValue:
- 'System'
items:
- 'System'
- 'Light'
- 'Dark'
---
::
### Color
Use the `color` prop to change the color of the CheckboxGroup.
::component-code
---
prettier: true
ignore:
- defaultValue
- items
external:
- items
externalTypes:
- CheckboxGroupItem[]
items:
color:
- primary
- secondary
- success
- info
- warning
- error
- neutral
props:
color: neutral
defaultValue:
- 'System'
items:
- 'System'
- 'Light'
- 'Dark'
---
::
### Variant
Use the `variant` prop to change the variant of the CheckboxGroup.
::component-code
---
prettier: true
ignore:
- defaultValue
- items
external:
- items
externalTypes:
- CheckboxGroupItem[]
items:
color:
- primary
- secondary
- success
- info
- warning
- error
- neutral
variant:
- list
- card
props:
color: 'primary'
variant: 'card'
defaultValue:
- 'System'
items:
- 'System'
- 'Light'
- 'Dark'
---
::
### Size
Use the `size` prop to change the size of the CheckboxGroup.
::component-code
---
prettier: true
ignore:
- defaultValue
- items
external:
- items
externalTypes:
- CheckboxGroupItem[]
items:
variant:
- list
- card
props:
size: 'xl'
variant: 'list'
defaultValue:
- 'System'
items:
- 'System'
- 'Light'
- 'Dark'
---
::
### Orientation
Use the `orientation` prop to change the orientation of the CheckboxGroup. Defaults to `vertical`.
::component-code
---
prettier: true
ignore:
- defaultValue
- items
external:
- items
externalTypes:
- CheckboxGroupItem[]
items:
variant:
- list
- card
props:
orientation: 'horizontal'
variant: 'list'
defaultValue:
- 'System'
items:
- 'System'
- 'Light'
- 'Dark'
---
::
### Indicator
Use the `indicator` prop to change the position or hide the indicator. Defaults to `start`.
::component-code
---
prettier: true
ignore:
- defaultValue
- items
external:
- items
externalTypes:
- CheckboxGroupItem[]
items:
indicator:
- start
- end
- hidden
variant:
- list
- card
props:
indicator: 'end'
variant: 'card'
defaultValue:
- 'System'
items:
- 'System'
- 'Light'
- 'Dark'
---
::
### Disabled
Use the `disabled` prop to disable the CheckboxGroup.
::component-code
---
prettier: true
ignore:
- defaultValue
- items
external:
- items
externalTypes:
- CheckboxGroupItem[]
props:
disabled: true
defaultValue:
- 'System'
items:
- 'System'
- 'Light'
- 'Dark'
---
::
## API
### Props
:component-props
### Slots
:component-slots
### Emits
:component-emits
## Theme
:component-theme

View File

@@ -156,6 +156,23 @@ props:
---
::
### Variant :badge{label="New" class="align-text-top"}
Use the `variant` prop to change the variant of the Checkbox.
::component-code
---
ignore:
- label
- defaultValue
props:
color: 'primary'
variant: 'card'
defaultValue: true
label: Check me
---
::
### Size
Use the `size` prop to change the size of the Checkbox.
@@ -167,6 +184,24 @@ ignore:
- defaultValue
props:
size: xl
variant: list
defaultValue: true
label: Check me
---
::
### Indicator :badge{label="New" class="align-text-top"}
Use the `indicator` prop to change the position or hide the indicator. Defaults to `start`.
::component-code
---
ignore:
- label
- defaultValue
props:
indicator: 'end'
variant: 'card'
defaultValue: true
label: Check me
---

View File

@@ -7,9 +7,9 @@ links:
icon: i-custom-fuse-js
to: https://fusejs.io/
target: _blank
- label: Combobox
- label: Listbox
icon: i-custom-reka-ui
to: https://reka-ui.com/docs/components/combobox
to: https://reka-ui.com/docs/components/listbox
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/CommandPalette.vue

View File

@@ -99,12 +99,12 @@ props:
slots:
default: |
<div class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72">
<div class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72">
Right click here
</div>
---
:div{class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72"}[Right click here]
:div{class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72"}[Right click here]
::
::note
@@ -143,12 +143,12 @@ props:
slots:
default: |
<div class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72">
<div class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72">
Right click here
</div>
---
:div{class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72"}[Right click here]
:div{class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72"}[Right click here]
::
### Disabled
@@ -179,12 +179,12 @@ props:
slots:
default: |
<div class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72">
<div class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72">
Right click here
</div>
---
:div{class="flex items-center justify-center rounded-md border border-dashed border-(--ui-border-accented) text-sm aspect-video w-72"}[Right click here]
:div{class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72"}[Right click here]
::
## Examples

View File

@@ -248,7 +248,7 @@ Make sure to add the `data-vaul-drawer-wrapper` directive to a parent element of
```vue [app.vue]
<template>
<UApp>
<div class="bg-(--ui-bg)" data-vaul-drawer-wrapper>
<div class="bg-default" data-vaul-drawer-wrapper>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
@@ -262,7 +262,7 @@ export default defineNuxtConfig({
app: {
rootAttrs: {
'data-vaul-drawer-wrapper': '',
'class': 'bg-(--ui-bg)'
'class': 'bg-default'
}
}
})

View File

@@ -34,7 +34,7 @@ slots:
The label `for` attribute and the form control are associated with a unique `id` if not provided.
::
When using the `required` prop, an asterisk is be added next to the label.
When using the `required` prop, an asterisk is added next to the label.
::component-code
---

View File

@@ -195,12 +195,12 @@ This will give you access to the following:
| Name | Type |
| ---- | ---- |
| `submit()`{lang="ts-type"} | `Promise<void>`{lang="ts-type"} <br> <div class="text-(--ui-text-toned) mt-1"><p>Triggers form submission.</p> |
| `validate(opts: { name?: keyof T \| (keyof T)[], silent?: boolean, nested?: boolean, transform?: boolean })`{lang="ts-type"} | `Promise<T>`{lang="ts-type"} <br> <div class="text-(--ui-text-toned) mt-1"><p>Triggers form validation. Will raise any errors unless `opts.silent` is set to true.</p> |
| `clear(path?: keyof T)`{lang="ts-type"} | `void` <br> <div class="text-(--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?: keyof T)`{lang="ts-type"} | `FormError[]`{lang="ts-type"} <br> <div class="text-(--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?: keyof T)`{lang="ts-type"} | `void` <br> <div class="text-(--ui-text-toned) mt-1"><p>Sets form errors for a given path. If no path is provided, overrides all errors.</p> |
| `errors`{lang="ts-type"} | `Ref<FormError[]>`{lang="ts-type"} <br> <div class="text-(--ui-text-toned) mt-1"><p>A reference to the array containing validation errors. Use this to access or manipulate the error information.</p> |
| `submit()`{lang="ts-type"} | `Promise<void>`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>Triggers form submission.</p> |
| `validate(opts: { name?: keyof T \| (keyof T)[], silent?: boolean, nested?: boolean, transform?: boolean })`{lang="ts-type"} | `Promise<T>`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>Triggers form validation. Will raise any errors unless `opts.silent` is set to true.</p> |
| `clear(path?: keyof T)`{lang="ts-type"} | `void` <br> <div class="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?: keyof T)`{lang="ts-type"} | `FormError[]`{lang="ts-type"} <br> <div class="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[], name?: keyof T)`{lang="ts-type"} | `void` <br> <div class="text-toned mt-1"><p>Sets form errors for a given path. If no path is provided, overrides all errors.</p> |
| `errors`{lang="ts-type"} | `Ref<FormError[]>`{lang="ts-type"} <br> <div class="text-toned mt-1"><p>A reference to the array containing validation errors. Use this to access or manipulate the error information.</p> |
| `disabled`{lang="ts-type"} | `Ref<boolean>`{lang="ts-type"} |
| `dirty`{lang="ts-type"} | `Ref<boolean>`{lang="ts-type"} `true` if at least one form field has been updated by the user.|
| `dirtyFields`{lang="ts-type"} | `DeepReadonly<Set<keyof T>>`{lang="ts-type"} Tracks fields that have been modified by the user. |
@@ -209,4 +209,4 @@ This will give you access to the following:
## Theme
:component-theme
:component-theme

Some files were not shown because too many files have changed in this diff Show More