mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-15 12:39:35 +01:00
Compare commits
241 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13be8f1c83 | ||
|
|
48f68de4ca | ||
|
|
13bd3f3804 | ||
|
|
65735e787f | ||
|
|
6b971b8e6c | ||
|
|
1598d8fc72 | ||
|
|
2176e30113 | ||
|
|
1f3e9789fe | ||
|
|
b797690483 | ||
|
|
f7303d5c94 | ||
|
|
346031f279 | ||
|
|
dae6d77cf2 | ||
|
|
c1d5bcc1ac | ||
|
|
1bc44f8594 | ||
|
|
9ee68d20fc | ||
|
|
d5f50be354 | ||
|
|
03ab56c9bd | ||
|
|
9985fd5af4 | ||
|
|
fb2a835a78 | ||
|
|
2d5100044b | ||
|
|
7903d2adc2 | ||
|
|
cd9ee1ff99 | ||
|
|
29208f1877 | ||
|
|
f9f505b0c0 | ||
|
|
7361914715 | ||
|
|
88923bb678 | ||
|
|
212154d0d0 | ||
|
|
b9037e166f | ||
|
|
58fc563d63 | ||
|
|
11569bc7e0 | ||
|
|
1934063763 | ||
|
|
b6de20104f | ||
|
|
2971a31242 | ||
|
|
30068da217 | ||
|
|
44734f717e | ||
|
|
77cc1f3670 | ||
|
|
e55a27a503 | ||
|
|
45f5e628ea | ||
|
|
e47bba9a05 | ||
|
|
fcbedd1244 | ||
|
|
3a964d5a4b | ||
|
|
b7c9c83dfa | ||
|
|
43ee099fbe | ||
|
|
4bc9878ef4 | ||
|
|
bb8d7aa48e | ||
|
|
8c727f21d7 | ||
|
|
48fabbcdeb | ||
|
|
c46b952022 | ||
|
|
c0e14d006e | ||
|
|
a58efd23aa | ||
|
|
ec2b51b59e | ||
|
|
e2dc287dbb | ||
|
|
dbe8b34b6e | ||
|
|
091725f940 | ||
|
|
c21fbe5ec6 | ||
|
|
cff1282f30 | ||
|
|
86a7da03b1 | ||
|
|
252189de0a | ||
|
|
4451768415 | ||
|
|
8e67cab77a | ||
|
|
d113c31844 | ||
|
|
18e4b4ff4e | ||
|
|
1c8ec1d857 | ||
|
|
d7872a149c | ||
|
|
9104a4d54d | ||
|
|
0506c0cc6a | ||
|
|
2bef1e26c6 | ||
|
|
02694db29c | ||
|
|
b8a7a47620 | ||
|
|
bd732d3b34 | ||
|
|
93406d26b8 | ||
|
|
b034a5679c | ||
|
|
c7b1fc32ad | ||
|
|
3b0dbfe473 | ||
|
|
1454149c97 | ||
|
|
5af04bad5f | ||
|
|
f242c7243e | ||
|
|
5a864e8d6f | ||
|
|
ee373629d5 | ||
|
|
63b5f2bc2f | ||
|
|
4e96dcca42 | ||
|
|
b131b1168b | ||
|
|
3c849b98a6 | ||
|
|
714e0ff250 | ||
|
|
74c77f9bac | ||
|
|
54fda9eef8 | ||
|
|
c3567a34a4 | ||
|
|
d210d18a2f | ||
|
|
7aeecea599 | ||
|
|
70e889813c | ||
|
|
2b9696f4d3 | ||
|
|
188184b674 | ||
|
|
b0d1da8dc2 | ||
|
|
fec5f3f3ce | ||
|
|
05509b7ed1 | ||
|
|
88b17cd93c | ||
|
|
0eca0fd201 | ||
|
|
420fcb003a | ||
|
|
f607140941 | ||
|
|
40da32588d | ||
|
|
264373b499 | ||
|
|
bb70218568 | ||
|
|
402f508e7d | ||
|
|
0d69747c9d | ||
|
|
760eb467be | ||
|
|
b830f63c89 | ||
|
|
71dac5e5b0 | ||
|
|
7b81bfa1ae | ||
|
|
bf1c9e7c94 | ||
|
|
23d9b51a58 | ||
|
|
2e6ba71e89 | ||
|
|
ea4007c62d | ||
|
|
69d6997210 | ||
|
|
6565472570 | ||
|
|
ee408e522e | ||
|
|
461e6173a9 | ||
|
|
b824f0682e | ||
|
|
7ce6af4870 | ||
|
|
b4cc9a5ab4 | ||
|
|
06eceff68b | ||
|
|
40f3e3b486 | ||
|
|
a5458765dc | ||
|
|
ac574b239b | ||
|
|
feb716c941 | ||
|
|
15da5cf71e | ||
|
|
125a28190b | ||
|
|
569fa7619b | ||
|
|
0ff2448655 | ||
|
|
a6c3daa363 | ||
|
|
e16eeee8c1 | ||
|
|
53ac62eae5 | ||
|
|
9c36d37b84 | ||
|
|
0462edb84e | ||
|
|
91e77bb09c | ||
|
|
84e35d1a79 | ||
|
|
28f29e98b8 | ||
|
|
81d7ca0cd1 | ||
|
|
89d3766835 | ||
|
|
9104213d35 | ||
|
|
d699558e38 | ||
|
|
7cbc3913d9 | ||
|
|
d2ceeadae7 | ||
|
|
c7f64b64c7 | ||
|
|
72ab47e77d | ||
|
|
5b187d6fbd | ||
|
|
f9e61fc422 | ||
|
|
1291e95e1c | ||
|
|
f943203770 | ||
|
|
f2d387622a | ||
|
|
b02dc4d5b7 | ||
|
|
6dddadc370 | ||
|
|
d89ecce472 | ||
|
|
efb74668bd | ||
|
|
e065734d58 | ||
|
|
0c5bea5f11 | ||
|
|
f6d4dd3b88 | ||
|
|
d9d4f1915a | ||
|
|
c70d29702e | ||
|
|
a0d8935f64 | ||
|
|
04aefcf81f | ||
|
|
e68b9795be | ||
|
|
b8c8718560 | ||
|
|
2a33a8171d | ||
|
|
23cfc046e7 | ||
|
|
e68cb53ab6 | ||
|
|
109b857472 | ||
|
|
ea15e21cdc | ||
|
|
b7153cd879 | ||
|
|
5047d448ed | ||
|
|
a0fee0fa73 | ||
|
|
b762d29220 | ||
|
|
98c19be71a | ||
|
|
8cf9f27d53 | ||
|
|
c0455c831f | ||
|
|
0360ea7a3c | ||
|
|
711539f3ce | ||
|
|
80d6d89467 | ||
|
|
d573fb636f | ||
|
|
1d08d319a7 | ||
|
|
b654c93e93 | ||
|
|
b7e04db645 | ||
|
|
e6034a2765 | ||
|
|
a8c38224c6 | ||
|
|
a9ef6406ea | ||
|
|
96e846ddee | ||
|
|
16dbc1b536 | ||
|
|
c6b2ae45e5 | ||
|
|
547c657ee7 | ||
|
|
b16b434041 | ||
|
|
fb12323304 | ||
|
|
0a404615ff | ||
|
|
cbf0f22efd | ||
|
|
4cde571e38 | ||
|
|
023497d144 | ||
|
|
56d4ca3b74 | ||
|
|
11b8c3d9db | ||
|
|
419a24f703 | ||
|
|
854bb81295 | ||
|
|
bf8e3954a4 | ||
|
|
637ec4d27b | ||
|
|
f3632ddee5 | ||
|
|
dbd2aed20b | ||
|
|
51c8b8e3e5 | ||
|
|
588a908358 | ||
|
|
d692a81b1e | ||
|
|
ec98d415b4 | ||
|
|
c80d2e6c12 | ||
|
|
ce61a2b6db | ||
|
|
eee5bb9939 | ||
|
|
d3804157ec | ||
|
|
03e24f4583 | ||
|
|
d0e626c551 | ||
|
|
670d8bfbac | ||
|
|
64b703df8d | ||
|
|
976b03f241 | ||
|
|
35e3b8c720 | ||
|
|
07ef771b17 | ||
|
|
5c75b5c490 | ||
|
|
53df9d9a8c | ||
|
|
0d1a76e3c6 | ||
|
|
b2ed4662af | ||
|
|
423c48879d | ||
|
|
acecff40ec | ||
|
|
1fd5fac295 | ||
|
|
b23f2decfc | ||
|
|
7154254ac2 | ||
|
|
49f85d55c5 | ||
|
|
97037864b3 | ||
|
|
0abccabc26 | ||
|
|
ac323c4ccc | ||
|
|
d4e408cfd8 | ||
|
|
f3bf69c233 | ||
|
|
d6daf466ac | ||
|
|
6e66990372 | ||
|
|
56e28d80db | ||
|
|
24e61ccc8b | ||
|
|
c9e6256e7f | ||
|
|
ce955d24f1 | ||
|
|
bf580863af | ||
|
|
f38a217032 | ||
|
|
717a027bad |
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* @benjamincanac
|
||||
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before reporting a bug, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
Before reporting a bug, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
- type: textarea
|
||||
id: env
|
||||
attributes:
|
||||
|
||||
15
.github/ISSUE_TEMPLATE/bug-v3.yml
vendored
15
.github/ISSUE_TEMPLATE/bug-v3.yml
vendored
@@ -5,8 +5,8 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
> [!IMPORTANT]
|
||||
> As Nuxt UI v3 is currently in alpha, we recommend thorough testing before using it in production environments. We're actively working on stabilization and welcome feedback from early adopters to improve the library.
|
||||
> [!IMPORTANT]
|
||||
> As Nuxt UI v3 is currently in alpha, we recommend thorough testing before using it in production environments. We're actively working on stabilization and welcome feedback from early adopters to improve the library.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
@@ -29,11 +29,20 @@ body:
|
||||
- Build Modules: `-`
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: package
|
||||
attributes:
|
||||
label: Is this bug related to Nuxt or Vue?
|
||||
options:
|
||||
- Nuxt
|
||||
- Vue
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
placeholder: v3.0.0-alpha.5
|
||||
placeholder: v3.0.0-alpha.x
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
4
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -5,14 +5,14 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before requesting a feature, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
Before requesting a feature, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
- type: dropdown
|
||||
id: version
|
||||
attributes:
|
||||
label: For what version of Nuxt UI are you suggesting this?
|
||||
options:
|
||||
- v2.x
|
||||
- v3-alpha
|
||||
- v3.0.0-alpha.x
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/question.yml
vendored
4
.github/ISSUE_TEMPLATE/question.yml
vendored
@@ -5,14 +5,14 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before asking a question, please make sure that you have read through our [documentation](https://ui.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
Before asking a question, please make sure that you have read through our [documentation](https://ui2.nuxt.com) and existing [issues](https://github.com/nuxt/ui/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc).
|
||||
- type: dropdown
|
||||
id: version
|
||||
attributes:
|
||||
label: For what version of Nuxt UI are you asking this question?
|
||||
options:
|
||||
- v2.x
|
||||
- v3-alpha
|
||||
- v3.0.0-alpha.x
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
name: ci-dev
|
||||
name: module
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- v2
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- v2
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
permissions:
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [20]
|
||||
node: [22]
|
||||
|
||||
env:
|
||||
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
|
||||
@@ -37,16 +37,6 @@ jobs:
|
||||
node-version: ${{ matrix.node }}
|
||||
cache: pnpm
|
||||
|
||||
- name: Filter changes
|
||||
uses: dorny/paths-filter@v3
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
src:
|
||||
- 'src/**'
|
||||
- 'package.json'
|
||||
- 'pnpm-lock.yaml'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
@@ -65,8 +55,5 @@ jobs:
|
||||
- name: Test
|
||||
run: pnpm run test run
|
||||
|
||||
- name: Release Edge
|
||||
if: github.event_name == 'push' && steps.changes.outputs.src == 'true'
|
||||
run: ./scripts/release-edge.sh
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}}
|
||||
- name: Publish
|
||||
run: pnpx pkg-pr-new publish --compact --no-template --pnpm
|
||||
@@ -1,18 +1,18 @@
|
||||
name: ci-main
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- 'v2*'
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
publish:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest] # macos-latest, windows-latest
|
||||
node: [20]
|
||||
node: [22]
|
||||
|
||||
env:
|
||||
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
|
||||
@@ -48,14 +48,7 @@ jobs:
|
||||
- name: Test
|
||||
run: pnpm run test run
|
||||
|
||||
- name: Version Check
|
||||
id: check
|
||||
uses: EndBug/version-check@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Release
|
||||
if: github.event_name == 'push' && steps.check.outputs.changed == 'true'
|
||||
- name: Publish
|
||||
run: ./scripts/release.sh
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
|
||||
23
.github/workflows/stale.yml
vendored
23
.github/workflows/stale.yml
vendored
@@ -1,23 +0,0 @@
|
||||
name: stale
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
exempt-issue-labels: triage,v3
|
||||
stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity.'
|
||||
stale-issue-label: stale
|
||||
stale-pr-label: stale
|
||||
days-before-stale: 30
|
||||
days-before-close: -1
|
||||
80
CHANGELOG.md
80
CHANGELOG.md
@@ -1,5 +1,85 @@
|
||||
# Changelog
|
||||
|
||||
## [2.22.1](https://github.com/nuxt/ui/compare/v2.22.0...v2.22.1) (2025-07-16)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Badge/Button:** support numeric zero as visible label ([#4116](https://github.com/nuxt/ui/issues/4116)) ([2971a31](https://github.com/nuxt/ui/commit/2971a3124299e927ddb506bb0fc61b906aa0cfeb))
|
||||
|
||||
## [2.22.0](https://github.com/nuxt/ui/compare/v2.21.1...v2.22.0) (2025-04-22)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **Form:** drop explicit support for `zod` and `valibot` (#3618)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Link:** properly pick all `aria-*` & `data-*` attrs ([2bef1e2](https://github.com/nuxt/ui/commit/2bef1e26c6dfd5ee81b11f6da76e257861fc0bef)), closes [#3007](https://github.com/nuxt/ui/issues/3007)
|
||||
* **Table:** checkbox still emit `[@select](https://github.com/select)` event ([#3269](https://github.com/nuxt/ui/issues/3269)) ([c0e14d0](https://github.com/nuxt/ui/commit/c0e14d006ea39965e805adbf9698f5cb95e7c965))
|
||||
* **Table:** remove type annotation in template ([4e96dcc](https://github.com/nuxt/ui/commit/4e96dcca4213bbb56f1dd465ad7d47374e83bc9a)), closes [#3146](https://github.com/nuxt/ui/issues/3146)
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **Form:** drop explicit support for `zod` and `valibot` ([#3618](https://github.com/nuxt/ui/issues/3618)) ([ee37362](https://github.com/nuxt/ui/commit/ee373629d5a9800921301dcbab309f884eaf83fb))
|
||||
|
||||
## [2.21.1](https://github.com/nuxt/ui/compare/v2.21.0...v2.21.1) (2025-03-08)
|
||||
|
||||
### Features
|
||||
|
||||
* **Form:** add standard schema support ([#2880](https://github.com/nuxt/ui/issues/2880)) ([9c36d37](https://github.com/nuxt/ui/commit/9c36d37b847468d1cbd76eea38ac00cbc22549ca))
|
||||
* **module:** add `colorMode` option ([d2ceead](https://github.com/nuxt/ui/commit/d2ceeadae796254128697d94a3e317234bc2ecda)), closes [#3143](https://github.com/nuxt/ui/issues/3143)
|
||||
* **SelectMenu:** add inputTargetForm prop to handle input validation ([#3107](https://github.com/nuxt/ui/issues/3107)) ([feb716c](https://github.com/nuxt/ui/commit/feb716c941f1e7315009b53861a4dc0c2f233052))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Alert/Notification:** allow description ui override ([125a281](https://github.com/nuxt/ui/commit/125a28190b1a83e2456457e7a4ec618384b2446c)), closes [#2554](https://github.com/nuxt/ui/issues/2554)
|
||||
* **Table:** revert [#2600](https://github.com/nuxt/ui/issues/2600) to fix excessive column data slot re-renders ([#3375](https://github.com/nuxt/ui/issues/3375)) ([23d9b51](https://github.com/nuxt/ui/commit/23d9b51a5861f5d1f32f68a3141a600655a0598a))
|
||||
|
||||
## [2.21.0](https://github.com/nuxt/ui/compare/v2.20.0...v2.21.0) (2025-01-14)
|
||||
|
||||
### Features
|
||||
|
||||
* **module:** handle `tailwindMerge` config from `app.config` ([#2902](https://github.com/nuxt/ui/issues/2902)) ([ea15e21](https://github.com/nuxt/ui/commit/ea15e21cdcba00e21302415829113e8c6def8a6e))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Table:** `v-model` causing first column missing ([#2890](https://github.com/nuxt/ui/issues/2890)) ([d573fb6](https://github.com/nuxt/ui/commit/d573fb636f7f749ce95b93c5fb1ae2a053eeeeb0))
|
||||
* **Table:** remove `[@select](https://github.com/select)` event on checkbox ([#3042](https://github.com/nuxt/ui/issues/3042)) ([d9d4f19](https://github.com/nuxt/ui/commit/d9d4f1915aac586ae1abf3ebe67ca9aff65b9be0))
|
||||
* **tailwind:** use mjs template ([#2945](https://github.com/nuxt/ui/issues/2945)) ([8cf9f27](https://github.com/nuxt/ui/commit/8cf9f27d537bad5ffe4e136f52ff71548a451c5f))
|
||||
|
||||
## [2.20.0](https://github.com/nuxt/ui/compare/v2.19.2...v2.20.0) (2024-12-09)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **Form:** resolve async validation in yup & issue directly mutate state (#2701)
|
||||
|
||||
### Features
|
||||
|
||||
* **Accordion:** add `close` event ([#2750](https://github.com/nuxt/ui/issues/2750)) ([419a24f](https://github.com/nuxt/ui/commit/419a24f7034cefda2c6669f3c26742552e500f63))
|
||||
* **Badge:** handle `icon` prop ([#2594](https://github.com/nuxt/ui/issues/2594)) ([0d1a76e](https://github.com/nuxt/ui/commit/0d1a76e3c69e08534abb295b96548e67cfbea00c))
|
||||
* **InputMenu/SelectMenu:** add support for `dot notation` in `by` prop ([#2607](https://github.com/nuxt/ui/issues/2607)) ([53df9d9](https://github.com/nuxt/ui/commit/53df9d9a8cd6850803bdafc7ef6efe4e7404d334))
|
||||
* **Link:** allow partial query match for `activeClass` ([#2663](https://github.com/nuxt/ui/issues/2663)) ([03e24f4](https://github.com/nuxt/ui/commit/03e24f45836bdddd94b30cbaecc2288a78b56b0b))
|
||||
* **Notification:** add `pauseTimeoutOnHover` prop ([#2661](https://github.com/nuxt/ui/issues/2661)) ([11b8c3d](https://github.com/nuxt/ui/commit/11b8c3d9db1ec62b1c3557703c7ab5c99cb42df5))
|
||||
* **Table:** add contextmenu handling to table rows ([#2283](https://github.com/nuxt/ui/issues/2283)) ([c9e6256](https://github.com/nuxt/ui/commit/c9e6256e7f2c06da8bfda13700f56f6994e76eab))
|
||||
* **Table:** add custom `[@select](https://github.com/select):all` event ([#2581](https://github.com/nuxt/ui/issues/2581)) ([ac323c4](https://github.com/nuxt/ui/commit/ac323c4cccd930f2cd8c1f54b325bd509acd40bf))
|
||||
* **Table:** allow dynamically render `checkbox` ([#2549](https://github.com/nuxt/ui/issues/2549)) ([d6daf46](https://github.com/nuxt/ui/commit/d6daf466ace42b828151c45b18cd47179e85d66d))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **AvatarGroup/ButtonGroup/MeterGroup:** allow deeply partial `ui` config ([#2542](https://github.com/nuxt/ui/issues/2542)) ([bf58086](https://github.com/nuxt/ui/commit/bf580863af11d6a1a4c6c6774b44ec37b082e933))
|
||||
* **Carousel:** wrong `ui` type with `strategy` ([07ef771](https://github.com/nuxt/ui/commit/07ef771b17c72e275508a273371454a5e8a62257))
|
||||
* **components:** replace `as const` with correct type in config ([#2652](https://github.com/nuxt/ui/issues/2652)) ([51c8b8e](https://github.com/nuxt/ui/commit/51c8b8e3e59d7eceff72625650a199fcf7c6feca))
|
||||
* **date-picker:** undefined `dayIndex` ([#2545](https://github.com/nuxt/ui/issues/2545)) ([ce955d2](https://github.com/nuxt/ui/commit/ce955d24f1dfd222e87ce88428c0612c3f13cd50))
|
||||
* **Form:** resolve async validation in yup & issue directly mutate state ([#2701](https://github.com/nuxt/ui/issues/2701)) ([f3632dd](https://github.com/nuxt/ui/commit/f3632ddee511f0fccb24d4fc37403421e84ffdae))
|
||||
* **Form:** use parsed value from `joi` instead of original state ([#2587](https://github.com/nuxt/ui/issues/2587)) ([acecff4](https://github.com/nuxt/ui/commit/acecff40ec0156e45b4934c5d10c4dfa7c135f8e))
|
||||
* **InputMenu/SelectMenu:** use `by` prop to compare objects & support dot notation in `value-attribute` ([#2566](https://github.com/nuxt/ui/issues/2566)) ([7154254](https://github.com/nuxt/ui/commit/7154254ac22830f651ec200f7f3af2f5577f2de0))
|
||||
* **Link:** `exactQuery` prop type ([#2781](https://github.com/nuxt/ui/issues/2781)) ([4cde571](https://github.com/nuxt/ui/commit/4cde571e387775a9b12759f6f8c99117c84cbcff))
|
||||
* **Notification:** element renders even when no `notification` is present ([#2561](https://github.com/nuxt/ui/issues/2561)) ([d4e408c](https://github.com/nuxt/ui/commit/d4e408cfd8e2ef26021519f2f30f57e9120e1939))
|
||||
* **Table:** data outdated when rows change ([#2600](https://github.com/nuxt/ui/issues/2600)) ([b23f2de](https://github.com/nuxt/ui/commit/b23f2decfc9607555a315d0d087d0a042f03a938))
|
||||
* **Table:** missing type on props `loadingState` ([#2551](https://github.com/nuxt/ui/issues/2551)) ([6e66990](https://github.com/nuxt/ui/commit/6e66990372ef6bd7c109a64c753d9b50e96a450b))
|
||||
* **Table:** prevent `onClick` while blocking element ([#2592](https://github.com/nuxt/ui/issues/2592)) ([9703786](https://github.com/nuxt/ui/commit/97037864b39749db228fa5f51981f19e4a9c29dd))
|
||||
* **types:** improve `DeepPartial` type for App Config ([#2621](https://github.com/nuxt/ui/issues/2621)) ([976b03f](https://github.com/nuxt/ui/commit/976b03f241ef9626a6338685e43c844a8b3953fd))
|
||||
|
||||
## [2.19.2](https://github.com/nuxt/ui/compare/v2.19.1...v2.19.2) (2024-11-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
35
README.md
35
README.md
@@ -1,4 +1,4 @@
|
||||
[](https://ui.nuxt.com)
|
||||
[](https://ui2.nuxt.com)
|
||||
|
||||
# Nuxt UI
|
||||
|
||||
@@ -20,29 +20,34 @@ Its goal is to provide everything related to UI when building a Nuxt app. This i
|
||||
- Keyboard shortcuts
|
||||
- Bundled icons
|
||||
- Fully typed
|
||||
- [Figma Kit](https://www.figma.com/community/file/1288455405058138934)
|
||||
- [Figma Kit](https://www.figma.com/community/file/1436401057300493073)
|
||||
|
||||
Read more on [ui.nuxt.com](https://ui.nuxt.com)
|
||||
Read more on [ui2.nuxt.com](https://ui2.nuxt.com)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npx nuxi@latest module add ui
|
||||
# npm
|
||||
npm install @nuxt/ui@2
|
||||
# yarn
|
||||
yarn add @nuxt/ui@2
|
||||
# pnpm
|
||||
pnpm add @nuxt/ui@2
|
||||
# bun
|
||||
bun add @nuxt/ui@2
|
||||
```
|
||||
|
||||
If you want latest updates, please use `@nuxt/ui-edge` in your `package.json`:
|
||||
Next, register the `@nuxt/ui` module in your `nuxt.config.ts`:
|
||||
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
"@nuxt/ui": "npm:@nuxt/ui-edge@latest"
|
||||
}
|
||||
}
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
modules: ['@nuxt/ui']
|
||||
})
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Visit https://ui.nuxt.com to explore the documentation.
|
||||
Visit https://ui2.nuxt.com to explore the documentation.
|
||||
|
||||
## Credits
|
||||
|
||||
@@ -59,15 +64,15 @@ Visit https://ui.nuxt.com to explore the documentation.
|
||||
Thank you for considering contributing to Nuxt UI. Here are a few ways you can get involved:
|
||||
|
||||
- Reporting Bugs: If you come across any bugs or issues, please check out the reporting bugs guide to learn how to submit a bug report.
|
||||
- Suggestions: Have any thoughts to enhance Nuxt UI? We'd love to hear them! Check out the [contribution guide](https://ui.nuxt.com/getting-started/contributing) to share your suggestions.
|
||||
- Suggestions: Have any thoughts to enhance Nuxt UI? We'd love to hear them! Check out the [contribution guide](https://ui2.nuxt.com/getting-started/contributing) to share your suggestions.
|
||||
|
||||
## Local Development
|
||||
|
||||
Follow the docs to [Set up your local development environment](https://ui.nuxt.com/getting-started/contributing#_2-local-development-setup) and contribute.
|
||||
Follow the docs to [Set up your local development environment](https://ui2.nuxt.com/getting-started/contributing#_2-local-development-setup) and contribute.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under the [MIT license](https://github.com/nuxt/ui/blob/dev/LICENSE.md).
|
||||
Licensed under the [MIT license](https://github.com/nuxt/ui/blob/v2/LICENSE.md).
|
||||
|
||||
<!-- Badges -->
|
||||
[npm-version-src]: https://img.shields.io/npm/v/@nuxt/ui/latest.svg?style=flat&colorA=18181B&colorB=28CF8D
|
||||
|
||||
@@ -91,7 +91,7 @@ useHead({
|
||||
],
|
||||
link: [
|
||||
{ rel: 'icon', type: 'image/svg+xml', href: '/icon.svg' },
|
||||
{ rel: 'canonical', href: `https://ui.nuxt.com${withoutTrailingSlash(route.path)}` }
|
||||
{ rel: 'canonical', href: `https://ui2.nuxt.com${withoutTrailingSlash(route.path)}` }
|
||||
],
|
||||
htmlAttrs: {
|
||||
lang: 'en'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const id = 'nuxt-ui-banner-2'
|
||||
const to = 'https://ui3.nuxt.dev'
|
||||
const id = 'nuxt-ui-banner-4'
|
||||
const to = 'https://ui.nuxt.com'
|
||||
|
||||
const hideBanner = () => {
|
||||
localStorage.setItem(id, 'true')
|
||||
@@ -30,7 +30,6 @@ if (import.meta.server) {
|
||||
:to="to"
|
||||
target="_blank"
|
||||
class="focus:outline-none"
|
||||
aria-label="Nuxt UI Pro pricing"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span class="absolute inset-0 " aria-hidden="true" />
|
||||
@@ -40,19 +39,19 @@ if (import.meta.server) {
|
||||
<div class="lg:flex-1 hidden lg:flex items-center" />
|
||||
|
||||
<p class="text-sm font-medium text-white dark:text-gray-900 truncate">
|
||||
<UIcon name="i-heroicons-rocket-launch" class="w-5 h-5 align-top flex-shrink-0 pointer-events-none mr-2" />
|
||||
<span class="font-semibold">Nuxt UI v3-alpha</span> has been released!
|
||||
<UIcon name="i-lucide-rocket" class="size-5 align-top flex-shrink-0 pointer-events-none mr-1.5" />
|
||||
<span class="font-bold">Nuxt UI v3</span> is officially released!
|
||||
</p>
|
||||
|
||||
<UButton
|
||||
to="https://ui3.nuxt.dev"
|
||||
<!-- <UButton
|
||||
:to="to"
|
||||
target="_blank"
|
||||
label="Try it out"
|
||||
label="Buy now"
|
||||
color="black"
|
||||
variant="solid"
|
||||
size="2xs"
|
||||
trailing-icon="i-heroicons-arrow-right-20-solid"
|
||||
/>
|
||||
/> -->
|
||||
|
||||
<div class="flex items-center justify-end lg:flex-1">
|
||||
<button
|
||||
|
||||
@@ -30,7 +30,7 @@ const { $ui } = useNuxtApp()
|
||||
const links = [{
|
||||
icon: 'i-simple-icons-figma',
|
||||
label: 'Figma Kit',
|
||||
to: 'https://www.figma.com/community/file/1288455405058138934',
|
||||
to: 'https://www.figma.com/community/file/1436401057300493073',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Playground',
|
||||
|
||||
@@ -10,12 +10,34 @@
|
||||
}"
|
||||
>
|
||||
<template #left>
|
||||
<NuxtLink to="/" class="flex items-end gap-2 font-bold text-xl text-gray-900 dark:text-white min-w-0" aria-label="Nuxt UI">
|
||||
<NuxtLink to="/" class="flex items-end gap-2 text-xl text-gray-900 dark:text-white min-w-0 shrink-0" aria-label="Nuxt UI">
|
||||
<LogoPro v-if="$route.path.startsWith('/pro')" class="w-auto h-6 shrink-0" />
|
||||
<Logo v-else class="w-auto h-6 shrink-0" />
|
||||
|
||||
<UBadge :label="$route.path.startsWith('/pro') ? `v${pkg.version.split('-')[0]}` : `v${config.version}`" variant="subtle" size="xs" class="-mb-[2px] rounded font-semibold truncate hidden sm:inline-flex" />
|
||||
</NuxtLink>
|
||||
|
||||
<UDropdown
|
||||
:items="[[{ label: $route.path.startsWith('/pro') ? `v${pkg.version.split('-')[0]}` : `v${config.version}`, class: 'text-primary-500 dark:text-primary-400' }, { label: 'v3.x', to: 'https://ui.nuxt.com' }]]"
|
||||
:popper="{ strategy: 'absolute', offsetDistance: 11, placement: 'bottom-start' }"
|
||||
:ui="{
|
||||
background: 'dark:bg-gray-900',
|
||||
ring: 'dark:ring-gray-800',
|
||||
width: 'w-auto',
|
||||
item: {
|
||||
padding: 'p-1',
|
||||
size: 'text-xs',
|
||||
active: 'dark:bg-gray-800/50'
|
||||
}
|
||||
}"
|
||||
>
|
||||
<UButton
|
||||
:label="$route.path.startsWith('/pro') ? `v${pkg.version.split('-')[0]}` : `v${config.version}`"
|
||||
trailing-icon="i-lucide-chevron-down"
|
||||
variant="outline"
|
||||
size="2xs"
|
||||
truncate
|
||||
class="-mb-[6px] font-semibold rounded-full truncate ring-primary-500/25 dark:ring-primary-400/25 bg-primary-500/10 dark:bg-primary-400/10 hover:bg-primary-500/15 dark:hover:bg-primary-400/15 transition-colors"
|
||||
/>
|
||||
</UDropdown>
|
||||
</template>
|
||||
|
||||
<template #right>
|
||||
@@ -25,10 +47,10 @@
|
||||
<UContentSearchButton :label="null" />
|
||||
</UTooltip>
|
||||
|
||||
<UColorModeButton />
|
||||
<UColorModeButton class="hidden lg:inline-flex" />
|
||||
|
||||
<UButton
|
||||
to="https://github.com/nuxt/ui"
|
||||
to="https://github.com/nuxt/ui/tree/v2"
|
||||
target="_blank"
|
||||
icon="i-simple-icons-github"
|
||||
aria-label="GitHub"
|
||||
|
||||
@@ -9,7 +9,7 @@ onMounted(() => {
|
||||
if (carbonads.value) {
|
||||
const script = document.createElement('script')
|
||||
script.setAttribute('type', 'text/javascript')
|
||||
script.setAttribute('src', 'https://cdn.carbonads.com/carbon.js?serve=CWYIVK3E&placement=uinuxtcom')
|
||||
script.setAttribute('src', 'https://cdn.carbonads.com/carbon.js?serve=CW7IC53I&placement=ui2nuxtcom')
|
||||
script.setAttribute('id', '_carbonads_js')
|
||||
carbonads.value.appendChild(script)
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const ui = {
|
||||
inactive: 'text-gray-400 dark:text-gray-500'
|
||||
},
|
||||
avatar: {
|
||||
size: '2xs' as const
|
||||
size: '2xs'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { sub, format, isSameDay, type Duration } from 'date-fns'
|
||||
import { sub, format, isSameDay } from 'date-fns'
|
||||
import type { Duration } from 'date-fns'
|
||||
|
||||
const ranges = [
|
||||
{ label: 'Last 7 days', duration: { days: 7 } },
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { object, string, nonempty, type Infer } from 'superstruct'
|
||||
import { object, string, nonempty } from 'superstruct'
|
||||
import type { Infer } from 'superstruct'
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
|
||||
const schema = object({
|
||||
|
||||
@@ -21,7 +21,7 @@ async function onSubmit(event: FormSubmitEvent<Schema>) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UForm :schema="v.safeParser(schema)" :state="state" class="space-y-4" @submit="onSubmit">
|
||||
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
|
||||
<UFormGroup label="Email" name="email">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormGroup>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { object, string, type InferType } from 'yup'
|
||||
import { object, string } from 'yup'
|
||||
import type { InferType } from 'yup'
|
||||
import type { FormSubmitEvent } from '#ui/types'
|
||||
|
||||
const schema = object({
|
||||
|
||||
15
docs/components/content/examples/InputExampleMaxLength.vue
Normal file
15
docs/components/content/examples/InputExampleMaxLength.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<UInput
|
||||
v-model="name"
|
||||
:maxlength="maxLength"
|
||||
>
|
||||
<template #trailing>
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">{{ name.length }}/{{ maxLength }}</span>
|
||||
</template>
|
||||
</UInput>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const name = ref('')
|
||||
const maxLength = 10
|
||||
</script>
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
// Columns
|
||||
const columns = [{
|
||||
key: 'select',
|
||||
class: 'w-2'
|
||||
}, {
|
||||
key: 'id',
|
||||
label: '#',
|
||||
sortable: true
|
||||
@@ -20,6 +23,7 @@ const columns = [{
|
||||
|
||||
const selectedColumns = ref(columns)
|
||||
const columnsTable = computed(() => columns.filter(column => selectedColumns.value.includes(column)))
|
||||
const excludeSelectColumn = computed(() => columns.filter(v => v.key !== 'select'))
|
||||
|
||||
// Selected Rows
|
||||
const selectedRows = ref([])
|
||||
@@ -153,7 +157,7 @@ const { data: todos, status } = await useLazyAsyncData<{
|
||||
</UButton>
|
||||
</UDropdown>
|
||||
|
||||
<USelectMenu v-model="selectedColumns" :options="columns" multiple>
|
||||
<USelectMenu v-model="selectedColumns" :options="excludeSelectColumn" multiple>
|
||||
<UButton
|
||||
icon="i-heroicons-view-columns"
|
||||
color="gray"
|
||||
|
||||
66
docs/components/content/examples/TableExampleContextmenu.vue
Normal file
66
docs/components/content/examples/TableExampleContextmenu.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
const people = [{
|
||||
id: 1,
|
||||
name: 'Lindsay Walton',
|
||||
title: 'Front-end Developer',
|
||||
email: 'lindsay.walton@example.com',
|
||||
role: 'Member'
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'Courtney Henry',
|
||||
title: 'Designer',
|
||||
email: 'courtney.henry@example.com',
|
||||
role: 'Admin'
|
||||
}, {
|
||||
id: 3,
|
||||
name: 'Tom Cook',
|
||||
title: 'Director of Product',
|
||||
email: 'tom.cook@example.com',
|
||||
role: 'Member'
|
||||
}, {
|
||||
id: 4,
|
||||
name: 'Whitney Francis',
|
||||
title: 'Copywriter',
|
||||
email: 'whitney.francis@example.com',
|
||||
role: 'Admin'
|
||||
}, {
|
||||
id: 5,
|
||||
name: 'Leonard Krasner',
|
||||
title: 'Senior Designer',
|
||||
email: 'leonard.krasner@example.com',
|
||||
role: 'Owner'
|
||||
}]
|
||||
|
||||
const virtualElement = ref({ getBoundingClientRect: () => ({}) })
|
||||
const contextMenuRow = ref()
|
||||
|
||||
function contextmenu(event: MouseEvent, row: any) {
|
||||
// Prevent the default context menu
|
||||
event.preventDefault()
|
||||
|
||||
virtualElement.value.getBoundingClientRect = () => ({
|
||||
width: 0,
|
||||
height: 0,
|
||||
top: event.clientY,
|
||||
left: event.clientX
|
||||
})
|
||||
|
||||
contextMenuRow.value = row
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<UTable :rows="people" @contextmenu.stop="contextmenu" />
|
||||
|
||||
<UContextMenu
|
||||
:virtual-element="virtualElement"
|
||||
:model-value="!!contextMenuRow"
|
||||
@update:model-value="contextMenuRow = null"
|
||||
>
|
||||
<div class="p-4">
|
||||
{{ contextMenuRow.id }} - {{ contextMenuRow.name }}
|
||||
</div>
|
||||
</UContextMenu>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
const people = [{
|
||||
id: 1,
|
||||
name: 'Lindsay Walton',
|
||||
title: 'Front-end Developer',
|
||||
email: 'lindsay.walton@example.com',
|
||||
role: 'Member'
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'Courtney Henry',
|
||||
title: 'Designer',
|
||||
email: 'courtney.henry@example.com',
|
||||
role: 'Admin'
|
||||
}, {
|
||||
id: 3,
|
||||
name: 'Tom Cook',
|
||||
title: 'Director of Product',
|
||||
email: 'tom.cook@example.com',
|
||||
role: 'Member'
|
||||
}, {
|
||||
id: 4,
|
||||
name: 'Whitney Francis',
|
||||
title: 'Copywriter',
|
||||
email: 'whitney.francis@example.com',
|
||||
role: 'Admin'
|
||||
}, {
|
||||
id: 5,
|
||||
name: 'Leonard Krasner',
|
||||
title: 'Senior Designer',
|
||||
email: 'leonard.krasner@example.com',
|
||||
role: 'Owner'
|
||||
}, {
|
||||
id: 6,
|
||||
name: 'Floyd Miles',
|
||||
title: 'Principal Designer',
|
||||
email: 'floyd.miles@example.com',
|
||||
role: 'Member'
|
||||
}]
|
||||
|
||||
const selected = ref([people[1]])
|
||||
|
||||
const columns = [{
|
||||
key: 'id',
|
||||
label: 'ID'
|
||||
}, {
|
||||
key: 'name',
|
||||
label: 'User name'
|
||||
}, {
|
||||
key: 'title',
|
||||
label: 'Job position'
|
||||
}, {
|
||||
key: 'email',
|
||||
label: 'Email'
|
||||
}, {
|
||||
key: 'role'
|
||||
}, {
|
||||
key: 'select',
|
||||
class: 'w-2'
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable v-model="selected" :rows="people" :columns="columns" />
|
||||
</template>
|
||||
@@ -32,6 +32,11 @@ const attrs = {
|
||||
'is-dark': { selector: 'html', darkClass: 'dark' },
|
||||
'first-day-of-week': 2
|
||||
}
|
||||
|
||||
function onDayClick(_: any, event: MouseEvent): void {
|
||||
const target = event.target as HTMLElement
|
||||
target.blur()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -40,11 +45,13 @@ const attrs = {
|
||||
v-model.range="date"
|
||||
:columns="2"
|
||||
v-bind="{ ...attrs, ...$attrs }"
|
||||
@dayclick="onDayClick"
|
||||
/>
|
||||
<VCalendarDatePicker
|
||||
v-else
|
||||
v-model="date"
|
||||
v-bind="{ ...attrs, ...$attrs }"
|
||||
@dayclick="onDayClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ULandingGrid ref="section" class="lg:grid-cols-10 lg:gap-8 overflow-hidden p-px">
|
||||
<ULandingGrid ref="section" class="lg:grid-cols-10 lg:gap-8 overflow-hidden p-1">
|
||||
<div :ref="(el) => (refs[1] = el)" class="col-span-8 flex items-center animate-top">
|
||||
<RangeExample />
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ Its goal is to provide everything related to UI when building a Nuxt app. This i
|
||||
- Keyboard shortcuts
|
||||
- Bundled icons
|
||||
- Fully typed
|
||||
- [Figma Kit](https://www.figma.com/community/file/1288455405058138934)
|
||||
- [Figma Kit](https://www.figma.com/community/file/1436401057300493073)
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -7,13 +7,29 @@ description: 'Learn how to install and configure Nuxt UI in your application.'
|
||||
|
||||
### Add to a Nuxt project
|
||||
|
||||
1. Add `@nuxt/ui` module to your project:
|
||||
1. Install the `@nuxt/ui` dependency in your project:
|
||||
|
||||
```bash
|
||||
npx nuxi@latest module add ui
|
||||
::code-group
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm add @nuxt/ui@2
|
||||
```
|
||||
|
||||
2. Add it to the `modules` section in your `nuxt.config.ts`:
|
||||
```bash [yarn]
|
||||
yarn add @nuxt/ui@2
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @nuxt/ui@2
|
||||
```
|
||||
|
||||
```bash [bun]
|
||||
bun add @nuxt/ui@2
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
2. Register the `@nuxt/ui` module in your `nuxt.config.ts`:
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
@@ -29,7 +45,7 @@ That's it! You can now use all the components and composables in your Nuxt app
|
||||
The Nuxt Starter template is available from the `nuxi init` command.
|
||||
|
||||
```bash
|
||||
npx nuxi@latest init -t ui
|
||||
npx nuxi@latest init -t ui2
|
||||
```
|
||||
|
||||
Please check [nuxt/starter](https://github.com/nuxt/starter/tree/ui) for details.
|
||||
@@ -94,7 +110,7 @@ You can read more about this in the [Theming](/getting-started/theming#dark-mode
|
||||
|
||||
## TypeScript
|
||||
|
||||
This module is written in TypeScript and provides typings for all the components and composables. You can look at the [source code](https://github.com/nuxt/ui/tree/dev/src/runtime/types) to see all the available types.
|
||||
This module is written in TypeScript and provides typings for all the components and composables. You can look at the [source code](https://github.com/nuxt/ui/tree/v2/src/runtime/types) to see all the available types.
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb" to="https://nuxt.com/docs/guide/concepts/typescript" target="_blank"}
|
||||
You can read more about TypeScript on the official Nuxt documentation.
|
||||
@@ -230,7 +246,7 @@ You can also add the following to your `.vscode/settings.json` to enable Intelli
|
||||
| `prefix` | `u` | Define the prefix of the imported components. |
|
||||
| `global` | `false` | Expose components globally. |
|
||||
| `safelistColors` | `['primary']` | Force safelisting of colors to need be purged. |
|
||||
| `disableGlobalStyles` | `false` | Disable [global CSS styles](https://github.com/nuxt/ui/blob/dev/src/runtime/ui.css) injected by the module. |
|
||||
| `disableGlobalStyles` | `false` | Disable [global CSS styles](https://github.com/nuxt/ui/blob/v2/src/runtime/ui.css) injected by the module. |
|
||||
|
||||
Configure options in your `nuxt.config.ts` as such:
|
||||
|
||||
@@ -243,19 +259,21 @@ export default defineNuxtConfig({
|
||||
})
|
||||
```
|
||||
|
||||
## Edge
|
||||
## Continuous Releases
|
||||
|
||||
To use the latest updates pushed on the [`dev`](https://github.com/nuxt/ui/tree/dev) branch, you can use `@nuxt/ui-edge`.
|
||||
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.
|
||||
|
||||
Update your `package.json` to the following:
|
||||
Preview releases are automatically generated for every commit to the `dev` branch and pull requests targeting the `dev` branch. To use it into your project, replace the version in your `package.json` with the commit hash or pull request number.
|
||||
|
||||
```diff [package.json]
|
||||
{
|
||||
"devDependencies": {
|
||||
- "@nuxt/ui": "^2.11.0"
|
||||
+ "@nuxt/ui": "npm:@nuxt/ui-edge@latest"
|
||||
"dependencies": {
|
||||
- "@nuxt/ui": "^2.21.0",
|
||||
+ "@nuxt/ui": "https://pkg.pr.new/@nuxt/ui@bf1c9e7",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run `pnpm install`, `yarn install` or `npm install`.
|
||||
::note
|
||||
**pkg.pr.new** will automatically comment on PRs with the installation URL, making it easy to test changes.
|
||||
::
|
||||
|
||||
@@ -25,7 +25,7 @@ Try to change the `primary` and `gray` colors by clicking on the :u-icon{name="i
|
||||
|
||||
As this module uses Tailwind CSS under the hood, you can use any of the [Tailwind CSS colors](https://tailwindcss.com/docs/customizing-colors#color-palette-reference) or your own custom colors or groups, such as `brand.primary`. By default, the `primary` color is `green` and the `gray` color is `cool`.
|
||||
|
||||
When [using custom colors](https://tailwindcss.com/docs/customizing-colors#using-custom-colors) or [adding additional colors](https://tailwindcss.com/docs/customizing-colors#adding-additional-colors) through the `extend` key in your `tailwind.config.ts`, you'll need to make sure to define all the shades from `50` to `950` as most of them are used in the components config defined in [`ui.config/`](https://github.com/nuxt/ui/tree/dev/src/runtime/ui.config) directory. You can [generate your colors](https://tailwindcss.com/docs/customizing-colors#generating-colors) using tools such as https://uicolors.app/ for example.
|
||||
When [using custom colors](https://tailwindcss.com/docs/customizing-colors#using-custom-colors) or [adding additional colors](https://tailwindcss.com/docs/customizing-colors#adding-additional-colors) through the `extend` key in your `tailwind.config.ts`, you'll need to make sure to define all the shades from `50` to `950` as most of them are used in the components config defined in [`ui.config/`](https://github.com/nuxt/ui/tree/v2/src/runtime/ui.config) directory. You can [generate your colors](https://tailwindcss.com/docs/customizing-colors#generating-colors) using tools such as https://uicolors.app/ for example.
|
||||
|
||||
```ts [tailwind.config.ts]
|
||||
import type { Config } from 'tailwindcss'
|
||||
@@ -118,7 +118,7 @@ export default defineAppConfig({
|
||||
})
|
||||
```
|
||||
|
||||
The available options for each component should auto-complete, and you can review the defaults for each component using your IDE's function such as `Cmd`+`Click` (these files can be found in [`src/runtime/ui.config/`](https://github.com/nuxt/ui/tree/dev/src/runtime/ui.config)).
|
||||
The available options for each component should auto-complete, and you can review the defaults for each component using your IDE's function such as `Cmd`+`Click` (these files can be found in [`src/runtime/ui.config/`](https://github.com/nuxt/ui/tree/v2/src/runtime/ui.config)).
|
||||
|
||||
Thanks to [tailwind-merge](https://github.com/dcastil/tailwind-merge), the `app.config.ts` is smartly merged with the default config. This means you don't have to rewrite everything.
|
||||
|
||||
@@ -221,6 +221,52 @@ export default defineAppConfig({
|
||||
})
|
||||
```
|
||||
|
||||
### Extend Tailwind Merge
|
||||
|
||||
Tailwind Merge is a library that allows you to efficiently merge Tailwind CSS classes. It is used by this module to merge the classes from the `ui` prop, the `class` attribute, and the default classes.
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb" to="https://github.com/dcastil/tailwind-merge" target="_blank"}
|
||||
Learn more about Tailwind Merge.
|
||||
::
|
||||
|
||||
By default, Tailwind Merge doesn't handle custom Tailwind CSS configuration like custom colors, spacing, or other utilities you may have defined. You'll need to extend it to handle your custom configuration.
|
||||
|
||||
You can extend Tailwind Merge by using the `tailwindMerge` option in your `app.config.ts`:
|
||||
|
||||
::code-group
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
tailwindMerge: {
|
||||
extend: {
|
||||
theme: {
|
||||
spacing: ['sm', 'md', 'lg', 'xl', '2xl']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```ts [tailwind.config.ts]
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
export default <Partial<Config>>{
|
||||
theme: {
|
||||
extend: {
|
||||
spacing: {
|
||||
sm: '0.5rem',
|
||||
md: '1rem',
|
||||
lg: '1.5rem',
|
||||
xl: '2rem',
|
||||
'2xl': '2.5rem'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
::
|
||||
|
||||
## Dark mode
|
||||
|
||||
All the components are styled with dark mode in mind.
|
||||
@@ -343,6 +389,12 @@ export default defineAppConfig({
|
||||
loadingIcon: 'i-octicon-sync-24'
|
||||
}
|
||||
},
|
||||
inputMenu: {
|
||||
default: {
|
||||
selectedIcon: 'i-octicon-check-24',
|
||||
trailingIcon: 'i-octicon-chevron-down-24'
|
||||
}
|
||||
},
|
||||
select: {
|
||||
default: {
|
||||
loadingIcon: 'i-octicon-sync-24',
|
||||
@@ -378,6 +430,9 @@ export default defineAppConfig({
|
||||
sortButton: {
|
||||
icon: 'i-octicon-arrow-switch-24'
|
||||
},
|
||||
expandButton: {
|
||||
icon: 'i-octicon-chevron-down-24'
|
||||
},
|
||||
loadingState: {
|
||||
icon: 'i-octicon-sync-24'
|
||||
},
|
||||
@@ -411,6 +466,21 @@ export default defineAppConfig({
|
||||
default: {
|
||||
divider: 'i-octicon-chevron-right-24'
|
||||
}
|
||||
},
|
||||
carousel: {
|
||||
default: {
|
||||
prevButton: {
|
||||
icon: 'i-octicon-chevron-left-24'
|
||||
},
|
||||
nextButton: {
|
||||
icon: 'i-octicon-chevron-right-24'
|
||||
}
|
||||
}
|
||||
},
|
||||
toggle: {
|
||||
default: {
|
||||
loadingIcon: 'i-octicon-sync-24'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -49,18 +49,22 @@ defineShortcuts({
|
||||
Shortcuts keys are written as the literal keyboard key value. Combinations are made with `_` separator. Chained shortcuts are made with `-` separator.
|
||||
|
||||
Modifiers are also available:
|
||||
- `meta`: acts as `Command` for MacOS and `Control` for others
|
||||
- `ctrl`: acts as `Control`
|
||||
- `shift`: acts as `Shift` and is only necessary for alphabetic keys
|
||||
| Modifier | Description |
|
||||
|----------|-------------|
|
||||
| `meta` | Acts as `Command (⌘)` on macOS and `Control (Ctrl)` on Windows/Linux. |
|
||||
| `ctrl` | Represents the `Control (Ctrl)` key across all operating systems. |
|
||||
| `shift` | Represents the `Shift` key, only needed for alphabetic keys (e.g., `shift_e`). |
|
||||
|
||||
Examples of keys:
|
||||
- `escape`: will trigger by hitting `Esc`
|
||||
- `meta_k`: will trigger by hitting `⌘` and `K` at the same time on MacOS, and `Ctrl` and `K` on Windows and Linux
|
||||
- `ctrl_k`: will trigger by hitting `Ctrl` and `K` at the same time on MacOS, Windows and Linux
|
||||
- `shift_e`: will trigger by hitting `Shift` and `E` at the same time on MacOS, Windows and Linux
|
||||
- `?`: will trigger by hitting `?` on some keyboard layouts, or for example `Shift` and `/`, which results in `?` on US Mac keyboards
|
||||
- `g-d`: will trigger by hitting `g` then `d` with a maximum delay of 800ms by default
|
||||
- `arrowleft`: will trigger by hitting `←` (also: `arrowright`, `arrowup`, `arrowdown`)
|
||||
| Shortcut Key | Action |
|
||||
|---------------|--------|
|
||||
| `escape` | Triggers when `Esc` is pressed |
|
||||
| `meta_k` | `⌘ + K` on Mac, `Ctrl + K` on Windows/Linux |
|
||||
| `ctrl_k` | Triggers `Ctrl + K` on all OS |
|
||||
| `shift_e` | Triggers `Shift + E` on all OS |
|
||||
| `?` | Triggers `?` (Shift + `/` on US Mac keyboards) |
|
||||
| `g-d` | Triggers when `g` then `d` are pressed within 800ms |
|
||||
| `arrowleft` | Triggers when `←` is pressed (also: `arrowright`, `arrowup`, `arrowdown`) |
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
For a complete list of available shortcut keys, refer to the [`KeyboardEvent`](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values) API docs. Note the `KeyboardEvent.key` has to be written in lowercase.
|
||||
|
||||
@@ -6,7 +6,7 @@ links:
|
||||
to: 'https://headlessui.com/v1/vue/disclosure'
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Accordion.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Accordion.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display an alert element to draw attention.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Alert.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Alert.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display an image that represents a resource or a group of resources
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Avatar.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Avatar.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a short text to represent a status or a category.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Badge.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Badge.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -141,6 +141,74 @@ Badge
|
||||
You can customize the whole [preset](#preset) by using the `ui` prop.
|
||||
::
|
||||
|
||||
### Icon
|
||||
|
||||
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
||||
|
||||
Use the `leading` and `trailing` props to set the icon position or the `leading-icon` and `trailing-icon` props to set a different icon for each position.
|
||||
|
||||
::component-card
|
||||
---
|
||||
props:
|
||||
icon: 'i-heroicons-rocket-launch'
|
||||
size: 'sm'
|
||||
color: 'primary'
|
||||
variant: 'solid'
|
||||
label: Badge
|
||||
trailing: false
|
||||
options:
|
||||
- name: variant
|
||||
restriction: only
|
||||
values:
|
||||
- solid
|
||||
excludedProps:
|
||||
- icon
|
||||
- label
|
||||
---
|
||||
::
|
||||
|
||||
## Slots
|
||||
|
||||
### `leading`
|
||||
|
||||
Use the `#leading` slot to set the content of the leading icon.
|
||||
|
||||
::component-card
|
||||
---
|
||||
slots:
|
||||
leading: <UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs" />
|
||||
baseProps:
|
||||
color: 'gray'
|
||||
props:
|
||||
label: Badge
|
||||
color: 'gray'
|
||||
excludedProps:
|
||||
- color
|
||||
---
|
||||
|
||||
#leading
|
||||
:u-avatar{src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs"}
|
||||
::
|
||||
|
||||
### `trailing`
|
||||
|
||||
Use the `#trailing` slot to set the content of the trailing icon.
|
||||
|
||||
::component-card
|
||||
---
|
||||
slots:
|
||||
trailing: <UIcon name="i-heroicons-rocket-launch" class="w-4 h-4" />
|
||||
props:
|
||||
label: Badge
|
||||
color: 'gray'
|
||||
excludedProps:
|
||||
- color
|
||||
---
|
||||
|
||||
#trailing
|
||||
:u-icon{name="i-heroicons-rocket-launch" class="w-4 h-4"}
|
||||
::
|
||||
|
||||
## Props
|
||||
|
||||
:component-props
|
||||
|
||||
@@ -4,7 +4,7 @@ description: A list of links that indicate the current page's location within a
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/navigation/Breadcrumb.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/navigation/Breadcrumb.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Create a button with icon or link capabilities.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Button.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Button.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a card for content with a header, body and footer.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/layout/Card.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/layout/Card.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display images or content in a scrollable area.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Carousel.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Carousel.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a checkbox field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Checkbox.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/Checkbox.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -87,7 +87,7 @@ slots:
|
||||
[Label]{.italic}
|
||||
::
|
||||
|
||||
### `help` :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
|
||||
### `help`
|
||||
|
||||
Like the `#label` slot, use the `#help` slot to override the content of the help text.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a chip indicator on any component.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Chip.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Chip.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -7,7 +7,7 @@ links:
|
||||
to: 'https://headlessui.com/v1/vue/combobox'
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/navigation/CommandPalette.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/navigation/CommandPalette.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -274,7 +274,7 @@ hiddenCode: true
|
||||
---
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/CommandPaletteExampleThemeAlgolia.vue#L23" target="_blank"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/v2/docs/components/content/examples/CommandPaletteExampleThemeAlgolia.vue#L23" target="_blank"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
@@ -290,6 +290,6 @@ hiddenCode: true
|
||||
---
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/CommandPaletteExampleThemeRaycast.vue#L30" target="_blank"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/v2/docs/components/content/examples/CommandPaletteExampleThemeRaycast.vue#L30" target="_blank"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
@@ -3,7 +3,7 @@ description: A container lets you center and constrain the width of your content
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/layout/Container.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/layout/Container.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Display a menu that appears on right click.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/overlays/ContextMenu.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/overlays/ContextMenu.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -70,6 +70,11 @@ const attrs = {
|
||||
'is-dark': { selector: 'html', darkClass: 'dark' },
|
||||
'first-day-of-week': 2
|
||||
}
|
||||
|
||||
function onDayClick(_: any, event: MouseEvent): void {
|
||||
const target = event.target as HTMLElement
|
||||
target.blur()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -78,11 +83,13 @@ const attrs = {
|
||||
v-model.range="date"
|
||||
:columns="2"
|
||||
v-bind="{ ...attrs, ...$attrs }"
|
||||
@dayclick="onDayClick"
|
||||
/>
|
||||
<VCalendarDatePicker
|
||||
v-else
|
||||
v-model="date"
|
||||
v-bind="{ ...attrs, ...$attrs }"
|
||||
@dayclick="onDayClick"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a separator between content.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/layout/Divider.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/layout/Divider.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -6,7 +6,7 @@ links:
|
||||
to: https://headlessui.com/v1/vue/menu
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Dropdown.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Dropdown.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Display a label and additional informations around a form element.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/FormGroup.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/FormGroup.vue
|
||||
---
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Collect and validate form data.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Form.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/Form.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -14,7 +14,7 @@ It works with the [FormGroup](/components/form-group) component to display error
|
||||
|
||||
The form component requires two props:
|
||||
- `state` - a reactive object holding the form's state.
|
||||
- `schema` - a schema object from a validation library like [Yup](https://github.com/jquense/yup), [Zod](https://github.com/colinhacks/zod), [Joi](https://github.com/hapijs/joi), [Valibot](https://github.com/fabian-hiller/valibot) or [Superstruct](https://github.com/ianstormtaylor/superstruct).
|
||||
- `schema` - any [Standard Schema](https://standardschema.dev/) or a schema from [Yup](https://github.com/jquense/yup), [Joi](https://github.com/hapijs/joi) or [Superstruct](https://github.com/ianstormtaylor/superstruct).
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
Note that **no validation library is included** by default, so ensure you **install the one you need**.
|
||||
@@ -190,7 +190,7 @@ hiddenCode: true
|
||||
---
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/FormExampleElements.vue" target="_blank"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/v2/docs/components/content/examples/FormExampleElements.vue" target="_blank"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Display a list of horizontal links.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/navigation/HorizontalNavigation.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/navigation/HorizontalNavigation.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -7,7 +7,7 @@ links:
|
||||
to: 'https://headlessui.com/v1/vue/combobox'
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/InputMenu.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/InputMenu.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display an input field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Input.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/Input.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -142,7 +142,7 @@ props:
|
||||
|
||||
### Loading
|
||||
|
||||
Use the `loading` prop to show a loading icon and disable the Input.
|
||||
Use the `loading` prop to show a loading icon in the Input.
|
||||
|
||||
Use the `loading-icon` prop to set a different icon or change it globally in `ui.input.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.
|
||||
|
||||
@@ -173,6 +173,13 @@ baseProps:
|
||||
---
|
||||
::
|
||||
|
||||
### Limit
|
||||
|
||||
Use the `maxlength` prop to limit the length of the Input.
|
||||
|
||||
:component-example{component="input-example-max-length"}
|
||||
|
||||
|
||||
## Slots
|
||||
|
||||
### `leading`
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Display a keyboard key in a text block.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Kbd.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Kbd.vue
|
||||
navigation:
|
||||
title: 'Kbd'
|
||||
---
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Render a NuxtLink but with superpowers.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Link.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Link.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -14,6 +14,7 @@ The Link component is a wrapper around [`<NuxtLink>`](https://nuxt.com/docs/api/
|
||||
- `inactive-class` prop to set a class when the link is inactive, `active-class` is used when active.
|
||||
- `exact` prop to style with `active-class` when the link is active and the route is exactly the same as the current route.
|
||||
- `exact-query` and `exact-hash` props to style with `active-class` when the link is active and the query or hash is exactly the same as the current query or hash.
|
||||
- use `exact-query="partial"` to style with `active-class` when the link is active and the query partially match the current query.
|
||||
|
||||
The incentive behind this is to provide the same API as NuxtLink back in Nuxt 2 / Vue 2. You can read more about it in the Vue Router [migration from Vue 2](https://router.vuejs.org/guide/migration/#removal-of-the-exact-prop-in-router-link) guide.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Display a gauge meter that fills or depletes.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Meter.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Meter.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -6,7 +6,7 @@ links:
|
||||
to: 'https://headlessui.com/v1/vue/dialog'
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/overlays/Modal.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/overlays/Modal.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a toast notification in your app.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/overlays/Notification.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/overlays/Notification.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -137,9 +137,9 @@ excludedProps:
|
||||
|
||||
### Timeout
|
||||
|
||||
Use the `timeout` prop to configure how long the Notification will remain. The default value is `5000`, set it to `0` to disable the timeout.
|
||||
Use the `timeout` prop to configure how long the Notification will remain. The default value is `5000`, set it to `0` to disable the timeout. The `pauseTimeoutOnHover` prop (`true` by default) controls whether hovering the notification should pause the timeout.
|
||||
|
||||
You will see a progress bar at the bottom of the Notification which will indicate the remaining time. When hovering the Notification, the progress bar will be paused.
|
||||
You will see a progress bar at the bottom of the Notification which will indicate the remaining time. When hovering the Notification, the progress bar will be paused if `pauseTimeoutOnHover` is enabled; otherwise, it won't stop.
|
||||
|
||||
::component-card
|
||||
---
|
||||
@@ -149,6 +149,7 @@ baseProps:
|
||||
description: 'This is a notification.'
|
||||
props:
|
||||
timeout: 60000
|
||||
pauseTimeoutOnHover: true
|
||||
---
|
||||
::
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Add a pagination to handle pages.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/navigation/Pagination.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/navigation/Pagination.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -6,7 +6,7 @@ links:
|
||||
to: 'https://headlessui.com/v1/vue/popover'
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/overlays/Popover.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/overlays/Popover.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Show a horizontal bar to indicate task progression.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/elements/Progress.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/elements/Progress.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Display a set of radio buttons.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/RadioGroup.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/RadioGroup.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -126,7 +126,7 @@ slots:
|
||||
[Label]{.italic}
|
||||
::
|
||||
|
||||
### `help` :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
|
||||
### `help`
|
||||
|
||||
Like the `#label` slot, use the `#help` slot to override the content of the help text.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a range field
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Range.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/Range.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -7,7 +7,7 @@ links:
|
||||
to: 'https://headlessui.com/v1/vue/listbox'
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/SelectMenu.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/SelectMenu.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -188,7 +188,7 @@ componentProps:
|
||||
---
|
||||
::
|
||||
|
||||
Pass a function to the `show-create-option-when` prop to control wether or not to show the create option. This function takes two arguments: the query (as the first argument) and an array of current results (as the second argument). It should return true to display the create option. :u-badge{label="New" class="!rounded-full" variant="subtle"}
|
||||
Pass a function to the `show-create-option-when` prop to control wether or not to show the create option. This function takes two arguments: the query (as the first argument) and an array of current results (as the second argument). It should return true to display the create option.
|
||||
|
||||
The example below shows how to make the create option visible when the query is at least three characters long and does not exactly match any of the current results (case insensitive).
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a select field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Select.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/Select.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a placeholder while content is loading.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/layout/Skeleton.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/layout/Skeleton.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -6,7 +6,7 @@ links:
|
||||
to: 'https://headlessui.com/v1/vue/dialog'
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/overlays/Slideover.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/overlays/Slideover.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: 'Display data in a table.'
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/data/Table.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/data/Table.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -29,7 +29,7 @@ Use the `columns` prop to configure which columns to display. It's an array of o
|
||||
- `sortable` - Whether the column is sortable. Defaults to `false`.
|
||||
- `direction` - The sort direction to use on first click. Defaults to `asc`.
|
||||
- `class` - The class to apply to the column cells.
|
||||
- `rowClass` - The class to apply to the data column cells. :u-badge{label="New" class="!rounded-full" variant="subtle"}
|
||||
- `rowClass` - The class to apply to the data column cells.
|
||||
- `sort` - Pass your own `sort` function. Defaults to a simple _greater than_ / _less than_ comparison.
|
||||
|
||||
Arguments for the `sort` function are: Value A, Value B, Direction - 'asc' or 'desc'
|
||||
@@ -62,7 +62,7 @@ extraClass: 'overflow-hidden'
|
||||
padding: false
|
||||
component: 'table-example-columns-selectable'
|
||||
componentProps:
|
||||
class: 'flex-1 flex-col overflow-hidden'
|
||||
class: 'flex-1 flex-col overflow-hidden min-h-[230px]'
|
||||
---
|
||||
::
|
||||
|
||||
@@ -285,6 +285,81 @@ componentProps:
|
||||
---
|
||||
::
|
||||
|
||||
|
||||
#### Event Selectable
|
||||
The `UTable` component provides two key events for handling row selection:
|
||||
|
||||
##### ***@select:all***
|
||||
The `@select:all` event is emitted when the header checkbox in a selectable table is toggled. This event returns a boolean value indicating whether all rows are selected (true) or deselected (false).
|
||||
|
||||
##### ***@update:modelValue***
|
||||
The `@update:modelValue` event is emitted whenever the selection state changes, including both individual row selection and bulk selection. This event returns an array containing the currently selected rows.
|
||||
|
||||
Here's how to implement both events:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const selected = ref([])
|
||||
|
||||
const onHandleSelectAll = (isSelected: boolean) => {
|
||||
console.log('All rows selected:', isSelected)
|
||||
}
|
||||
|
||||
const onUpdateSelection = (selectedRows: any[]) => {
|
||||
console.log('Currently selected rows:', selectedRows)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable
|
||||
v-model="selected"
|
||||
:rows="people"
|
||||
@select:all="onHandleSelectAll"
|
||||
@update:modelValue="onUpdateSelection"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
|
||||
#### Single Select Mode
|
||||
Control how the select function allows only one row to be selected at a time.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<!-- Allow only one row to be selectable at a time -->
|
||||
<UTable :single-select="true" />
|
||||
</template>
|
||||
```
|
||||
|
||||
#### Checkbox Placement
|
||||
You can customize the checkbox column position by using the `select` key in the `columns` configuration.
|
||||
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
extraClass: 'overflow-hidden'
|
||||
padding: false
|
||||
component: 'table-example-dynamically-render-selectable'
|
||||
componentProps:
|
||||
class: 'flex-1'
|
||||
---
|
||||
::
|
||||
|
||||
### Contextmenu
|
||||
|
||||
Use the `contextmenu` listener on your Table to make the rows right-clickable. The function will receive the original event as the first argument and the row as the second argument.
|
||||
|
||||
You can use this to open a [ContextMenu](/components/context-menu) for that row.
|
||||
|
||||
::component-example{class="grid"}
|
||||
---
|
||||
extraClass: 'overflow-hidden'
|
||||
padding: false
|
||||
component: 'table-example-contextmenu'
|
||||
componentProps:
|
||||
class: 'flex-1 flex-col overflow-hidden'
|
||||
---
|
||||
::
|
||||
|
||||
### Searchable
|
||||
|
||||
You can easily use the [Input](/components/input) component to filter the rows.
|
||||
@@ -313,7 +388,7 @@ componentProps:
|
||||
---
|
||||
::
|
||||
|
||||
### Expandable :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
|
||||
### Expandable
|
||||
|
||||
You can use the `v-model:expand` to enables row expansion functionality in the table component. It maintains an object containing an `openedRows` an array and `row` an object, which tracks the indices of currently expanded rows.
|
||||
|
||||
@@ -377,7 +452,6 @@ Controls whether multiple rows can be expanded simultaneously in the table.
|
||||
<!-- Or simply -->
|
||||
<UTable />
|
||||
</template>
|
||||
|
||||
```
|
||||
|
||||
#### Disable Row Expansion
|
||||
@@ -518,6 +592,82 @@ componentProps:
|
||||
---
|
||||
::
|
||||
|
||||
### `select-header`
|
||||
This slot allows you to customize the checkbox appearance in the table header for selecting all rows at once while using feature [Selectable](#selectable).
|
||||
|
||||
#### Usage
|
||||
```vue
|
||||
<template>
|
||||
<UTable v-model="selectable">
|
||||
<template #select-header="{ checked, change, indeterminate }">
|
||||
<!-- Place your custom component here -->
|
||||
</template>
|
||||
</UTable>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### Props
|
||||
|
||||
| Prop | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `checked` | `Boolean` | Indicates if all rows are selected |
|
||||
| `change` | `Function` | Function to handle selection state changes. Must receive a boolean value (true/false) |
|
||||
| `indeterminate` | `Boolean` | Indicates partial selection (when some rows are selected) |
|
||||
|
||||
#### Example
|
||||
```vue
|
||||
<template>
|
||||
<UTable>
|
||||
<!-- Header checkbox customization -->
|
||||
<template #select-header="{ indeterminate, checked, change }">
|
||||
<input
|
||||
type="checkbox"
|
||||
:indeterminate="indeterminate"
|
||||
:checked="checked"
|
||||
@change="e => change(e.target.checked)"
|
||||
/>
|
||||
</template>
|
||||
</UTable>
|
||||
</template>
|
||||
```
|
||||
|
||||
### `select-data`
|
||||
This slot allows you to customize the checkbox appearance for each row in the table while using feature [Selectable](#selectable).
|
||||
|
||||
#### Usage
|
||||
```vue
|
||||
<template>
|
||||
<UTable v-model="selectable">
|
||||
<template #select-data="{ checked, change }">
|
||||
<!-- Place your custom component here -->
|
||||
</template>
|
||||
</UTable>
|
||||
</template>
|
||||
```
|
||||
|
||||
#### Props
|
||||
|
||||
| Prop | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `checked` | `Boolean` | Indicates if the current row is selected |
|
||||
| `change` | `Function` | Function to handle selection state changes. Must receive a boolean value (true/false) |
|
||||
|
||||
#### Example
|
||||
```vue
|
||||
<template>
|
||||
<UTable>
|
||||
<!-- Row checkbox customization -->
|
||||
<template #select-data="{ checked, change }">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="checked"
|
||||
@change="e => change(e.target.checked)"
|
||||
/>
|
||||
</template>
|
||||
</UTable>
|
||||
</template>
|
||||
```
|
||||
|
||||
### `expand-action`
|
||||
|
||||
The `#expand-action` slot allows you to customize the expansion control interface for expandable table rows. This feature provides a flexible way to implement custom expand/collapse functionality while maintaining access to essential row data and state.
|
||||
@@ -619,6 +769,6 @@ hiddenCode: true
|
||||
---
|
||||
::
|
||||
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/TableExampleAdvanced.vue" target="_blank"}
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/v2/docs/components/content/examples/TableExampleAdvanced.vue" target="_blank"}
|
||||
Take a look at the component!
|
||||
::
|
||||
|
||||
@@ -3,7 +3,7 @@ description: A set of tab panels that are displayed one at a time.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/navigation/Tabs.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/navigation/Tabs.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
@@ -92,7 +92,7 @@ Use the `#default` slot to customize the content of the trigger buttons. You wil
|
||||
|
||||
:component-example{component="tabs-example-default-slot"}
|
||||
|
||||
### `icon` :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
|
||||
### `icon`
|
||||
|
||||
Use the `#icon` slot to customize the icon of the trigger buttons. You will have access to the `item`, `index`, `selected` and `disabled` in the slot scope.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display a textarea field.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Textarea.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/Textarea.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -6,7 +6,7 @@ links:
|
||||
to: 'https://headlessui.com/v1/vue/switch'
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Toggle.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/forms/Toggle.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ description: Display content that appears on hover next to an element.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/overlays/Tooltip.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/overlays/Tooltip.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -4,7 +4,7 @@ description: Display a list of vertical links.
|
||||
links:
|
||||
- label: GitHub
|
||||
icon: i-simple-icons-github
|
||||
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/navigation/VerticalNavigation.vue
|
||||
to: https://github.com/nuxt/ui/blob/v2/src/runtime/components/navigation/VerticalNavigation.vue
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -3,7 +3,7 @@ title: '<span class="text-primary">Nuxt UI</span> Releases'
|
||||
head.title: Releases
|
||||
description: Follow the latest releases and updates happening on the nuxt/ui repository.
|
||||
links:
|
||||
- label: Get Started
|
||||
- label: Get started
|
||||
trailingIcon: i-heroicons-arrow-right-20-solid
|
||||
to: /getting-started
|
||||
size: md
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<div>
|
||||
<NuxtLoadingIndicator />
|
||||
|
||||
<Banner />
|
||||
|
||||
<Header :links="links" />
|
||||
|
||||
<UContainer>
|
||||
|
||||
@@ -15,7 +15,7 @@ export default defineNuxtConfig({
|
||||
]
|
||||
: [
|
||||
'@nuxt/ui-pro',
|
||||
process.env.NUXT_GITHUB_TOKEN && ['github:nuxt/ui-pro/.docs#dev', { giget: { auth: process.env.NUXT_GITHUB_TOKEN } }]
|
||||
process.env.NUXT_GITHUB_TOKEN && ['github:nuxt/ui-pro/.docs#v1', { giget: { auth: process.env.NUXT_GITHUB_TOKEN } }]
|
||||
].filter(Boolean),
|
||||
|
||||
modules: [
|
||||
@@ -26,13 +26,11 @@ export default defineNuxtConfig({
|
||||
module,
|
||||
'@nuxtjs/plausible',
|
||||
'@vueuse/nuxt',
|
||||
'nuxt-component-meta',
|
||||
'nuxt-cloudflare-analytics',
|
||||
'modules/content-examples-code'
|
||||
'nuxt-component-meta'
|
||||
],
|
||||
|
||||
site: {
|
||||
url: 'https://ui.nuxt.com'
|
||||
url: 'https://ui2.nuxt.com'
|
||||
},
|
||||
|
||||
content: {
|
||||
@@ -54,7 +52,7 @@ export default defineNuxtConfig({
|
||||
prefix: '/pro',
|
||||
driver: 'github',
|
||||
repo: 'nuxt/ui-pro',
|
||||
branch: 'dev',
|
||||
branch: 'v1',
|
||||
dir: '.docs/content/pro',
|
||||
token: process.env.NUXT_GITHUB_TOKEN || ''
|
||||
}
|
||||
@@ -95,6 +93,11 @@ export default defineNuxtConfig({
|
||||
vite: {
|
||||
optimizeDeps: {
|
||||
include: ['date-fns']
|
||||
},
|
||||
server: {
|
||||
fs: {
|
||||
allow: process.env.NUXT_UI_PRO_PATH ? [resolve(process.env.NUXT_UI_PRO_PATH)] : undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -115,11 +118,6 @@ export default defineNuxtConfig({
|
||||
}
|
||||
},
|
||||
|
||||
cloudflareAnalytics: {
|
||||
token: '1e2b0c5e9a214f0390b9b94e043d8d4c',
|
||||
scriptPath: false
|
||||
},
|
||||
|
||||
componentMeta: {
|
||||
exclude: [
|
||||
'@nuxt/content',
|
||||
|
||||
@@ -3,28 +3,28 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@iconify-json/heroicons": "^1.2.1",
|
||||
"@iconify-json/simple-icons": "^1.2.11",
|
||||
"@iconify-json/vscode-icons": "^1.2.2",
|
||||
"@iconify-json/heroicons": "^1.2.2",
|
||||
"@iconify-json/lucide": "^1.2.57",
|
||||
"@iconify-json/simple-icons": "^1.2.44",
|
||||
"@iconify-json/vscode-icons": "^1.2.23",
|
||||
"@nuxt/content": "^2.13.4",
|
||||
"@nuxt/fonts": "^0.10.2",
|
||||
"@nuxt/image": "^1.8.1",
|
||||
"@nuxt/fonts": "^0.11.4",
|
||||
"@nuxt/image": "^1.10.0",
|
||||
"@nuxt/ui": "latest",
|
||||
"@nuxt/ui-pro": "npm:@nuxt/ui-pro-edge@1.4.4-28846941.4241122",
|
||||
"@nuxtjs/plausible": "^1.0.3",
|
||||
"@octokit/rest": "^21.0.2",
|
||||
"@vueuse/nuxt": "^11.2.0",
|
||||
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@fdb0248",
|
||||
"@nuxtjs/plausible": "^1.2.0",
|
||||
"@octokit/rest": "^21.1.1",
|
||||
"@vueuse/nuxt": "^13.5.0",
|
||||
"date-fns": "^4.1.0",
|
||||
"joi": "^17.13.3",
|
||||
"nuxt": "^3.14.0",
|
||||
"nuxt-cloudflare-analytics": "^1.0.8",
|
||||
"nuxt-component-meta": "^0.9.0",
|
||||
"nuxt-og-image": "^3.0.8",
|
||||
"prettier": "^3.3.3",
|
||||
"ufo": "^1.5.4",
|
||||
"nuxt": "^4.0.1",
|
||||
"nuxt-component-meta": "^0.12.1",
|
||||
"nuxt-og-image": "^5.1.9",
|
||||
"prettier": "^3.6.2",
|
||||
"ufo": "^1.6.1",
|
||||
"v-calendar": "^3.1.2",
|
||||
"valibot": "^0.42.1",
|
||||
"yup": "^1.4.0",
|
||||
"zod": "^3.23.8"
|
||||
"valibot": "^1.1.0",
|
||||
"yup": "^1.6.1",
|
||||
"zod": "^4.0.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ defineOgImageComponent('Docs', {
|
||||
const communityLinks = computed(() => [{
|
||||
icon: 'i-heroicons-pencil-square',
|
||||
label: 'Edit this page',
|
||||
to: `https://github.com/nuxt/ui/edit/dev/docs/content/${page?.value?._file}`,
|
||||
to: `https://github.com/nuxt/ui/edit/v2/docs/content/${page?.value?._file}`,
|
||||
target: '_blank'
|
||||
}, {
|
||||
icon: 'i-heroicons-star',
|
||||
@@ -98,7 +98,7 @@ const communityLinks = computed(() => [{
|
||||
const resourcesLinks = [{
|
||||
icon: 'i-simple-icons-figma',
|
||||
label: 'Figma Kit',
|
||||
to: 'https://www.figma.com/community/file/1288455405058138934',
|
||||
to: 'https://www.figma.com/community/file/1436401057300493073',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Playground',
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
</template>
|
||||
|
||||
<template #links>
|
||||
<UButton label="Get Started" trailing-icon="i-heroicons-arrow-right-20-solid" size="lg" to="/getting-started/installation" />
|
||||
<UButton label="Get started" size="lg" to="/getting-started/installation" />
|
||||
<UButton label="Explore components" trailing-icon="i-heroicons-arrow-right-20-solid" color="gray" size="lg" to="/components/button" />
|
||||
|
||||
<UInput
|
||||
<!-- <UInput
|
||||
v-model="source"
|
||||
color="gray"
|
||||
readonly
|
||||
@@ -47,7 +48,7 @@
|
||||
@click="copy(source)"
|
||||
/>
|
||||
</template>
|
||||
</UInput>
|
||||
</UInput> -->
|
||||
</template>
|
||||
|
||||
<ClientOnly>
|
||||
@@ -192,16 +193,16 @@
|
||||
</div>
|
||||
</ULandingHero>
|
||||
|
||||
<ULandingSection v-for="(section, index) in page.pro.sections" :key="index" v-bind="section" class="!pt-0">
|
||||
<!-- <ULandingSection v-for="(section, index) in page.pro.sections" :key="index" v-bind="section" class="!pt-0">
|
||||
<MDC
|
||||
v-if="section.code"
|
||||
:value="section.code"
|
||||
tag="pre"
|
||||
class="prose prose-primary dark:prose-invert max-w-none"
|
||||
/>
|
||||
</ULandingSection>
|
||||
</ULandingSection> -->
|
||||
|
||||
<div ref="sectionRef" :style="{ '--y': `${y}px`, '--inc': `${inc}px` }" class="_screen_xl">
|
||||
<!-- <div ref="sectionRef" :style="{ '--y': `${y}px`, '--inc': `${inc}px` }" class="_screen_xl">
|
||||
<ULandingSection class="sticky h-screen top-0 flex !pb-16" :ui="{ container: 'flex-1 sm:gap-y-12' }">
|
||||
<template #title>
|
||||
<Transition name="fade" mode="out-in">
|
||||
@@ -281,8 +282,6 @@
|
||||
<template #page-body>
|
||||
<div class="-mt-8 prose prose-primary prose-sm dark:prose-invert max-w-none">
|
||||
<MDC :value="md" tag="div" />
|
||||
|
||||
<!-- <hr class="border-gray-800/10 dark:border-gray-200/10 !mt-5"> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -325,7 +324,7 @@
|
||||
</template>
|
||||
|
||||
<template #links>
|
||||
<UButton label="Get Started" icon="i-heroicons-rocket-launch" size="md" />
|
||||
<UButton label="Get started" icon="i-heroicons-rocket-launch" size="md" />
|
||||
|
||||
<UInput
|
||||
model-value="npm i @nuxt/ui"
|
||||
@@ -374,9 +373,9 @@
|
||||
</ULandingSection>
|
||||
|
||||
<div class="h-[calc(var(--inc)*42)]" />
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="_not_screen_xl">
|
||||
<!-- <div class="_not_screen_xl">
|
||||
<ULandingSection>
|
||||
<template #title>
|
||||
<span v-html="page.pro.landing?.title" />
|
||||
@@ -403,15 +402,15 @@
|
||||
<source src="https://res.cloudinary.com/nuxt/video/upload/v1698923398/ui-pro/nuxt-ui-pro-docs-demo_jm6ubr.ogg" type="video/ogg">
|
||||
</video>
|
||||
</ULandingSection>
|
||||
</div>
|
||||
</div> -->
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ParsedContent, NavItem } from '@nuxt/content'
|
||||
import { useElementBounding, useWindowScroll, useElementSize, breakpointsTailwind, useBreakpoints } from '@vueuse/core'
|
||||
import type { HomeProBlock } from '~/types'
|
||||
import type { NavItem } from '@nuxt/content'
|
||||
import { useElementBounding, useWindowScroll, breakpointsTailwind, useBreakpoints } from '@vueuse/core'
|
||||
// import type { HomeProBlock } from '~/types'
|
||||
|
||||
const { data: page } = await useAsyncData('index', () => queryContent('/').findOne())
|
||||
const { data: module } = await useFetch<{
|
||||
@@ -423,6 +422,7 @@ const { data: module } = await useFetch<{
|
||||
username: string
|
||||
}[]
|
||||
}>('https://api.nuxt.com/modules/ui', {
|
||||
key: 'stats',
|
||||
transform: ({ stats, contributors }) => ({ stats, contributors })
|
||||
})
|
||||
|
||||
@@ -434,321 +434,321 @@ useSeoMeta({
|
||||
ogTitle: page.value.title,
|
||||
description: page.value.description,
|
||||
ogDescription: page.value.description,
|
||||
ogImage: 'https://ui.nuxt.com/social-card.png',
|
||||
twitterImage: 'https://ui.nuxt.com/social-card.png'
|
||||
ogImage: 'https://ui2.nuxt.com/social-card.png',
|
||||
twitterImage: 'https://ui2.nuxt.com/social-card.png'
|
||||
})
|
||||
|
||||
const source = ref('npx nuxi@latest module add ui')
|
||||
// const source = ref('npx nuxi@latest module add ui')
|
||||
const sectionRef = ref()
|
||||
const demoRef = ref(null)
|
||||
// const demoRef = ref(null)
|
||||
const start = ref(0)
|
||||
|
||||
const { $ui } = useNuxtApp()
|
||||
const { height } = useElementSize(demoRef)
|
||||
// const { $ui } = useNuxtApp()
|
||||
// const { height } = useElementSize(demoRef)
|
||||
const { top } = useElementBounding(sectionRef)
|
||||
const { y } = useWindowScroll()
|
||||
const config = useRuntimeConfig().public
|
||||
const { copy, copied } = useClipboard({ source })
|
||||
// const { copy, copied } = useClipboard({ source })
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||
|
||||
const lgAndLarger = breakpoints.greaterOrEqual('lg')
|
||||
|
||||
const { format } = Intl.NumberFormat('en', { notation: 'compact' })
|
||||
|
||||
const steps = {
|
||||
header: 0,
|
||||
footer: 5,
|
||||
landing: 10,
|
||||
docs: 27
|
||||
}
|
||||
// const steps = {
|
||||
// header: 0,
|
||||
// footer: 5,
|
||||
// landing: 10,
|
||||
// docs: 27
|
||||
// }
|
||||
|
||||
// Computed
|
||||
|
||||
const inc = computed(() => (height.value - 32 - 64 - 32 - 32) / 4)
|
||||
// const inc = computed(() => (height.value - 32 - 64 - 32 - 32) / 4)
|
||||
|
||||
const landingBlocks = computed(() => isAfterStep(steps.landing) && isBeforeStep(steps.docs)
|
||||
? [{
|
||||
class: 'inset-x-0 top-20 bottom-20 overflow-hidden',
|
||||
inactive: true,
|
||||
children: [{
|
||||
name: 'ULandingHero',
|
||||
to: '/pro/components/landing-hero',
|
||||
class: [
|
||||
'inset-4',
|
||||
isAfterStep(steps.landing + 2) && '-top-[calc(var(--y)-var(--step-y)-1rem)] bottom-[calc(var(--y)-var(--step-y)+1rem)]'
|
||||
].filter(Boolean).join(' '),
|
||||
style: {
|
||||
'--step-y': `${getStepY(steps.landing + 2)}px`
|
||||
},
|
||||
inactive: isAfterStep(steps.landing + 1),
|
||||
children: [{
|
||||
slot: 'landing-hero',
|
||||
class: 'inset-4'
|
||||
}]
|
||||
}, isAfterStep(steps.landing + 2) && {
|
||||
name: 'ULandingSection',
|
||||
to: '/pro/components/landing-section',
|
||||
class: [
|
||||
'inset-4',
|
||||
isBeforeStep(steps.landing + 6) && '-top-[calc(var(--y)-var(--prev-step-y)-var(--height)-1rem)] bottom-[calc(var(--y)-var(--prev-step-y)-var(--height)+1rem)]',
|
||||
isAfterStep(steps.landing + 10) && '-top-[calc(var(--y)-var(--step-y)-1rem)] bottom-[calc(var(--y)-var(--step-y)+1rem)]'
|
||||
].filter(Boolean).join(' '),
|
||||
style: {
|
||||
'--height': (inc.value * 4) + 'px',
|
||||
'--step-y': `${getStepY(steps.landing + 10)}px`,
|
||||
'--prev-step-y': `${getStepY(steps.landing + 2)}px`
|
||||
},
|
||||
inactive: isAfterStep(steps.landing + 7),
|
||||
children: [{
|
||||
slot: 'landing-section',
|
||||
class: 'inset-x-4 top-16'
|
||||
}, {
|
||||
name: 'ULandingGrid',
|
||||
to: '/pro/components/landing-grid',
|
||||
class: ['inset-x-4 bottom-4 top-48', isAfterStep(steps.landing + 8) && 'grid grid-cols-4 gap-4 p-4'].filter(Boolean).join(' '),
|
||||
inactive: isAfterStep(steps.landing + 8),
|
||||
children: [isAfterStep(steps.landing + 9)
|
||||
? {
|
||||
slot: 'landing-card-1',
|
||||
class: '!relative'
|
||||
}
|
||||
: {
|
||||
name: 'ULandingCard',
|
||||
to: '/pro/components/landing-card',
|
||||
class: '!relative h-full',
|
||||
inactive: false
|
||||
}, isAfterStep(steps.landing + 9)
|
||||
? {
|
||||
slot: 'landing-card-2',
|
||||
class: '!relative h-full'
|
||||
}
|
||||
: {
|
||||
name: 'ULandingCard',
|
||||
to: '/pro/components/landing-card',
|
||||
class: '!relative h-full',
|
||||
inactive: false
|
||||
}, isAfterStep(steps.landing + 9)
|
||||
? {
|
||||
slot: 'landing-card-3',
|
||||
class: '!relative h-full'
|
||||
}
|
||||
: {
|
||||
name: 'ULandingCard',
|
||||
to: '/pro/components/landing-card',
|
||||
class: '!relative h-full',
|
||||
inactive: false
|
||||
}, isAfterStep(steps.landing + 9)
|
||||
? {
|
||||
slot: 'landing-card-4',
|
||||
class: '!relative h-full'
|
||||
}
|
||||
: {
|
||||
name: 'ULandingCard',
|
||||
to: '/pro/components/landing-card',
|
||||
class: '!relative h-full',
|
||||
inactive: false
|
||||
}]
|
||||
}]
|
||||
}, isAfterStep(steps.landing + 10) && {
|
||||
name: 'ULandingSection',
|
||||
to: '/pro/components/landing-section',
|
||||
class: [
|
||||
'inset-4',
|
||||
isBeforeStep(steps.landing + 14) && '-top-[calc(var(--y)-var(--prev-step-y)-var(--height)-1rem)] bottom-[calc(var(--y)-var(--prev-step-y)-var(--height)+1rem)]'
|
||||
].filter(Boolean).join(' '),
|
||||
style: {
|
||||
'--height': (inc.value * 4) + 'px',
|
||||
'--step-y': `${getStepY(steps.landing + 18)}px`,
|
||||
'--prev-step-y': `${getStepY(steps.landing + 10)}px`
|
||||
},
|
||||
inactive: isAfterStep(steps.landing + 15),
|
||||
children: [{
|
||||
name: 'ULandingCTA',
|
||||
class: 'inset-4',
|
||||
inactive: isAfterStep(steps.landing + 16),
|
||||
children: [{
|
||||
slot: 'landing-cta',
|
||||
class: 'inset-0'
|
||||
}]
|
||||
}]
|
||||
}].filter(Boolean)
|
||||
}]
|
||||
: [])
|
||||
// const landingBlocks = computed(() => isAfterStep(steps.landing) && isBeforeStep(steps.docs)
|
||||
// ? [{
|
||||
// class: 'inset-x-0 top-20 bottom-20 overflow-hidden',
|
||||
// inactive: true,
|
||||
// children: [{
|
||||
// name: 'ULandingHero',
|
||||
// to: '/pro/components/landing-hero',
|
||||
// class: [
|
||||
// 'inset-4',
|
||||
// isAfterStep(steps.landing + 2) && '-top-[calc(var(--y)-var(--step-y)-1rem)] bottom-[calc(var(--y)-var(--step-y)+1rem)]'
|
||||
// ].filter(Boolean).join(' '),
|
||||
// style: {
|
||||
// '--step-y': `${getStepY(steps.landing + 2)}px`
|
||||
// },
|
||||
// inactive: isAfterStep(steps.landing + 1),
|
||||
// children: [{
|
||||
// slot: 'landing-hero',
|
||||
// class: 'inset-4'
|
||||
// }]
|
||||
// }, isAfterStep(steps.landing + 2) && {
|
||||
// name: 'ULandingSection',
|
||||
// to: '/pro/components/landing-section',
|
||||
// class: [
|
||||
// 'inset-4',
|
||||
// isBeforeStep(steps.landing + 6) && '-top-[calc(var(--y)-var(--prev-step-y)-var(--height)-1rem)] bottom-[calc(var(--y)-var(--prev-step-y)-var(--height)+1rem)]',
|
||||
// isAfterStep(steps.landing + 10) && '-top-[calc(var(--y)-var(--step-y)-1rem)] bottom-[calc(var(--y)-var(--step-y)+1rem)]'
|
||||
// ].filter(Boolean).join(' '),
|
||||
// style: {
|
||||
// '--height': (inc.value * 4) + 'px',
|
||||
// '--step-y': `${getStepY(steps.landing + 10)}px`,
|
||||
// '--prev-step-y': `${getStepY(steps.landing + 2)}px`
|
||||
// },
|
||||
// inactive: isAfterStep(steps.landing + 7),
|
||||
// children: [{
|
||||
// slot: 'landing-section',
|
||||
// class: 'inset-x-4 top-16'
|
||||
// }, {
|
||||
// name: 'ULandingGrid',
|
||||
// to: '/pro/components/landing-grid',
|
||||
// class: ['inset-x-4 bottom-4 top-48', isAfterStep(steps.landing + 8) && 'grid grid-cols-4 gap-4 p-4'].filter(Boolean).join(' '),
|
||||
// inactive: isAfterStep(steps.landing + 8),
|
||||
// children: [isAfterStep(steps.landing + 9)
|
||||
// ? {
|
||||
// slot: 'landing-card-1',
|
||||
// class: '!relative'
|
||||
// }
|
||||
// : {
|
||||
// name: 'ULandingCard',
|
||||
// to: '/pro/components/landing-card',
|
||||
// class: '!relative h-full',
|
||||
// inactive: false
|
||||
// }, isAfterStep(steps.landing + 9)
|
||||
// ? {
|
||||
// slot: 'landing-card-2',
|
||||
// class: '!relative h-full'
|
||||
// }
|
||||
// : {
|
||||
// name: 'ULandingCard',
|
||||
// to: '/pro/components/landing-card',
|
||||
// class: '!relative h-full',
|
||||
// inactive: false
|
||||
// }, isAfterStep(steps.landing + 9)
|
||||
// ? {
|
||||
// slot: 'landing-card-3',
|
||||
// class: '!relative h-full'
|
||||
// }
|
||||
// : {
|
||||
// name: 'ULandingCard',
|
||||
// to: '/pro/components/landing-card',
|
||||
// class: '!relative h-full',
|
||||
// inactive: false
|
||||
// }, isAfterStep(steps.landing + 9)
|
||||
// ? {
|
||||
// slot: 'landing-card-4',
|
||||
// class: '!relative h-full'
|
||||
// }
|
||||
// : {
|
||||
// name: 'ULandingCard',
|
||||
// to: '/pro/components/landing-card',
|
||||
// class: '!relative h-full',
|
||||
// inactive: false
|
||||
// }]
|
||||
// }]
|
||||
// }, isAfterStep(steps.landing + 10) && {
|
||||
// name: 'ULandingSection',
|
||||
// to: '/pro/components/landing-section',
|
||||
// class: [
|
||||
// 'inset-4',
|
||||
// isBeforeStep(steps.landing + 14) && '-top-[calc(var(--y)-var(--prev-step-y)-var(--height)-1rem)] bottom-[calc(var(--y)-var(--prev-step-y)-var(--height)+1rem)]'
|
||||
// ].filter(Boolean).join(' '),
|
||||
// style: {
|
||||
// '--height': (inc.value * 4) + 'px',
|
||||
// '--step-y': `${getStepY(steps.landing + 18)}px`,
|
||||
// '--prev-step-y': `${getStepY(steps.landing + 10)}px`
|
||||
// },
|
||||
// inactive: isAfterStep(steps.landing + 15),
|
||||
// children: [{
|
||||
// name: 'ULandingCTA',
|
||||
// class: 'inset-4',
|
||||
// inactive: isAfterStep(steps.landing + 16),
|
||||
// children: [{
|
||||
// slot: 'landing-cta',
|
||||
// class: 'inset-0'
|
||||
// }]
|
||||
// }]
|
||||
// }].filter(Boolean)
|
||||
// }]
|
||||
// : [])
|
||||
|
||||
const docsBlocks = computed(() => [isAfterStep(steps.docs) && {
|
||||
name: 'UPage',
|
||||
to: '/pro/components/page',
|
||||
class: 'inset-x-0 top-20 bottom-20',
|
||||
inactive: isAfterStep(steps.docs + 1),
|
||||
children: [isAfterStep(steps.docs + 2)
|
||||
? {
|
||||
name: 'UAside',
|
||||
to: '/pro/components/aside',
|
||||
class: 'left-4 inset-y-4 w-64',
|
||||
inactive: isAfterStep(steps.docs + 3),
|
||||
children: [isAfterStep(steps.docs + 4)
|
||||
? {
|
||||
slot: 'aside-top',
|
||||
class: 'inset-x-4 top-4'
|
||||
}
|
||||
: {
|
||||
name: '#top',
|
||||
class: 'inset-x-4 top-4 h-9'
|
||||
}, isAfterStep(steps.docs + 5)
|
||||
? {
|
||||
name: 'UNavigationTree',
|
||||
to: '/pro/components/navigation-tree',
|
||||
class: ['inset-x-4 top-[4.25rem] bottom-4', isAfterStep(steps.docs + 6) && '!bg-transparent !border-0'].join(' '),
|
||||
inactive: isAfterStep(steps.docs + 6),
|
||||
children: [{
|
||||
slot: 'aside-default',
|
||||
class: 'inset-0'
|
||||
}]
|
||||
}
|
||||
: {
|
||||
name: '#default',
|
||||
class: 'inset-x-4 top-[4.25rem] bottom-4'
|
||||
}]
|
||||
}
|
||||
: {
|
||||
name: '#left',
|
||||
class: 'left-4 inset-y-4 w-64'
|
||||
}, isAfterStep(steps.docs + 7)
|
||||
? {
|
||||
name: 'UPage',
|
||||
to: '/pro/components/page',
|
||||
class: 'left-72 right-4 inset-y-4',
|
||||
inactive: isAfterStep(steps.docs + 8),
|
||||
children: [...(isAfterStep(steps.docs + 9)
|
||||
? [{
|
||||
name: 'UPageHeader',
|
||||
to: '/pro/components/page-header',
|
||||
class: 'top-4 left-4 right-72 h-32',
|
||||
inactive: isAfterStep(steps.docs + 10),
|
||||
children: [{
|
||||
slot: 'page-header',
|
||||
class: 'inset-4 justify-start'
|
||||
}]
|
||||
}, {
|
||||
name: 'UPageBody',
|
||||
to: '/pro/components/page-body',
|
||||
class: 'top-40 left-4 right-72 bottom-4 overflow-y-auto',
|
||||
inactive: isAfterStep(steps.docs + 11),
|
||||
children: [{
|
||||
slot: 'page-body',
|
||||
class: 'inset-x-4 top-4 justify-start'
|
||||
}, isAfterStep(steps.docs + 12)
|
||||
? {
|
||||
slot: 'content-surround',
|
||||
class: 'bottom-4 inset-x-4 h-28'
|
||||
}
|
||||
: {
|
||||
name: 'UContentSurround',
|
||||
to: '/pro/components/content-surround',
|
||||
class: 'bottom-4 inset-x-4 h-28',
|
||||
inactive: false
|
||||
}]
|
||||
}]
|
||||
: [{
|
||||
name: '#default',
|
||||
class: 'left-4 right-72 inset-y-4'
|
||||
}]), isAfterStep(steps.docs + 13)
|
||||
? {
|
||||
name: 'UContentToc',
|
||||
to: '/pro/components/content-toc',
|
||||
class: 'right-4 inset-y-4 w-64',
|
||||
inactive: isAfterStep(steps.docs + 14),
|
||||
children: [{
|
||||
slot: 'content-toc',
|
||||
class: 'inset-4 overflow-y-auto'
|
||||
}]
|
||||
}
|
||||
: {
|
||||
name: '#right',
|
||||
class: 'right-4 inset-y-4 w-64'
|
||||
}]
|
||||
}
|
||||
: {
|
||||
name: '#default',
|
||||
class: 'left-72 right-4 inset-y-4'
|
||||
}]
|
||||
}].filter(Boolean))
|
||||
// const docsBlocks = computed(() => [isAfterStep(steps.docs) && {
|
||||
// name: 'UPage',
|
||||
// to: '/pro/components/page',
|
||||
// class: 'inset-x-0 top-20 bottom-20',
|
||||
// inactive: isAfterStep(steps.docs + 1),
|
||||
// children: [isAfterStep(steps.docs + 2)
|
||||
// ? {
|
||||
// name: 'UAside',
|
||||
// to: '/pro/components/aside',
|
||||
// class: 'left-4 inset-y-4 w-64',
|
||||
// inactive: isAfterStep(steps.docs + 3),
|
||||
// children: [isAfterStep(steps.docs + 4)
|
||||
// ? {
|
||||
// slot: 'aside-top',
|
||||
// class: 'inset-x-4 top-4'
|
||||
// }
|
||||
// : {
|
||||
// name: '#top',
|
||||
// class: 'inset-x-4 top-4 h-9'
|
||||
// }, isAfterStep(steps.docs + 5)
|
||||
// ? {
|
||||
// name: 'UNavigationTree',
|
||||
// to: '/pro/components/navigation-tree',
|
||||
// class: ['inset-x-4 top-[4.25rem] bottom-4', isAfterStep(steps.docs + 6) && '!bg-transparent !border-0'].join(' '),
|
||||
// inactive: isAfterStep(steps.docs + 6),
|
||||
// children: [{
|
||||
// slot: 'aside-default',
|
||||
// class: 'inset-0'
|
||||
// }]
|
||||
// }
|
||||
// : {
|
||||
// name: '#default',
|
||||
// class: 'inset-x-4 top-[4.25rem] bottom-4'
|
||||
// }]
|
||||
// }
|
||||
// : {
|
||||
// name: '#left',
|
||||
// class: 'left-4 inset-y-4 w-64'
|
||||
// }, isAfterStep(steps.docs + 7)
|
||||
// ? {
|
||||
// name: 'UPage',
|
||||
// to: '/pro/components/page',
|
||||
// class: 'left-72 right-4 inset-y-4',
|
||||
// inactive: isAfterStep(steps.docs + 8),
|
||||
// children: [...(isAfterStep(steps.docs + 9)
|
||||
// ? [{
|
||||
// name: 'UPageHeader',
|
||||
// to: '/pro/components/page-header',
|
||||
// class: 'top-4 left-4 right-72 h-32',
|
||||
// inactive: isAfterStep(steps.docs + 10),
|
||||
// children: [{
|
||||
// slot: 'page-header',
|
||||
// class: 'inset-4 justify-start'
|
||||
// }]
|
||||
// }, {
|
||||
// name: 'UPageBody',
|
||||
// to: '/pro/components/page-body',
|
||||
// class: 'top-40 left-4 right-72 bottom-4 overflow-y-auto',
|
||||
// inactive: isAfterStep(steps.docs + 11),
|
||||
// children: [{
|
||||
// slot: 'page-body',
|
||||
// class: 'inset-x-4 top-4 justify-start'
|
||||
// }, isAfterStep(steps.docs + 12)
|
||||
// ? {
|
||||
// slot: 'content-surround',
|
||||
// class: 'bottom-4 inset-x-4 h-28'
|
||||
// }
|
||||
// : {
|
||||
// name: 'UContentSurround',
|
||||
// to: '/pro/components/content-surround',
|
||||
// class: 'bottom-4 inset-x-4 h-28',
|
||||
// inactive: false
|
||||
// }]
|
||||
// }]
|
||||
// : [{
|
||||
// name: '#default',
|
||||
// class: 'left-4 right-72 inset-y-4'
|
||||
// }]), isAfterStep(steps.docs + 13)
|
||||
// ? {
|
||||
// name: 'UContentToc',
|
||||
// to: '/pro/components/content-toc',
|
||||
// class: 'right-4 inset-y-4 w-64',
|
||||
// inactive: isAfterStep(steps.docs + 14),
|
||||
// children: [{
|
||||
// slot: 'content-toc',
|
||||
// class: 'inset-4 overflow-y-auto'
|
||||
// }]
|
||||
// }
|
||||
// : {
|
||||
// name: '#right',
|
||||
// class: 'right-4 inset-y-4 w-64'
|
||||
// }]
|
||||
// }
|
||||
// : {
|
||||
// name: '#default',
|
||||
// class: 'left-72 right-4 inset-y-4'
|
||||
// }]
|
||||
// }].filter(Boolean))
|
||||
|
||||
const blocks = computed(() => [isAfterStep(steps.header) && {
|
||||
name: 'UHeader',
|
||||
to: '/pro/components/header',
|
||||
class: 'h-16 inset-x-0 top-0',
|
||||
inactive: isAfterStep(steps.header + 1),
|
||||
children: [isAfterStep(steps.header + 2)
|
||||
? {
|
||||
slot: 'header-left',
|
||||
class: 'left-4 top-4'
|
||||
}
|
||||
: {
|
||||
name: '#left',
|
||||
class: 'left-4 inset-y-4 w-64'
|
||||
}, isAfterStep(steps.header + 3)
|
||||
? {
|
||||
slot: 'header-center',
|
||||
class: 'inset-x-72 top-5'
|
||||
}
|
||||
: {
|
||||
name: '#center',
|
||||
class: 'inset-x-72 inset-y-4'
|
||||
}, isAfterStep(steps.header + 4)
|
||||
? {
|
||||
slot: 'header-right',
|
||||
class: 'right-4 top-4'
|
||||
}
|
||||
: {
|
||||
name: '#right',
|
||||
class: 'right-4 inset-y-4 w-64'
|
||||
}]
|
||||
}, isAfterStep(steps.footer) && {
|
||||
name: 'UFooter',
|
||||
to: '/pro/components/footer',
|
||||
class: 'h-16 inset-x-0 bottom-0',
|
||||
inactive: isAfterStep(steps.footer + 1),
|
||||
children: [isAfterStep(steps.footer + 2)
|
||||
? {
|
||||
slot: 'footer-left',
|
||||
class: 'left-4 bottom-5'
|
||||
}
|
||||
: {
|
||||
name: '#left',
|
||||
class: 'left-4 inset-y-4 w-64'
|
||||
}, isAfterStep(steps.footer + 3)
|
||||
? {
|
||||
slot: 'footer-center',
|
||||
class: 'inset-x-72 bottom-5'
|
||||
}
|
||||
: {
|
||||
name: '#center',
|
||||
class: 'inset-x-72 inset-y-4'
|
||||
}, isAfterStep(steps.footer + 4)
|
||||
? {
|
||||
slot: 'footer-right',
|
||||
class: 'right-4 bottom-4'
|
||||
}
|
||||
: {
|
||||
name: '#right',
|
||||
class: 'right-4 inset-y-4 w-64'
|
||||
}]
|
||||
}, ...landingBlocks.value, ...docsBlocks.value].filter(Boolean))
|
||||
// const blocks = computed(() => [isAfterStep(steps.header) && {
|
||||
// name: 'UHeader',
|
||||
// to: '/pro/components/header',
|
||||
// class: 'h-16 inset-x-0 top-0',
|
||||
// inactive: isAfterStep(steps.header + 1),
|
||||
// children: [isAfterStep(steps.header + 2)
|
||||
// ? {
|
||||
// slot: 'header-left',
|
||||
// class: 'left-4 top-4'
|
||||
// }
|
||||
// : {
|
||||
// name: '#left',
|
||||
// class: 'left-4 inset-y-4 w-64'
|
||||
// }, isAfterStep(steps.header + 3)
|
||||
// ? {
|
||||
// slot: 'header-center',
|
||||
// class: 'inset-x-72 top-5'
|
||||
// }
|
||||
// : {
|
||||
// name: '#center',
|
||||
// class: 'inset-x-72 inset-y-4'
|
||||
// }, isAfterStep(steps.header + 4)
|
||||
// ? {
|
||||
// slot: 'header-right',
|
||||
// class: 'right-4 top-4'
|
||||
// }
|
||||
// : {
|
||||
// name: '#right',
|
||||
// class: 'right-4 inset-y-4 w-64'
|
||||
// }]
|
||||
// }, isAfterStep(steps.footer) && {
|
||||
// name: 'UFooter',
|
||||
// to: '/pro/components/footer',
|
||||
// class: 'h-16 inset-x-0 bottom-0',
|
||||
// inactive: isAfterStep(steps.footer + 1),
|
||||
// children: [isAfterStep(steps.footer + 2)
|
||||
// ? {
|
||||
// slot: 'footer-left',
|
||||
// class: 'left-4 bottom-5'
|
||||
// }
|
||||
// : {
|
||||
// name: '#left',
|
||||
// class: 'left-4 inset-y-4 w-64'
|
||||
// }, isAfterStep(steps.footer + 3)
|
||||
// ? {
|
||||
// slot: 'footer-center',
|
||||
// class: 'inset-x-72 bottom-5'
|
||||
// }
|
||||
// : {
|
||||
// name: '#center',
|
||||
// class: 'inset-x-72 inset-y-4'
|
||||
// }, isAfterStep(steps.footer + 4)
|
||||
// ? {
|
||||
// slot: 'footer-right',
|
||||
// class: 'right-4 bottom-4'
|
||||
// }
|
||||
// : {
|
||||
// name: '#right',
|
||||
// class: 'right-4 inset-y-4 w-64'
|
||||
// }]
|
||||
// }, ...landingBlocks.value, ...docsBlocks.value].filter(Boolean))
|
||||
|
||||
// Methods
|
||||
|
||||
function isBeforeStep(i = 0) {
|
||||
return y.value < (start.value + (i * inc.value))
|
||||
}
|
||||
// function isBeforeStep(i = 0) {
|
||||
// return y.value < (start.value + (i * inc.value))
|
||||
// }
|
||||
|
||||
function isAfterStep(i = 0) {
|
||||
return y.value >= (start.value + (i * inc.value))
|
||||
}
|
||||
// function isAfterStep(i = 0) {
|
||||
// return y.value >= (start.value + (i * inc.value))
|
||||
// }
|
||||
|
||||
function getStepY(step: number) {
|
||||
return start.value + (step * inc.value)
|
||||
}
|
||||
// function getStepY(step: number) {
|
||||
// return start.value + (step * inc.value)
|
||||
// }
|
||||
|
||||
// Hooks
|
||||
|
||||
@@ -760,94 +760,94 @@ onMounted(() => {
|
||||
|
||||
// Slots Data
|
||||
|
||||
const headerLinks = [{
|
||||
label: 'Documentation',
|
||||
active: true
|
||||
}, {
|
||||
label: 'Playground'
|
||||
}, {
|
||||
label: 'Roadmap'
|
||||
}, {
|
||||
label: 'Pro'
|
||||
}]
|
||||
// const headerLinks = [{
|
||||
// label: 'Documentation',
|
||||
// active: true
|
||||
// }, {
|
||||
// label: 'Playground'
|
||||
// }, {
|
||||
// label: 'Roadmap'
|
||||
// }, {
|
||||
// label: 'Pro'
|
||||
// }]
|
||||
|
||||
const navigationLinks = [{
|
||||
label: 'Getting Started',
|
||||
children: [{
|
||||
label: 'Introduction'
|
||||
}, {
|
||||
label: 'Installation',
|
||||
active: true
|
||||
}, {
|
||||
label: 'Theming'
|
||||
}, {
|
||||
label: 'Shortcuts'
|
||||
}, {
|
||||
label: 'Examples'
|
||||
}, {
|
||||
label: 'Roadmap'
|
||||
}]
|
||||
}, {
|
||||
label: 'Elements',
|
||||
children: [{
|
||||
label: 'Alert'
|
||||
}, {
|
||||
label: 'Avatar'
|
||||
}, {
|
||||
label: 'Badge'
|
||||
}, {
|
||||
label: 'Button'
|
||||
}]
|
||||
}]
|
||||
// const navigationLinks = [{
|
||||
// label: 'Getting Started',
|
||||
// children: [{
|
||||
// label: 'Introduction'
|
||||
// }, {
|
||||
// label: 'Installation',
|
||||
// active: true
|
||||
// }, {
|
||||
// label: 'Theming'
|
||||
// }, {
|
||||
// label: 'Shortcuts'
|
||||
// }, {
|
||||
// label: 'Examples'
|
||||
// }, {
|
||||
// label: 'Roadmap'
|
||||
// }]
|
||||
// }, {
|
||||
// label: 'Elements',
|
||||
// children: [{
|
||||
// label: 'Alert'
|
||||
// }, {
|
||||
// label: 'Avatar'
|
||||
// }, {
|
||||
// label: 'Badge'
|
||||
// }, {
|
||||
// label: 'Button'
|
||||
// }]
|
||||
// }]
|
||||
|
||||
const surround = [{
|
||||
title: 'Introduction',
|
||||
description: 'Fully styled and customizable components for Nuxt.',
|
||||
_path: '/'
|
||||
}, {
|
||||
title: 'Theming',
|
||||
description: 'Learn how to customize the look and feel of the components.',
|
||||
_path: '/'
|
||||
}]
|
||||
// const surround = [{
|
||||
// title: 'Introduction',
|
||||
// description: 'Fully styled and customizable components for Nuxt.',
|
||||
// _path: '/'
|
||||
// }, {
|
||||
// title: 'Theming',
|
||||
// description: 'Learn how to customize the look and feel of the components.',
|
||||
// _path: '/'
|
||||
// }]
|
||||
|
||||
const md = `
|
||||
## Edge
|
||||
// const md = `
|
||||
// ## Edge
|
||||
|
||||
To use the latest updates pushed on the [\`dev\`](https://github.com/nuxt/ui/tree/dev) branch, you can use \`@nuxt/ui-edge\`.
|
||||
`
|
||||
// To use the latest updates pushed on the [\`dev\`](https://github.com/nuxt/ui/tree/v2) branch, you can use \`@nuxt/ui-edge\`.
|
||||
// `
|
||||
|
||||
const toc = [{
|
||||
id: 'quick-start',
|
||||
depth: 2,
|
||||
text: 'Quick Start'
|
||||
}, {
|
||||
id: 'intellisense',
|
||||
depth: 2,
|
||||
text: 'IntelliSense'
|
||||
}, {
|
||||
id: 'options',
|
||||
depth: 2,
|
||||
text: 'Options'
|
||||
}, {
|
||||
id: 'edge',
|
||||
depth: 2,
|
||||
text: 'Edge'
|
||||
}]
|
||||
// const toc = [{
|
||||
// id: 'quick-start',
|
||||
// depth: 2,
|
||||
// text: 'Quick Start'
|
||||
// }, {
|
||||
// id: 'intellisense',
|
||||
// depth: 2,
|
||||
// text: 'IntelliSense'
|
||||
// }, {
|
||||
// id: 'options',
|
||||
// depth: 2,
|
||||
// text: 'Options'
|
||||
// }, {
|
||||
// id: 'edge',
|
||||
// depth: 2,
|
||||
// text: 'Edge'
|
||||
// }]
|
||||
|
||||
const communityLinks = [{
|
||||
icon: 'i-heroicons-pencil-square',
|
||||
label: 'Edit this page'
|
||||
}, {
|
||||
icon: 'i-heroicons-star',
|
||||
label: 'Star on GitHub',
|
||||
to: 'https://github.com/nuxt/ui',
|
||||
target: '_blank'
|
||||
}, {
|
||||
icon: 'i-heroicons-book-open',
|
||||
label: 'Nuxt documentation',
|
||||
to: 'https://nuxt.com',
|
||||
target: '_blank'
|
||||
}]
|
||||
// const communityLinks = [{
|
||||
// icon: 'i-heroicons-pencil-square',
|
||||
// label: 'Edit this page'
|
||||
// }, {
|
||||
// icon: 'i-heroicons-star',
|
||||
// label: 'Star on GitHub',
|
||||
// to: 'https://github.com/nuxt/ui',
|
||||
// target: '_blank'
|
||||
// }, {
|
||||
// icon: 'i-heroicons-book-open',
|
||||
// label: 'Nuxt documentation',
|
||||
// to: 'https://nuxt.com',
|
||||
// target: '_blank'
|
||||
// }]
|
||||
</script>
|
||||
|
||||
<style scoped lang="postcss">
|
||||
|
||||
@@ -41,8 +41,8 @@ if (!page.value) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
|
||||
}
|
||||
|
||||
const { data: releases } = await useFetch('/api/releases.json')
|
||||
const { data: pulls } = await useLazyFetch('/api/pulls.json', { default: () => [] })
|
||||
const { data: releases } = await useFetch('/api/releases.json', { key: 'releases-list' })
|
||||
const { data: pulls } = await useLazyFetch('/api/pulls.json', { default: () => [], key: 'pulls-list' })
|
||||
|
||||
const dates = computed(() => {
|
||||
const first = releases.value[releases.value.length - 1]
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
user-agent: *
|
||||
disallow: /dev/*
|
||||
user-agent: *
|
||||
117
package.json
117
package.json
@@ -1,20 +1,29 @@
|
||||
{
|
||||
"name": "@nuxt/ui",
|
||||
"description": "A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.",
|
||||
"version": "2.19.2",
|
||||
"packageManager": "pnpm@9.12.3",
|
||||
"repository": "nuxt/ui",
|
||||
"homepage": "https://ui.nuxt.com",
|
||||
"version": "2.22.1",
|
||||
"packageManager": "pnpm@10.13.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/nuxt/ui.git"
|
||||
},
|
||||
"homepage": "https://ui2.nuxt.com",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/module.mjs",
|
||||
"require": "./dist/module.cjs"
|
||||
"types": "./dist/module.d.mts",
|
||||
"import": "./dist/module.mjs"
|
||||
}
|
||||
},
|
||||
"main": "./dist/module.cjs",
|
||||
"types": "./dist/types.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
".": [
|
||||
"./dist/module.d.mts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"main": "./dist/module.mjs",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
@@ -32,54 +41,78 @@
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/tailwindcss": "^0.2.1",
|
||||
"@headlessui/tailwindcss": "^0.2.2",
|
||||
"@headlessui/vue": "^1.7.23",
|
||||
"@iconify-json/heroicons": "^1.2.1",
|
||||
"@nuxt/icon": "^1.6.1",
|
||||
"@nuxt/kit": "^3.14.0",
|
||||
"@iconify-json/heroicons": "^1.2.2",
|
||||
"@nuxt/icon": "^1.15.0",
|
||||
"@nuxt/kit": "^4.0.1",
|
||||
"@nuxtjs/color-mode": "^3.5.2",
|
||||
"@nuxtjs/tailwindcss": "^6.12.2",
|
||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tailwindcss/forms": "^0.5.9",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@vueuse/core": "^11.2.0",
|
||||
"@vueuse/integrations": "^11.2.0",
|
||||
"@vueuse/math": "^11.2.0",
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@vueuse/core": "^13.5.0",
|
||||
"@vueuse/integrations": "^13.5.0",
|
||||
"@vueuse/math": "^13.5.0",
|
||||
"defu": "^6.1.4",
|
||||
"fuse.js": "^7.0.0",
|
||||
"ohash": "^1.1.4",
|
||||
"pathe": "^1.1.2",
|
||||
"fuse.js": "^7.1.0",
|
||||
"ohash": "^2.0.11",
|
||||
"pathe": "^2.0.3",
|
||||
"scule": "^1.3.0",
|
||||
"tailwind-merge": "^2.5.4",
|
||||
"tailwindcss": "^3.4.14"
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss": "^3.4.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint-config": "^0.6.1",
|
||||
"@nuxt/module-builder": "^0.8.4",
|
||||
"@nuxt/test-utils": "^3.14.4",
|
||||
"@release-it/conventional-changelog": "^9.0.2",
|
||||
"@nuxt/eslint-config": "^1.6.0",
|
||||
"@nuxt/module-builder": "^1.0.1",
|
||||
"@nuxt/test-utils": "^3.19.2",
|
||||
"@release-it/conventional-changelog": "^10.0.1",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"eslint": "^9.14.0",
|
||||
"happy-dom": "^14.12.3",
|
||||
"joi": "^17.13.3",
|
||||
"nuxt": "^3.14.0",
|
||||
"release-it": "^17.10.0",
|
||||
"superstruct": "^2.0.2",
|
||||
"unbuild": "^2.0.0",
|
||||
"valibot": "^0.42.1",
|
||||
"valibot30": "npm:valibot@0.30.0",
|
||||
"valibot31": "npm:valibot@0.31.0",
|
||||
"vitest": "^2.1.4",
|
||||
"eslint": "^9.31.0",
|
||||
"happy-dom": "^18.0.1",
|
||||
"nuxt": "^4.0.1",
|
||||
"release-it": "^19.0.4",
|
||||
"typescript": "^5.8.3",
|
||||
"vitest": "^3.2.4",
|
||||
"vitest-environment-nuxt": "^1.0.1",
|
||||
"vue-tsc": "^2.1.10",
|
||||
"yup": "^1.4.0",
|
||||
"zod": "^3.23.8"
|
||||
"vue-tsc": "^3.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"joi": "^17.13.0",
|
||||
"superstruct": "^2.0.0",
|
||||
"valibot": "^1.0.0",
|
||||
"yup": "^1.6.0",
|
||||
"zod": "^3.24.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"joi": {
|
||||
"optional": true
|
||||
},
|
||||
"valibot": {
|
||||
"optional": true
|
||||
},
|
||||
"superstruct": {
|
||||
"optional": true
|
||||
},
|
||||
"yup": {
|
||||
"optional": true
|
||||
},
|
||||
"zod": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"@nuxt/ui": "workspace:*",
|
||||
"@nuxt/content": "2.13.2",
|
||||
"@nuxtjs/mdc": "0.9.0"
|
||||
"@nuxtjs/mdc": "0.9.0",
|
||||
"@vueuse/core": "^13.5.0",
|
||||
"@vueuse/integrations": "^13.5.0",
|
||||
"@vueuse/math": "^13.5.0",
|
||||
"@vueuse/nuxt": "13.1.0",
|
||||
"unimport": "4.1.1",
|
||||
"chokidar": "3.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/ui": "latest",
|
||||
"nuxt": "^3.14.0"
|
||||
"nuxt": "^4.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
12573
pnpm-lock.yaml
generated
12573
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,10 @@
|
||||
packages:
|
||||
- "./"
|
||||
- "docs"
|
||||
- "playground"
|
||||
- ./
|
||||
- docs
|
||||
- playground
|
||||
|
||||
ignoredBuiltDependencies:
|
||||
- '@parcel/watcher'
|
||||
- esbuild
|
||||
- sharp
|
||||
- vue-demi
|
||||
|
||||
@@ -5,12 +5,7 @@
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true
|
||||
},
|
||||
"ignoreDeps": [
|
||||
"happy-dom",
|
||||
"valibot30",
|
||||
"valibot31"
|
||||
],
|
||||
"baseBranches": ["dev", "v3"],
|
||||
"baseBranches": ["v2", "v3"],
|
||||
"packageRules": [{
|
||||
"matchBaseBranches": ["v3"],
|
||||
"labels": ["v3"]
|
||||
@@ -24,5 +19,6 @@
|
||||
}, {
|
||||
"matchDepTypes": ["resolutions"],
|
||||
"enabled": false
|
||||
}]
|
||||
}],
|
||||
"postUpdateOptions": ["pnpmDedupe"]
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { execSync } from 'node:child_process'
|
||||
|
||||
async function loadPackage(dir: string) {
|
||||
const pkgPath = resolve(dir, 'package.json')
|
||||
|
||||
const data = JSON.parse(await fsp.readFile(pkgPath, 'utf-8').catch(() => '{}'))
|
||||
|
||||
const save = () => fsp.writeFile(pkgPath, JSON.stringify(data, null, 2) + '\n')
|
||||
|
||||
return {
|
||||
dir,
|
||||
data,
|
||||
save
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const pkg = await loadPackage(process.cwd())
|
||||
|
||||
const commit = execSync('git rev-parse --short HEAD').toString('utf-8').trim()
|
||||
|
||||
const date = Math.round(Date.now() / (1000 * 60))
|
||||
|
||||
pkg.data.name = `${pkg.data.name}-edge`
|
||||
|
||||
pkg.data.version = `${pkg.data.version}-${date}.${commit}`
|
||||
|
||||
pkg.save()
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Restore all git changes
|
||||
git restore -s@ -SW -- .
|
||||
|
||||
# Bump versions to edge
|
||||
pnpm jiti ./scripts/bump-edge
|
||||
|
||||
# Update token
|
||||
if [[ ! -z ${NODE_AUTH_TOKEN} ]] ; then
|
||||
echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" >> ~/.npmrc
|
||||
echo "registry=https://registry.npmjs.org/" >> ~/.npmrc
|
||||
echo "always-auth=true" >> ~/.npmrc
|
||||
npm whoami
|
||||
fi
|
||||
|
||||
# Release package
|
||||
echo "Publishing @nuxt/ui"
|
||||
npm publish -q --access public
|
||||
@@ -13,4 +13,4 @@ fi
|
||||
|
||||
# Release package
|
||||
echo "Publishing @nuxt/ui"
|
||||
npm publish -q --access public
|
||||
npm publish --access public --no-tag
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createRequire } from 'node:module'
|
||||
import { defineNuxtModule, installModule, addComponentsDir, addImportsDir, createResolver, addPlugin } from '@nuxt/kit'
|
||||
import type { ConfigExtension, DefaultClassGroupIds, DefaultThemeGroupIds } from 'tailwind-merge'
|
||||
import { name, version } from '../package.json'
|
||||
import createTemplates from './templates'
|
||||
import type * as config from './runtime/ui.config'
|
||||
@@ -20,6 +21,7 @@ type UI = {
|
||||
gray?: string
|
||||
colors?: string[]
|
||||
strategy?: Strategy
|
||||
tailwindMerge?: ConfigExtension<DefaultClassGroupIds, DefaultThemeGroupIds>
|
||||
[key: string]: any
|
||||
} & DeepPartial<typeof config, string | number | boolean>
|
||||
|
||||
@@ -41,6 +43,11 @@ export interface ModuleOptions {
|
||||
*/
|
||||
global?: boolean
|
||||
|
||||
/**
|
||||
* @default true
|
||||
*/
|
||||
colorMode?: boolean
|
||||
|
||||
safelistColors?: string[]
|
||||
/**
|
||||
* Disables the global css styles added by the module.
|
||||
@@ -59,6 +66,7 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
},
|
||||
defaults: {
|
||||
prefix: 'U',
|
||||
colorMode: true,
|
||||
safelistColors: ['primary'],
|
||||
disableGlobalStyles: false
|
||||
},
|
||||
@@ -81,7 +89,9 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
// Modules
|
||||
|
||||
await installModule('@nuxt/icon')
|
||||
await installModule('@nuxtjs/color-mode', { classSuffix: '' })
|
||||
if (options.colorMode) {
|
||||
await installModule('@nuxtjs/color-mode', { classSuffix: '' })
|
||||
}
|
||||
await installTailwind(options, nuxt, resolve)
|
||||
|
||||
// Plugins
|
||||
|
||||
@@ -8,28 +8,27 @@
|
||||
</slot>
|
||||
<thead :class="ui.thead">
|
||||
<tr :class="ui.tr.base">
|
||||
<th v-if="modelValue" scope="col" :class="ui.checkbox.padding">
|
||||
<UCheckbox
|
||||
:model-value="isAllRowChecked"
|
||||
:indeterminate="indeterminate"
|
||||
v-bind="ui.default.checkbox"
|
||||
aria-label="Select all"
|
||||
@change="onChange"
|
||||
/>
|
||||
</th>
|
||||
|
||||
<th v-if="expand" scope="col" :class="ui.tr.base">
|
||||
<span class="sr-only">Expand</span>
|
||||
</th>
|
||||
|
||||
<th
|
||||
v-for="(column, index) in columns"
|
||||
:key="index"
|
||||
scope="col"
|
||||
:class="[ui.th.base, ui.th.padding, ui.th.color, ui.th.font, ui.th.size, column.class]"
|
||||
:class="[ui.th.base, ui.th.padding, ui.th.color, ui.th.font, ui.th.size, column.key === 'select' && ui.checkbox.padding, column.class]"
|
||||
:aria-sort="getAriaSort(column)"
|
||||
>
|
||||
<slot :name="`${column.key}-header`" :column="column" :sort="sort" :on-sort="onSort">
|
||||
<slot v-if="!singleSelect && modelValue && column.key === 'select'" name="select-header" :indeterminate="indeterminate" :checked="isAllRowChecked" :change="onChange">
|
||||
<UCheckbox
|
||||
:model-value="isAllRowChecked"
|
||||
:indeterminate="indeterminate"
|
||||
v-bind="ui.default.checkbox"
|
||||
aria-label="Select all"
|
||||
@change="onChange"
|
||||
/>
|
||||
</slot>
|
||||
|
||||
<slot v-else :name="`${column.key}-header`" :column="column" :sort="sort" :on-sort="onSort">
|
||||
<UButton
|
||||
v-if="column.sortable"
|
||||
v-bind="{ ...(ui.default.sortButton || {}), ...sortButton }"
|
||||
@@ -77,16 +76,7 @@
|
||||
|
||||
<template v-else>
|
||||
<template v-for="(row, index) in rows" :key="index">
|
||||
<tr :class="[ui.tr.base, isSelected(row) && ui.tr.selected, isExpanded(row) && ui.tr.expanded, $attrs.onSelect && ui.tr.active, row?.class]" @click="() => onSelect(row)">
|
||||
<td v-if="modelValue" :class="ui.checkbox.padding">
|
||||
<UCheckbox
|
||||
:model-value="isSelected(row)"
|
||||
v-bind="ui.default.checkbox"
|
||||
aria-label="Select row"
|
||||
@change="onChangeCheckbox($event, row)"
|
||||
@click.capture.stop="() => onSelect(row)"
|
||||
/>
|
||||
</td>
|
||||
<tr :class="[ui.tr.base, isSelected(row) && ui.tr.selected, isExpanded(row) && ui.tr.expanded, $attrs.onSelect && ui.tr.active, row?.class]" @click="() => onSelect(row)" @contextmenu="(event) => onContextmenu(event, row)">
|
||||
<td
|
||||
v-if="expand"
|
||||
:class="[ui.td.base, ui.td.padding, ui.td.color, ui.td.font, ui.td.size]"
|
||||
@@ -102,8 +92,26 @@
|
||||
@click.capture.stop="toggleOpened(row)"
|
||||
/>
|
||||
</td>
|
||||
<td v-for="(column, subIndex) in columns" :key="subIndex" :class="[ui.td.base, ui.td.padding, ui.td.color, ui.td.font, ui.td.size, column?.rowClass, row[column.key]?.class]">
|
||||
<slot :name="`${column.key}-data`" :column="column" :row="row" :index="index" :get-row-data="(defaultValue) => getRowData(row, column.key, defaultValue)">
|
||||
<td v-for="(column, subIndex) in columns" :key="subIndex" :class="[ui.td.base, ui.td.padding, ui.td.color, ui.td.font, ui.td.size, column?.rowClass, row[column.key]?.class, column.key === 'select' && ui.checkbox.padding]">
|
||||
<!-- This is a workaround: Since the @change event doesn't bubble up naturally, we need to wrap it in another element and use @click.capture.stop to simulate event bubbling behavior -->
|
||||
<span v-if="modelValue && column.key === 'select' " @click.capture.stop="() => {}">
|
||||
<slot name="select-data" :checked="isSelected(row)" :change="(ev: boolean) => onChangeCheckbox(ev, row)">
|
||||
<UCheckbox
|
||||
:model-value="isSelected(row)"
|
||||
v-bind="ui.default.checkbox"
|
||||
aria-label="Select row"
|
||||
@change="onChangeCheckbox($event, row)"
|
||||
/>
|
||||
</slot>
|
||||
</span>
|
||||
<slot
|
||||
v-else
|
||||
:name="`${column.key}-data`"
|
||||
:column="column"
|
||||
:row="row"
|
||||
:index="index"
|
||||
:get-row-data="(defaultValue) => getRowData(row, column.key, defaultValue)"
|
||||
>
|
||||
{{ getRowData(row, column.key) }}
|
||||
</slot>
|
||||
</td>
|
||||
@@ -130,12 +138,13 @@ import type { PropType, AriaAttributes } from 'vue'
|
||||
import { upperFirst } from 'scule'
|
||||
import { defu } from 'defu'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { isEqual } from 'ohash/utils'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import UButton from '../elements/Button.vue'
|
||||
import UProgress from '../elements/Progress.vue'
|
||||
import UCheckbox from '../forms/Checkbox.vue'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { mergeConfig, get } from '../../utils'
|
||||
import { get, mergeConfig } from '../../utils'
|
||||
import type { TableRow, TableColumn, Strategy, Button, ProgressColor, ProgressAnimation, DeepPartial, Expanded } from '../../types/index'
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
@@ -144,7 +153,7 @@ import { table } from '#ui/ui.config'
|
||||
const config = mergeConfig<typeof table>(appConfig.ui.strategy, appConfig.ui.table, table)
|
||||
|
||||
function defaultComparator<T>(a: T, z: T): boolean {
|
||||
return JSON.stringify(a) === JSON.stringify(z)
|
||||
return isEqual(a, z)
|
||||
}
|
||||
|
||||
function defaultSort(a: any, b: any, direction: 'asc' | 'desc') {
|
||||
@@ -159,6 +168,14 @@ function defaultSort(a: any, b: any, direction: 'asc' | 'desc') {
|
||||
}
|
||||
}
|
||||
|
||||
function getStringifiedSet(arr: TableRow[]) {
|
||||
return new Set(arr.map(item => JSON.stringify(item)))
|
||||
}
|
||||
|
||||
function accessor<T extends Record<string, any>>(key: string) {
|
||||
return (obj: T) => get(obj, key)
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
UIcon,
|
||||
@@ -221,7 +238,7 @@ export default defineComponent({
|
||||
default: false
|
||||
},
|
||||
loadingState: {
|
||||
type: Object as PropType<{ icon: string, label: string }>,
|
||||
type: Object as PropType<{ icon: string, label: string } | null>,
|
||||
default: () => config.default.loadingState
|
||||
},
|
||||
emptyState: {
|
||||
@@ -247,13 +264,40 @@ export default defineComponent({
|
||||
multipleExpand: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
singleSelect: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['update:modelValue', 'update:sort', 'update:expand'],
|
||||
emits: ['update:modelValue', 'update:sort', 'update:expand', 'select:all'],
|
||||
setup(props, { emit, attrs: $attrs }) {
|
||||
const { ui, attrs } = useUI('table', toRef(props, 'ui'), config, toRef(props, 'class'))
|
||||
|
||||
const columns = computed(() => props.columns ?? Object.keys(props.rows[0] ?? {}).map(key => ({ key, label: upperFirst(key), sortable: false, class: undefined, sort: defaultSort }) as TableColumn))
|
||||
const columns = computed(() => {
|
||||
const defaultColumns = props.columns ?? (
|
||||
Object.keys(props.rows[0]).map(key => ({
|
||||
key,
|
||||
label: upperFirst(key),
|
||||
sortable: false,
|
||||
class: undefined,
|
||||
sort: defaultSort
|
||||
}))
|
||||
) as TableColumn[]
|
||||
|
||||
const hasColumnSelect = defaultColumns.find(v => v.key === 'select')
|
||||
|
||||
if (hasColumnSelect || !props.modelValue) {
|
||||
return defaultColumns
|
||||
}
|
||||
|
||||
return [{
|
||||
key: 'select',
|
||||
sortable: false,
|
||||
class: undefined,
|
||||
sort: defaultSort
|
||||
}, ...defaultColumns]
|
||||
})
|
||||
|
||||
const sort = useVModel(props, 'sort', emit, { passive: true, defaultValue: defu({}, props.sort, { column: null, direction: 'asc' }) })
|
||||
const expand = useVModel(props, 'expand', emit, {
|
||||
@@ -292,8 +336,6 @@ export default defineComponent({
|
||||
}
|
||||
})
|
||||
|
||||
const getStringifiedSet = (arr: TableRow[]) => new Set(arr.map(item => JSON.stringify(item)))
|
||||
|
||||
const totalRows = computed(() => props.rows.length)
|
||||
|
||||
const countCheckedRow = computed(() => {
|
||||
@@ -328,10 +370,6 @@ export default defineComponent({
|
||||
return props.by(a, z)
|
||||
}
|
||||
|
||||
function accessor<T extends Record<string, any>>(key: string) {
|
||||
return (obj: T) => get(obj, key)
|
||||
}
|
||||
|
||||
function isSelected(row: TableRow) {
|
||||
if (!props.modelValue) {
|
||||
return false
|
||||
@@ -355,6 +393,11 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
function onSelect(row: TableRow) {
|
||||
const selection = window.getSelection()
|
||||
if (selection && selection.toString().length > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!$attrs.onSelect) {
|
||||
return
|
||||
}
|
||||
@@ -363,6 +406,15 @@ export default defineComponent({
|
||||
$attrs.onSelect(row)
|
||||
}
|
||||
|
||||
function onContextmenu(event, row) {
|
||||
if (!$attrs.onContextmenu) {
|
||||
return
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
$attrs.onContextmenu(event, row)
|
||||
}
|
||||
|
||||
function selectAllRows() {
|
||||
// Create a new array to ensure reactivity
|
||||
const newSelected = [...selected.value]
|
||||
@@ -384,14 +436,14 @@ export default defineComponent({
|
||||
} else {
|
||||
selected.value = []
|
||||
}
|
||||
emit('select:all', checked)
|
||||
}
|
||||
|
||||
function onChangeCheckbox(checked: boolean, row: TableRow) {
|
||||
if (checked) {
|
||||
selected.value.push(row)
|
||||
selected.value = props.singleSelect ? [row] : [...selected.value, row]
|
||||
} else {
|
||||
const index = selected.value.findIndex(item => compare(item, row))
|
||||
selected.value.splice(index, 1)
|
||||
selected.value = selected.value.filter(value => !compare(toRaw(value), toRaw(row)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,6 +503,7 @@ export default defineComponent({
|
||||
isSelected,
|
||||
onSort,
|
||||
onSelect,
|
||||
onContextmenu,
|
||||
onChange,
|
||||
getRowData,
|
||||
toggleOpened,
|
||||
|
||||
@@ -126,7 +126,7 @@ export default defineComponent({
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
emits: ['open'],
|
||||
emits: ['open', 'close'],
|
||||
setup(props, { emit }) {
|
||||
const { ui, attrs } = useUI('accordion', toRef(props, 'ui'), config, toRef(props, 'class'))
|
||||
|
||||
@@ -142,6 +142,8 @@ export default defineComponent({
|
||||
|
||||
if (!isOpenBefore && isOpenAfter) {
|
||||
emit('open', index)
|
||||
} else if (isOpenBefore && !isOpenAfter) {
|
||||
emit('close', index)
|
||||
}
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
{{ title }}
|
||||
</slot>
|
||||
</p>
|
||||
<div v-if="description || $slots.description" :class="twMerge(ui.description, !title && !$slots.title && 'mt-0 leading-5')">
|
||||
<div v-if="description || $slots.description" :class="twMerge(ui.description, !title && !$slots.title && ui.descriptionOnly)">
|
||||
<slot name="description" :description="description">
|
||||
{{ description }}
|
||||
</slot>
|
||||
@@ -42,13 +42,13 @@
|
||||
<script lang="ts">
|
||||
import { computed, toRef, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { twJoin } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import UAvatar from '../elements/Avatar.vue'
|
||||
import UButton from '../elements/Button.vue'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import type { Avatar, Button, AlertColor, AlertVariant, AlertAction, Strategy, DeepPartial } from '../../types/index'
|
||||
import { mergeConfig } from '../../utils'
|
||||
import { mergeConfig, twMerge } from '../../utils'
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
import { alert } from '#ui/ui.config'
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed, toRef, watch } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { twJoin } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { mergeConfig } from '../../utils'
|
||||
import { mergeConfig, twMerge } from '../../utils'
|
||||
import type { AvatarSize, AvatarChipColor, AvatarChipPosition, Strategy, DeepPartial } from '../../types/index'
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { h, cloneVNode, computed, toRef, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { twJoin } from 'tailwind-merge'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { mergeConfig, getSlotsChildren } from '../../utils'
|
||||
import type { AvatarSize, Strategy } from '../../types/index'
|
||||
import { getSlotsChildren, mergeConfig, twMerge } from '../../utils'
|
||||
import type { AvatarSize, DeepPartial, Strategy } from '../../types/index'
|
||||
import UAvatar from './Avatar.vue'
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
@@ -32,7 +32,7 @@ export default defineComponent({
|
||||
default: () => ''
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof avatarGroupConfig> & { strategy?: Strategy }>,
|
||||
type: Object as PropType<DeepPartial<typeof avatarGroupConfig> & { strategy?: Strategy }>,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
<template>
|
||||
<span :class="badgeClass" v-bind="attrs">
|
||||
<slot>{{ label }}</slot>
|
||||
<slot name="leading">
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="leadingIconClass" aria-hidden="true" />
|
||||
</slot>
|
||||
|
||||
<slot>
|
||||
<span v-if="label !== undefined && label !== null">
|
||||
{{ label }}
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
<slot name="trailing">
|
||||
<UIcon v-if="isTrailing && trailingIconName" :name="trailingIconName" :class="trailingIconClass" aria-hidden="true" />
|
||||
</slot>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, toRef, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { twJoin } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { mergeConfig } from '../../utils'
|
||||
import { mergeConfig, twMerge } from '../../utils'
|
||||
import { useInjectButtonGroup } from '../../composables/useButtonGroup'
|
||||
import type { BadgeColor, BadgeSize, BadgeVariant, DeepPartial, Strategy } from '../../types/index'
|
||||
// @ts-expect-error
|
||||
@@ -19,6 +32,9 @@ import { badge } from '#ui/ui.config'
|
||||
const config = mergeConfig<typeof badge>(appConfig.ui.strategy, appConfig.ui.badge, badge)
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
UIcon
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
size: {
|
||||
@@ -49,6 +65,26 @@ export default defineComponent({
|
||||
type: [String, Number],
|
||||
default: null
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
leadingIcon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
trailingIcon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
trailing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
leading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
class: {
|
||||
type: [String, Object, Array] as PropType<any>,
|
||||
default: () => ''
|
||||
@@ -63,6 +99,14 @@ export default defineComponent({
|
||||
|
||||
const { size, rounded } = useInjectButtonGroup({ ui, props })
|
||||
|
||||
const isLeading = computed(() => {
|
||||
return (props.icon && props.leading) || (props.icon && !props.trailing) || !props.trailing || props.leadingIcon
|
||||
})
|
||||
|
||||
const isTrailing = computed(() => {
|
||||
return (props.icon && props.trailing) || props.trailing || props.trailingIcon
|
||||
})
|
||||
|
||||
const badgeClass = computed(() => {
|
||||
const variant = ui.value.color?.[props.color as string]?.[props.variant as string] || ui.value.variant[props.variant]
|
||||
|
||||
@@ -71,13 +115,42 @@ export default defineComponent({
|
||||
ui.value.font,
|
||||
rounded.value,
|
||||
ui.value.size[size.value],
|
||||
ui.value.gap[size.value],
|
||||
variant?.replaceAll('{color}', props.color)
|
||||
), props.class)
|
||||
})
|
||||
|
||||
const leadingIconName = computed(() => {
|
||||
return props.leadingIcon || props.icon
|
||||
})
|
||||
|
||||
const trailingIconName = computed(() => {
|
||||
return props.trailingIcon || props.icon
|
||||
})
|
||||
|
||||
const leadingIconClass = computed(() => {
|
||||
return twJoin(
|
||||
ui.value.icon.base,
|
||||
ui.value.icon.size[size.value]
|
||||
)
|
||||
})
|
||||
|
||||
const trailingIconClass = computed(() => {
|
||||
return twJoin(
|
||||
ui.value.icon.base,
|
||||
ui.value.icon.size[size.value]
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
attrs,
|
||||
badgeClass
|
||||
isLeading,
|
||||
isTrailing,
|
||||
badgeClass,
|
||||
leadingIconName,
|
||||
trailingIconName,
|
||||
leadingIconClass,
|
||||
trailingIconClass
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</slot>
|
||||
|
||||
<slot>
|
||||
<span v-if="label" :class="[truncate ? ui.truncate : '']">
|
||||
<span v-if="label !== undefined && label !== null" :class="[truncate ? ui.truncate : '']">
|
||||
{{ label }}
|
||||
</span>
|
||||
</slot>
|
||||
@@ -19,11 +19,11 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, toRef } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { twJoin } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import ULink from '../elements/Link.vue'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { mergeConfig, nuxtLinkProps, getNuxtLinkProps } from '../../utils'
|
||||
import { getNuxtLinkProps, mergeConfig, nuxtLinkProps, twMerge } from '../../utils'
|
||||
import { useInjectButtonGroup } from '../../composables/useButtonGroup'
|
||||
import type { ButtonColor, ButtonSize, ButtonVariant, DeepPartial, Strategy } from '../../types/index'
|
||||
// @ts-expect-error
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { h, computed, toRef, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { twJoin } from 'tailwind-merge'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { mergeConfig, getSlotsChildren } from '../../utils'
|
||||
import { getSlotsChildren, mergeConfig, twMerge } from '../../utils'
|
||||
import { useProvideButtonGroup } from '../../composables/useButtonGroup'
|
||||
import type { ButtonSize, Strategy } from '../../types/index'
|
||||
import type { ButtonSize, DeepPartial, Strategy } from '../../types/index'
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
import { button, buttonGroup } from '#ui/ui.config'
|
||||
@@ -35,7 +35,7 @@ export default defineComponent({
|
||||
default: () => ''
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof buttonGroupConfig> & { strategy?: Strategy }>,
|
||||
type: Object as PropType<DeepPartial<typeof buttonGroupConfig> & { strategy?: Strategy }>,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -58,9 +58,8 @@
|
||||
<script lang="ts">
|
||||
import { ref, toRef, computed, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { useScroll, useResizeObserver, useElementSize } from '@vueuse/core'
|
||||
import { mergeConfig } from '../../utils'
|
||||
import { mergeConfig, twMerge } from '../../utils'
|
||||
import UButton from '../elements/Button.vue'
|
||||
import type { Strategy, Button, DeepPartial } from '../../types/index'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
@@ -106,7 +105,7 @@ export default defineComponent({
|
||||
default: () => ''
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<DeepPartial<typeof config & { strategy?: Strategy }>>,
|
||||
type: Object as PropType<DeepPartial<typeof config> & { strategy?: Strategy }>,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
|
||||
@@ -60,13 +60,13 @@ import { defineComponent, ref, computed, watch, toRef, onMounted, resolveCompone
|
||||
import type { PropType } from 'vue'
|
||||
import { Menu as HMenu, MenuButton as HMenuButton, MenuItems as HMenuItems, MenuItem as HMenuItem, provideUseId } from '@headlessui/vue'
|
||||
import { defu } from 'defu'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { twJoin } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import UAvatar from '../elements/Avatar.vue'
|
||||
import UKbd from '../elements/Kbd.vue'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { usePopper } from '../../composables/usePopper'
|
||||
import { mergeConfig, getNuxtLinkProps } from '../../utils'
|
||||
import { getNuxtLinkProps, mergeConfig, twMerge } from '../../utils'
|
||||
import type { DeepPartial, DropdownItem, PopperOptions, Strategy } from '../../types/index'
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
<script lang="ts">
|
||||
import { toRef, defineComponent, computed } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { twJoin } from 'tailwind-merge'
|
||||
import { useUI } from '../../composables/useUI'
|
||||
import { mergeConfig } from '../../utils'
|
||||
import { mergeConfig, twMerge } from '../../utils'
|
||||
import type { DeepPartial, KbdSize, Strategy } from '../../types/index'
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user