Compare commits

...

194 Commits

Author SHA1 Message Date
Benjamin Canac
6e4230fd63 chore(release): 2.12.0 2024-01-09 17:42:24 +01:00
Benjamin Canac
0be676a9ef docs: bump @nuxt/ui-pro-edge 2024-01-09 17:13:55 +01:00
Benjamin Canac
e48b61b5df docs(TableExampleAdvanced): improve sorting with v-model:sort and sort-mode props
Resolves #1177
2024-01-09 15:13:29 +01:00
Benjamin Canac
56e0c9a9a0 feat(Table): add sort-mode prop
Resolves #1149
2024-01-09 14:54:13 +01:00
Ivan Topolnjak
c6841d06a4 fix(Table): respect sort prop updates from parent component (#1208)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2024-01-09 13:03:02 +01:00
Benjamin Canac
8508e84958 chore(Table): rename columns sortFn to sort 2024-01-09 12:05:32 +01:00
Benjamin Canac
6154ae94a9 docs: bump @nuxt/ui-pro + @nuxt/image (required by BlogPost) 2024-01-08 17:29:19 +01:00
renovate[bot]
6384edf92a chore(deps): update all non-major dependencies (#1196)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2024-01-08 14:54:03 +01:00
Ragura
4f3af6cfdb feat(Table): add custom sort function to columns (#1075)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2024-01-08 12:28:19 +01:00
Daniel Roe
893b2466ff docs: ignore /pro when no token is provided (#1205) 2024-01-06 13:36:33 +01:00
Benjamin Canac
9807e58f8f docs(installation): add Modules and TypeScript section
Related to #1169, #1200, #571 and #1190
2024-01-05 18:54:29 +01:00
Benjamin Canac
4124406032 fix(Card)!: remove overflow-hidden on wrapper
Fixes #806, fixes #1034
2024-01-05 17:37:35 +01:00
Benjamin Canac
3258167a14 fix(forms): dont disable inputs and selects on loading
Resolves #1117
2024-01-05 17:35:18 +01:00
Benjamin Canac
520624bd64 chore(InputMenu): handle async search with search prop 2024-01-05 17:33:36 +01:00
Benjamin Canac
e4b8fffc32 docs(SelectMenu): improve async search example 2024-01-05 17:29:47 +01:00
Benjamin Canac
5d781112f1 fix(Alert): always pass a function to actions click events
Fixes #1197
2024-01-04 11:05:33 +01:00
Benjamin Canac
1c8122a00b chore(deps): pin vue to 3.3.13 2024-01-04 10:53:08 +01:00
Benjamin Canac
0976833753 feat(Pagination): add disabled prop
Resolves #1189
2024-01-03 18:18:01 +01:00
Benjamin Canac
bc00f9c4b2 fix(Popover): improve placement with hover mode
Improvement of #781
2024-01-03 17:21:35 +01:00
Benjamin Canac
c6aa4215d7 fix(Dropdown): improve placement with hover mode
Resolves #1179
2024-01-03 17:20:06 +01:00
Benjamin Canac
3334e2af3d fix(Popover): allow manual mode without blocking normal behaviour 2024-01-03 16:51:20 +01:00
Benjamin Canac
3844714644 feat(Dropdown): handle manual mode
Resolves #1143
2024-01-03 16:49:00 +01:00
Benjamin Canac
84e6392981 chore(deps): update lock 2024-01-03 15:44:33 +01:00
Benjamin Canac
c2ef6237d8 chore(InputMenu): allow control of search query 2024-01-03 15:13:34 +01:00
Benjamin Canac
f735db04d6 feat(SelectMenu): allow control of search query
Resolves #1174
2024-01-03 15:13:34 +01:00
Benjamin Canac
e8f573b6bb fix(SelectMenu): input border focus after tailwindcss 3.4 2024-01-03 15:13:34 +01:00
renovate[bot]
288abf239f chore(deps): update all non-major dependencies (#1184)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-03 14:54:34 +01:00
Daniel Roe
44d93a1cfd chore(Accordion): match event listener types (#1193) 2024-01-03 14:53:58 +01:00
Daniel Roe
217840bb41 docs: allow generating docs without github token (#1194) 2024-01-03 14:52:32 +01:00
Romain Hamel
ea2a24b5fe fix(Form): memory leak (#1185) 2024-01-02 16:36:35 +01:00
Romain Hamel
4a25a12390 feat(Form): expose submit function (#1186) 2024-01-02 16:28:38 +01:00
Sébastien Chopin
d64cb8a6fd chore: Update PULL_REQUEST_TEMPLATE.md 2024-01-02 14:57:32 +01:00
Benjamin Canac
00d0fd5919 fix(Table): display nothing instead of error when key is missing
Fixes #1173
2024-01-02 11:10:42 +01:00
Benjamin Canac
30e7a3ca20 chore(deps): update lock 2024-01-02 10:54:32 +01:00
renovate[bot]
7d572c81bb chore(deps): update all non-major dependencies (#1007)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-02 10:37:51 +01:00
John Puaoi
97a3975197 fix(Form): invalid errors when using clear by path (#1165) 2024-01-02 10:34:52 +01:00
Victor Akintunde
43b999c88e docs(notification): add default timeout value (#1181) 2024-01-02 10:33:08 +01:00
Benjamin Canac
7151b7b97d fix(Dropdown): merge item class
Fixes #1157
2023-12-28 13:14:17 +01:00
Conner Blanton
ffd20b3991 feat(VerticalNavigation): ability to add dividers (#963)
* feat(VerticalNavigation): ability to add sections with divider

* lint fix

* updating branch. resolving conflicts

* reverting app.vue

* removing unnecessary style

---------

Co-authored-by: Inesh Bose <dev@inesh.xyz>
2023-12-27 14:34:51 +01:00
Neil Mispelaar
29e64ca963 feat(VerticalNavigation): improve accessibility (#948)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-12-26 13:00:33 +01:00
Benjamin Canac
556ee0d9c4 docs: update dependencies 2023-12-26 12:19:24 +01:00
Benjamin Canac
debafef0fa chore(deps): update dependencies 2023-12-26 11:15:44 +01:00
Benjamin Canac
2d9038bcb0 chore(npmrc): ignore workspace root check 2023-12-26 11:06:36 +01:00
nathanjcollins
f7f8f06b91 chore(deps): update tailwindcss dependency to 3.4.0 (#1145)
* chore: update dependency for tailwindcss to 3.4

* refactor: change w-x h-x to size-x

* up

* up

* revert: h-x w-x to size-x

* fix: undo

* up

---------

Co-authored-by: Nathan Collins <nathancollins@Nathans-MacBook-Pro.local>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-12-26 10:56:57 +01:00
Benjamin Canac
56e1fed373 fix(useShortcuts): invalid code after #1159 2023-12-25 17:39:01 +01:00
Lukas
648eec31b9 fix(useShortcuts): include contenteditable="plaintext-only" elements in usingInput (#1159) 2023-12-25 17:34:24 +01:00
Benjamin Canac
d0ce8ee1c4 Revert "docs: pull nuxt/ui-pro docs from main branch"
This reverts commit 9d8f358139.
2023-12-21 16:19:31 +01:00
Benjamin Canac
9d8f358139 docs: pull nuxt/ui-pro docs from main branch 2023-12-21 11:18:14 +01:00
Jakub Chrobak
bc6474a9ad docs(installation): add bun command (#1141)
* docs: add bun installation command

* fix: add missing bracket
2023-12-20 12:28:14 +01:00
Benjamin Canac
31924e32f2 chore(deps): update 2023-12-19 18:16:39 +01:00
Benjamin Canac
c963ba688f docs(theming): improve Icons section 2023-12-19 17:51:27 +01:00
Benjamin Canac
4dee128524 chore(deps): update @egoist/tailwindcss-icons 2023-12-19 17:36:13 +01:00
Benjamin Canac
4c84839a01 fix(Toggle): add missing change event
Fixes #1113
2023-12-19 13:09:11 +01:00
renovate[bot]
fd30022550 chore(deps): update devdependency date-fns to v3 (#1127)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-19 11:40:59 +01:00
Daniel Roe
1a1c640220 chore: migrate to @nuxt/test-utils alpha (#1133)
* test: update snapshots to remove quotes

* chore: add alpha versions of test-utils

* chore: migrate to new test format

* test: slightly improve typing in suite

* test: improve safety of basic test
2023-12-19 11:37:57 +01:00
Daniel Roe
5c99ae131d fix: update vue and fix type issues (#1112)
* chore: bump vue version to show type errors

* fix: address type issues
2023-12-19 10:54:00 +01:00
Benjamin Canac
b22bd70d54 fix(config): prevent class merge of avatar size 2023-12-16 00:16:34 +01:00
Benjamin Canac
0c8ab9d98e fix(RadioGroup): pass option.disabled to children
Fixes #1109
2023-12-16 00:16:34 +01:00
Inesh Bose
0fdc8f70b6 feat(SelectMenu): allow creating option despite search (#1080)
* chore: initial

* chore: use reusable vnode

* fix: use component with vnode

* chore: option placement

* chore: finish

* up

* up

* up

* fix(selectmenu): non-object custom options

* up

---------

Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-12-15 15:04:06 +01:00
Benjamin Canac
23770d8cf0 chore(deps): update tailwind-merge 2023-12-15 14:42:57 +01:00
Benjamin Canac
84e75ad237 chore(playground): add tailwind.config.ts 2023-12-15 12:51:55 +01:00
Benjamin Canac
00dd8c27bd chore(playground): add app.config.ts 2023-12-15 12:50:58 +01:00
Benjamin Canac
5f81a79edf chore(Table): unused omit function 2023-12-15 11:37:08 +01:00
Benjamin Canac
1a02b3abe7 chore(Table): remove unused click attribute in rows 2023-12-14 17:17:43 +01:00
Benjamin Canac
83631ccbca fix(Link): handle active override when value is false 2023-12-14 14:32:31 +01:00
Benjamin Canac
0f9b5d47a6 docs(index): update components count 2023-12-13 15:20:48 +01:00
Benjamin Canac
f623ec1130 feat(Breadcrumb): handle labelClass and merge iconClass 2023-12-12 19:12:01 +01:00
Benjamin Canac
a79f7c0a34 feat(VerticalNavigation): handle labelClass and merge iconClass 2023-12-12 19:11:12 +01:00
Benjamin Canac
1c9835d7f1 feat(Dropdown): handle labelClass and merge iconClass
Resolves #716
2023-12-12 19:07:46 +01:00
Benjamin Canac
6d8d82a265 feat(InputMenu): new component (#1095) 2023-12-12 18:45:04 +01:00
Benjamin Canac
66a80c7486 docs(SelectMenu): add missing New badge on empty slot 2023-12-12 18:19:44 +01:00
Benjamin Canac
0546c7922c docs(ComponentPropsField): improve codeblocks line-height 2023-12-12 18:10:16 +01:00
Benjamin Canac
eafe707c7d docs(ComponentPropsField): wrong line-height on code blocks 2023-12-12 17:02:41 +01:00
Benjamin Canac
5d1919a538 feat(SelectMenu): add empty slot when no options
Resolves #1089
2023-12-12 16:27:42 +01:00
Benjamin Canac
781365a5ed docs(SelectMenu): improve 2023-12-12 16:27:42 +01:00
Benjamin Canac
0129e2db40 docs(SelectMenu): remove duplicate config 2023-12-12 16:27:22 +01:00
Benjamin Canac
45b1a4bd32 docs(releases): display pulls on release day too 2023-12-11 17:22:42 +01:00
Conner Blanton
f32f578125 feat(Popover): open and close events (#1038) 2023-12-11 17:19:19 +01:00
Benjamin Canac
4b044866a5 docs: add ads 2023-12-11 16:50:00 +01:00
Benjamin Canac
9b768ec12b docs: bump @nuxt/ui-pro-edge 2023-12-11 12:47:12 +01:00
Benjamin Canac
7584d72f42 chore(release): 2.11.1 2023-12-11 12:14:39 +01:00
Benjamin Canac
6b5ddc18bd docs: improve error page 2023-12-11 11:58:09 +01:00
Benjamin Canac
4dd92f7f36 chore(CommandPalette): filter not working after refactor 2023-12-08 18:40:40 +01:00
Benjamin Canac
cbc27422a4 docs: bump @nuxt/ui-pro-edge 2023-12-08 15:47:35 +01:00
Benjamin Canac
db508b218f fix(CommandPalette): improve performances and avoid multiple recompute 2023-12-08 15:28:53 +01:00
Benjamin Canac
ad33b26729 fix(CommandPalette): missing right padding on input with close button 2023-12-08 15:26:13 +01:00
Benjamin Canac
f07968afef fix(module): prevent class merging on default children
Fixes #1076
2023-12-07 17:29:36 +01:00
Benjamin Canac
a8dc9b216a docs: bump `@nuxt/ui-pro-edge 2023-12-07 17:15:05 +01:00
Benjamin Canac
32474e21f7 docs: bump `@nuxt/ui-pro-edge 2023-12-07 11:57:12 +01:00
Benjamin Canac
c023fb400c docs(ComponentCard): add ignoreVModel prop 2023-12-07 11:43:55 +01:00
Benjamin Canac
4548809ee5 docs(nuxt.config): add date-fns to vite.optimizeDeps 2023-12-06 22:33:45 +01:00
Benjamin Canac
6b52963339 docs(nuxt.config): typecheck with new nuxt-component-meta 2023-12-06 22:32:08 +01:00
Benjamin Canac
2c2ff0f473 chore(deps): update 2023-12-06 22:25:35 +01:00
Benjamin Canac
0b762d61e7 docs: bump @nuxt/ui-pro-edge 2023-12-06 22:13:21 +01:00
Benjamin Canac
9cbb68871c docs(SelectMenu): display config of ui and ui-menu props
Resolves  #1046
2023-12-06 22:13:10 +01:00
Benjamin Canac
7c5b47ea72 chore(Progress): remove useless cast 2023-12-06 18:43:47 +01:00
Romain Hamel
7196d81b4c fix(RadioGroup): props reactivity issues (#1065) 2023-12-06 17:15:05 +01:00
Benjamin Canac
1cb8df869f docs: bump @nuxt/ui-pro-edge 2023-12-06 16:11:24 +01:00
Benjamin Canac
67cc349c6c docs: bump @nuxt/ui-pro-edge 2023-12-06 16:02:40 +01:00
MiladHp
1f0f6181db fix(Notification): handle dynamic backgrounds (#1063)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-12-05 17:11:56 +01:00
Benjamin Canac
18b6133b11 docs: bump @nuxt/ui-pro-edge 2023-12-05 16:46:13 +01:00
Benjamin Canac
51bfb9a4e1 docs: use @nuxt/ui-pro-edge 2023-12-04 17:09:05 +01:00
Benjamin Canac
76e1cc84db chore(deps): update 2023-12-04 15:35:16 +01:00
Benjamin Canac
d539f2540b chore(deps): remove unused dev dependencies 2023-12-04 15:19:26 +01:00
Muhammad Mahmoud
e53cdeaf0b fix(Breadcrumb): handle divider in rtl (#1049) 2023-12-04 11:26:48 +01:00
Benjamin Canac
4d72a758fa fix(types): favor Record<string, any>> instead of object 2023-11-30 17:19:08 +01:00
Benjamin Canac
a2e9b7da07 chore(useUI): missing undefined in type 2023-11-30 16:54:54 +01:00
Benjamin Canac
e408eabd8b fix(components): move remaining classes to config (#1039) 2023-11-30 16:31:48 +01:00
Benjamin Canac
5718dfd69a fix(types): workaround for popper weak type
Fixes #644
2023-11-30 16:29:37 +01:00
Benjamin Canac
4a9b66aeb3 fix(types): improve with strict mode (#1041) 2023-11-30 12:02:37 +01:00
Benjamin Canac
464ff0b703 docs(OgImageDocs): handle when no description provided 2023-11-29 17:38:37 +01:00
Benjamin Canac
6984989a2c Revert "chore(deps): pin vitest"
This reverts commit 29efa99fb7.
2023-11-28 18:16:29 +01:00
Benjamin Canac
2dcc11ff89 chore(useUI): improve type 2023-11-28 16:38:00 +01:00
Benjamin Canac
29efa99fb7 chore(deps): pin vitest 2023-11-28 16:30:34 +01:00
Benjamin Canac
6c432028ae chore(useUI): improve type 2023-11-28 16:29:35 +01:00
Benjamin Canac
0270ce9251 docs(installation): remove duplicate codeblock on edge 2023-11-27 18:23:51 +01:00
Benjamin Canac
182e3b6e8f docs: bump @nuxt/ui-pro to stable 2023-11-23 12:39:14 +01:00
Benjamin Canac
26afa45fbf docs: remove New badges on edge version 2023-11-23 12:16:45 +01:00
Benjamin Canac
edd92d01a9 docs: fix invalid link 2023-11-23 11:22:45 +01:00
Benjamin Canac
e34c513b1a chore(release): 2.11.0 2023-11-23 11:15:23 +01:00
Conner Blanton
06d4510d1c feat(Popover): ability to add overlay (#1014) 2023-11-23 11:12:42 +01:00
Benjamin Canac
819b5f8a17 test: move Button to elements dir 2023-11-22 17:59:16 +01:00
Benjamin Canac
15a40f53f2 fix(Link): reactivity issue with active prop
Fixes nuxt/nuxt.com#1432
2023-11-22 15:24:36 +01:00
Benjamin Canac
dd55b4f602 docs: add missing New badges 2023-11-22 15:15:28 +01:00
Benjamin Canac
ec58948153 feat(module): allow options override of @egoist/tailwindcss-icons plugin (#1013) 2023-11-22 14:42:56 +01:00
Benjamin Canac
27db7fdd95 docs: bump @nuxt/ui-pro & @nuxtjs/mdc 2023-11-22 14:16:40 +01:00
renovate[bot]
2fc73ffafe chore(deps): update devdependency @release-it/conventional-changelog to v8 (#949)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-22 10:30:40 +01:00
renovate[bot]
5908d1a96b chore(deps): update devdependency release-it to v17 (#947)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-22 10:27:58 +01:00
Inesh Bose
d02858f6c4 refactor(config): break ui.config.ts into separate files (#930) 2023-11-22 10:26:31 +01:00
Levi (Nguyễn Lương Huy)
10ec3d533e docs(README): add and improve contributing guide, local development guide (#860) 2023-11-22 10:20:44 +01:00
Conner Blanton
d39e2de935 feat(FormGroup): add eager validation (#992) 2023-11-21 23:24:15 +01:00
Benjamin Canac
9df9b9a2df docs(releases): improve page 2023-11-21 23:02:35 +01:00
Italo
37fdf224c0 fix(SelectMenu): fixes non-strings and nested searchable attributes (#967)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-21 22:20:48 +01:00
renovate[bot]
73d0fa7273 chore(deps): update all non-major dependencies (#867)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-21 21:10:40 +01:00
Italo
11ccbbb24e feat(SelectMenu): allows to clear search query on close (#968)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-21 18:59:42 +01:00
renovate[bot]
ceb2ed36d4 chore(deps): update devdependency @testing-library/vue to v8 (#986)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-21 18:41:39 +01:00
Iván Máximiliano, Lo Giudice
83c3be716a feat(Notification): customize default timeout (#1003) 2023-11-21 18:34:08 +01:00
Daniel Roe
ca62ce13d3 fix(module): boolean types and bump nuxt to 3.8.2 (#1006) 2023-11-21 18:32:51 +01:00
Benjamin Canac
16663887ca docs(releases): display multiple pulls per day 2023-11-21 17:27:19 +01:00
Benjamin Canac
762c5ebba1 docs: add releases page (#1004) 2023-11-21 17:08:13 +01:00
Conner Blanton
f4be95dcf5 fix(ButtonGroup): handle components with children (#999)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-20 19:38:05 +01:00
Conner Blanton
c9b9bd6fb9 docs: sort component size prop (#956) 2023-11-20 17:00:16 +01:00
Benjamin Canac
55697e601e feat(Textarea): add default slot for complex usages
Resolves #971
2023-11-20 15:51:34 +01:00
Benjamin Canac
0cb5cc3947 docs: add pro section on landing 2023-11-20 14:22:04 +01:00
Pacman Doh
f245b4677c docs(VerticalNavigation): add truncate in icon slot example (#998) 2023-11-20 13:51:18 +01:00
Benjamin Canac
a1b38c4b66 feat(Checkbox): config label, required and help size 2023-11-19 13:17:52 +01:00
Conner Blanton
d4f1b5ef82 feat(Chip): new component (#886)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-19 13:04:07 +01:00
Benjamin Canac
6cc77a3e6c fix(Link): handle active state when to prop is not provided
Fixes #988
2023-11-17 18:56:54 +01:00
Benjamin Canac
7339324355 feat(types): support custom values from app.config.ts (#863) 2023-11-17 18:48:50 +01:00
Juho Rutila
bcc46b87f5 test: add initial component tests (#923)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-17 10:49:43 +01:00
Benjamin Canac
b666c4a1a8 docs(deps): bump @nuxt/ui-pro-edge 2023-11-16 18:14:00 +01:00
Haytham A. Salama
a35bfc7343 feat(Breadcrumb): new component (#506)
Co-authored-by: Eduard Aymerich <eduardaymerich@gmail.com>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-16 18:06:51 +01:00
Florian Zdrada
a97593985c fix(CommandPalette): activate first option after async search (#981) 2023-11-16 17:50:37 +01:00
Benjamin Canac
e1e5fa902b refactor(Dropdown): move item click logic to a proper function 2023-11-16 12:32:41 +01:00
Benjamin Canac
9b976a0b68 docs(ComponentCard): display model-value instead of value 2023-11-15 11:27:46 +01:00
Benjamin Canac
9952581d5b docs: remove useless label from RangeExample 2023-11-15 11:27:28 +01:00
Benjamin Canac
60e195ae60 docs(Toggle): put back lost v-model example
Resolves #916
2023-11-15 11:27:12 +01:00
Benjamin Canac
7c1052f3f7 docs(ComponentCard): add code prop to key to prevent duplicates 2023-11-15 11:11:25 +01:00
Benjamin Canac
60fa2beed0 fix(Dropdown): pass event to click function 2023-11-14 19:26:15 +01:00
Benjamin Canac
050c9c8db9 chore(deps): update lock 2023-11-14 17:42:44 +01:00
Benjamin Canac
9361d47cf7 docs: remove @iconify-json/logos 2023-11-14 17:42:14 +01:00
Benjamin Canac
b3caec3a7d docs: improve og image component 2023-11-14 17:37:56 +01:00
Benjamin Canac
4dbc6240c5 docs: prevent UNotifications slot #description override
Otherwise it alters the display of the Notification examples where actions moves under the title.
2023-11-14 17:21:39 +01:00
Benjamin Canac
7cb987de42 fix(Notification): improve config options 2023-11-14 17:19:59 +01:00
Benjamin Canac
91511b921d fix(Alert): improve config options
Resolves #760
2023-11-14 17:13:21 +01:00
Benjamin Canac
f323379909 fix(Dropdown): use NuxtLink with custom prop to close on select
Fixes #899
2023-11-14 16:26:24 +01:00
Benjamin Canac
ded6a7f73d fix(Notification): prevent gap when no close button or action 2023-11-14 15:55:57 +01:00
Benjamin Canac
9a1a1b8caf fix(Alert): prevent gap when no close button or action
Fixes #831
2023-11-14 15:55:57 +01:00
Sylvain Marroufin
de38afd97b fix(defineShortcuts): support minus - key (#962) 2023-11-14 14:24:46 +01:00
Romain Hamel
a3046aa256 fix(FormGroup): hydration mismatch on inputId (#942) 2023-11-14 14:23:51 +01:00
Conner Blanton
3c71bf36b0 feat(Toggle): add size prop (#950) 2023-11-11 22:42:05 +01:00
max
c55871b844 fix(Progress): percentage calculation (#939) 2023-11-11 17:11:11 +01:00
Benjamin Canac
0eb8d8f7ec docs: consistent usage of :component-example 2023-11-10 11:24:49 +01:00
max
68f6956d6e fix(Input/Textarea): add v-model modifiers (#856) 2023-11-10 11:05:58 +01:00
Benjamin Canac
6f0bfb5d89 chore(Icon): use computed for dynamic prop 2023-11-09 16:20:22 +01:00
Maxime Pauvert
4a62dac8a4 chore(package): add homepage (#929)
Co-authored-by: roiLeo <medina.leo42@gmail.com>
2023-11-08 17:43:07 +01:00
Benjamin Canac
042603a3c7 docs: use new prose component Tabs (#920) 2023-11-07 13:01:42 +01:00
Benjamin Canac
c601fc6c55 feat(Icon): switch to nuxt-icon with dynamic prop or app config (#862) 2023-11-06 18:27:14 +01:00
Benjamin Canac
196e9ac7d4 docs: remove Pricing from pro header 2023-11-06 15:48:18 +01:00
Sébastien Chopin
bfe418f614 docs: update nuxt-og-image 2023-11-06 14:54:33 +01:00
Benjamin Canac
3d205d0c8a docs: move pro navigation at the end on edge version 2023-11-06 11:56:12 +01:00
Benjamin Canac
f3c491a417 chore(release-it): improve github release name 2023-11-04 15:36:43 +01:00
Benjamin Canac
d7cbd05533 docs: bump @nuxt/ui-pro 2023-11-03 16:46:19 +01:00
Arash
8451f4d9bb fix(Notifications): teleport to body (#909) 2023-11-03 15:08:52 +01:00
Benjamin Canac
c153138db1 docs: prevent err on page not found 2023-11-03 14:38:02 +01:00
Daniel Roe
c73a2ab676 docs: don't add pro path if it doesn't exist (#917)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-03 14:37:54 +01:00
Romain Hamel
e81d5cf998 fix(FormGroup): remove inputId if the input is a fieldset (#914) 2023-11-03 14:31:15 +01:00
Benjamin Canac
7891ccb9ac test: lint 2023-11-03 11:45:41 +01:00
Daniel Roe
c84438f491 fix(module): use correct alias for #ui-colors (#913) 2023-11-03 11:40:26 +01:00
Benjamin Canac
844b3185e9 docs: integrate @nuxt/ui-pro (#739)
Co-authored-by: Pooya Parsa <pooya@pi0.io>
Co-authored-by: Florent Delerue <florentdelerue@hotmail.com>
Co-authored-by: Sébastien Chopin <seb@nuxt.com>
2023-11-02 16:44:44 +01:00
Juho Rutila
ed4b5e0077 test: add unit tests for the module (#892)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
2023-11-02 11:00:20 +01:00
Conner Blanton
a2d70f04e9 fix(Radio): prevent help text from inlining with label (#894) 2023-10-31 14:29:48 +01:00
Benjamin Canac
1f9a063d98 docs: remove New badges for edge 2023-10-31 10:33:49 +01:00
Benjamin Canac
033910d90a docs: invalid radio links 2023-10-31 10:33:35 +01:00
258 changed files with 11340 additions and 6588 deletions

View File

@@ -4,7 +4,7 @@
### 🔗 Linked issue
<!-- Please ensure there is an open issue and mention its number as #123 -->
<!-- Please ensure there is an open issue and mention its number as: Fixes #123 -->
### ❓ Type of change

View File

@@ -21,6 +21,9 @@ jobs:
os: [ubuntu-latest] # macos-latest, windows-latest
node: [18]
env:
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
steps:
- uses: actions/setup-node@v4
with:
@@ -74,6 +77,9 @@ jobs:
- name: Build
run: pnpm run build
- 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

View File

@@ -14,6 +14,9 @@ jobs:
os: [ubuntu-latest] # macos-latest, windows-latest
node: [18]
env:
NUXT_GITHUB_TOKEN: ${{ secrets.NUXT_GITHUB_TOKEN }}
steps:
- uses: actions/setup-node@v4
with:
@@ -58,6 +61,9 @@ jobs:
- name: Build
run: pnpm run build
- name: Test
run: pnpm run test run
- name: Version Check
id: check
uses: EndBug/version-check@v2

1
.npmrc
View File

@@ -1,2 +1,3 @@
shamefully-hoist=true
auto-install-peers=true
ignore-workspace-root-check=true

View File

@@ -1,3 +1,2 @@
imports.autoImport=false
typescript.includeWorkspace=true
typescript.strict=false

View File

@@ -7,6 +7,7 @@
},
"github": {
"release": true,
"releaseName": "v${version}",
"web": true
},
"hooks": {

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"prettier.enable": false
}

View File

@@ -1,5 +1,121 @@
# Changelog
## [2.12.0](https://github.com/nuxt/ui/compare/v2.11.1...v2.12.0) (2024-01-09)
### ⚠ BREAKING CHANGES
* **Card:** remove `overflow-hidden` on wrapper
### Features
* **Breadcrumb:** handle `labelClass` and merge `iconClass` ([f623ec1](https://github.com/nuxt/ui/commit/f623ec1130edf448988784b36c15a850470685c4))
* **Dropdown:** handle `labelClass` and merge `iconClass` ([1c9835d](https://github.com/nuxt/ui/commit/1c9835d7f149231cf2e3e053e5ea08eceeaaa61d)), closes [#716](https://github.com/nuxt/ui/issues/716)
* **Dropdown:** handle manual mode ([3844714](https://github.com/nuxt/ui/commit/38447146445618a1310a6315c608f4cd21069e17)), closes [#1143](https://github.com/nuxt/ui/issues/1143)
* **Form:** expose submit function ([#1186](https://github.com/nuxt/ui/issues/1186)) ([4a25a12](https://github.com/nuxt/ui/commit/4a25a12390f8ecae83c1081c89eba99a8fda14f8))
* **InputMenu:** new component ([#1095](https://github.com/nuxt/ui/issues/1095)) ([6d8d82a](https://github.com/nuxt/ui/commit/6d8d82a265692aaee556e40b09e4b3048ae044da))
* **Pagination:** add `disabled` prop ([0976833](https://github.com/nuxt/ui/commit/0976833753cd2140649bc324f53a263d4e09ecff)), closes [#1189](https://github.com/nuxt/ui/issues/1189)
* **Popover:** open and close events ([#1038](https://github.com/nuxt/ui/issues/1038)) ([f32f578](https://github.com/nuxt/ui/commit/f32f578125c12b35e59db2f7981c8b1b5a146397))
* **SelectMenu:** add `empty` slot when no options ([5d1919a](https://github.com/nuxt/ui/commit/5d1919a5381b316637d50405d287428f67f2b9cc)), closes [#1089](https://github.com/nuxt/ui/issues/1089)
* **SelectMenu:** allow control of search query ([f735db0](https://github.com/nuxt/ui/commit/f735db04d62fca678ca30ecd565b32e70bcda3e0)), closes [#1174](https://github.com/nuxt/ui/issues/1174)
* **SelectMenu:** allow creating option despite search ([#1080](https://github.com/nuxt/ui/issues/1080)) ([0fdc8f7](https://github.com/nuxt/ui/commit/0fdc8f70b6a656114d30b07d682e4edcd61a23fb))
* **Table:** add `sort-mode` prop ([56e0c9a](https://github.com/nuxt/ui/commit/56e0c9a9a05e1e8491e2d460b8d51084bd2c1305)), closes [#1149](https://github.com/nuxt/ui/issues/1149)
* **Table:** add custom sort function to columns ([#1075](https://github.com/nuxt/ui/issues/1075)) ([4f3af6c](https://github.com/nuxt/ui/commit/4f3af6cfdb5213d1be3d2680fcf3a95f7b3bc0b3))
* **VerticalNavigation:** ability to add dividers ([#963](https://github.com/nuxt/ui/issues/963)) ([ffd20b3](https://github.com/nuxt/ui/commit/ffd20b3991a35ae7fa0e249fa009e330fd963705))
* **VerticalNavigation:** handle `labelClass` and merge `iconClass` ([a79f7c0](https://github.com/nuxt/ui/commit/a79f7c0a34c0414fe4feb95691e1f044b07ef087))
* **VerticalNavigation:** improve accessibility ([#948](https://github.com/nuxt/ui/issues/948)) ([29e64ca](https://github.com/nuxt/ui/commit/29e64ca963eeed1e82640957860f43391d8683ed))
### Bug Fixes
* **Alert:** always pass a function to actions click events ([5d78111](https://github.com/nuxt/ui/commit/5d781112f1eb464658c83047bf80c2ea7c9a2b05)), closes [#1197](https://github.com/nuxt/ui/issues/1197)
* **Card:** remove `overflow-hidden` on wrapper ([4124406](https://github.com/nuxt/ui/commit/412440603206151d63b04ffe6bed1bbc5b0e6615)), closes [#806](https://github.com/nuxt/ui/issues/806) [#1034](https://github.com/nuxt/ui/issues/1034)
* **config:** prevent class merge of `avatar` size ([b22bd70](https://github.com/nuxt/ui/commit/b22bd70d54e68c3217ba42690210084749fee656))
* **Dropdown:** improve placement with `hover` mode ([c6aa421](https://github.com/nuxt/ui/commit/c6aa4215d7f9003adeefa7cdff76c7a88715f20c)), closes [#1179](https://github.com/nuxt/ui/issues/1179)
* **Dropdown:** merge item `class` ([7151b7b](https://github.com/nuxt/ui/commit/7151b7b97d42f389506521044ebaffa8a299e7fb)), closes [#1157](https://github.com/nuxt/ui/issues/1157)
* **Form:** invalid errors when using `clear` by path ([#1165](https://github.com/nuxt/ui/issues/1165)) ([97a3975](https://github.com/nuxt/ui/commit/97a39751977bf1e942e2bafd5839141383b7af2f))
* **Form:** memory leak ([#1185](https://github.com/nuxt/ui/issues/1185)) ([ea2a24b](https://github.com/nuxt/ui/commit/ea2a24b5fe6ddc87e6eb951a662ce8b84b9d987f))
* **forms:** dont disable inputs and selects on `loading` ([3258167](https://github.com/nuxt/ui/commit/3258167a1431b664cd1dcc925a4b3fe06a996831)), closes [#1117](https://github.com/nuxt/ui/issues/1117)
* **Link:** handle `active` override when value is false ([83631cc](https://github.com/nuxt/ui/commit/83631ccbca1364f012b0c2899f97e2166dd1d360))
* **Popover:** allow manual mode without blocking normal behaviour ([3334e2a](https://github.com/nuxt/ui/commit/3334e2af3de2844de08ee530e62f2e4e2fd7ed24))
* **Popover:** improve placement with `hover` mode ([bc00f9c](https://github.com/nuxt/ui/commit/bc00f9c4b25dd4b99cb6e53014624f41ee929654)), closes [#781](https://github.com/nuxt/ui/issues/781)
* **RadioGroup:** pass `option.disabled` to children ([0c8ab9d](https://github.com/nuxt/ui/commit/0c8ab9d98e494c49cceac111edc0606ee4d63638)), closes [#1109](https://github.com/nuxt/ui/issues/1109)
* **SelectMenu:** input border focus after `tailwindcss` 3.4 ([e8f573b](https://github.com/nuxt/ui/commit/e8f573b6bb32a22873d9f93b40883ca12b481d7e))
* **Table:** display nothing instead of error when key is missing ([00d0fd5](https://github.com/nuxt/ui/commit/00d0fd59192cc171abb3d2ddaee46b2b9fa9422f)), closes [#1173](https://github.com/nuxt/ui/issues/1173)
* **Table:** respect sort prop updates from parent component ([#1208](https://github.com/nuxt/ui/issues/1208)) ([c6841d0](https://github.com/nuxt/ui/commit/c6841d06a48ffef95d238f94a4822a1e48b85422))
* **Toggle:** add missing `change` event ([4c84839](https://github.com/nuxt/ui/commit/4c84839a0183756b9f8df8674aace8cd40e44dcd)), closes [#1113](https://github.com/nuxt/ui/issues/1113)
* update vue and fix type issues ([#1112](https://github.com/nuxt/ui/issues/1112)) ([5c99ae1](https://github.com/nuxt/ui/commit/5c99ae131d1a50a8db21f1d5794a06080c515831))
* **useShortcuts:** include `contenteditable="plaintext-only"` elements in `usingInput` ([#1159](https://github.com/nuxt/ui/issues/1159)) ([648eec3](https://github.com/nuxt/ui/commit/648eec31b99fcffb65c042e0a5587da941c8e90f))
* **useShortcuts:** invalid code after [#1159](https://github.com/nuxt/ui/issues/1159) ([56e1fed](https://github.com/nuxt/ui/commit/56e1fed373786fc158ca9da9f02a9ec4e273afce))
### Reverts
* Revert "docs: pull `nuxt/ui-pro` docs from `main` branch" ([d0ce8ee](https://github.com/nuxt/ui/commit/d0ce8ee1c4a3d7b2285885d76e02e03168011110))
## [2.11.1](https://github.com/nuxt/ui/compare/v2.11.0...v2.11.1) (2023-12-11)
### Bug Fixes
* **Breadcrumb:** handle divider in rtl ([#1049](https://github.com/nuxt/ui/issues/1049)) ([e53cdea](https://github.com/nuxt/ui/commit/e53cdeaf0b3746da76cb6a658a5f71064d97fc9a))
* **CommandPalette:** improve performances and avoid multiple recompute ([db508b2](https://github.com/nuxt/ui/commit/db508b218f5277b2522566f790bd268eae2ee1e5))
* **CommandPalette:** missing right padding on input with close button ([ad33b26](https://github.com/nuxt/ui/commit/ad33b26729b1bf3d21f8d480e04c197f4fbb6119))
* **components:** move remaining classes to config ([#1039](https://github.com/nuxt/ui/issues/1039)) ([e408eab](https://github.com/nuxt/ui/commit/e408eabd8b841cdf8c71ce27c35c9675f2db8625))
* **module:** prevent class merging on `default` children ([f07968a](https://github.com/nuxt/ui/commit/f07968afef263d38183ce6c9cd9185ef7eee0494)), closes [#1076](https://github.com/nuxt/ui/issues/1076)
* **Notification:** handle dynamic backgrounds ([#1063](https://github.com/nuxt/ui/issues/1063)) ([1f0f618](https://github.com/nuxt/ui/commit/1f0f6181db7fa1ab45b8f7fec8df1cedccaec688))
* **RadioGroup:** props reactivity issues ([#1065](https://github.com/nuxt/ui/issues/1065)) ([7196d81](https://github.com/nuxt/ui/commit/7196d81b4cecf1711a01bed5fed1236ab3b2398b))
* **types:** favor `Record<string, any>>` instead of `object` ([4d72a75](https://github.com/nuxt/ui/commit/4d72a758fad5cffa09f3aaf6b3df9baf7edc2a9f))
* **types:** improve with strict mode ([#1041](https://github.com/nuxt/ui/issues/1041)) ([4a9b66a](https://github.com/nuxt/ui/commit/4a9b66aeb32a332e2d5be7e236e5d4567044b3e2))
* **types:** workaround for `popper` weak type ([5718dfd](https://github.com/nuxt/ui/commit/5718dfd69a7040987354485b30f7da7aee342abb)), closes [#644](https://github.com/nuxt/ui/issues/644)
### Reverts
* Revert "chore(deps): pin `vitest`" ([6984989](https://github.com/nuxt/ui/commit/6984989a2c20fbde177d1e64ea1a7cae07f03c4d))
## [2.11.0](https://github.com/nuxt/ui/compare/v2.10.0...v2.11.0) (2023-11-23)
### Features
* **Breadcrumb:** new component ([#506](https://github.com/nuxt/ui/issues/506)) ([a35bfc7](https://github.com/nuxt/ui/commit/a35bfc734372cd24a8f86fca7b69f091051ce918))
* **Checkbox:** config `label`, `required` and `help` size ([a1b38c4](https://github.com/nuxt/ui/commit/a1b38c4b66a16fefe8b514ec699a84309fcb7225))
* **Chip:** new component ([#886](https://github.com/nuxt/ui/issues/886)) ([d4f1b5e](https://github.com/nuxt/ui/commit/d4f1b5ef82f58c2df4dd9491ceb61b55da7ba4c3))
* **FormGroup:** add eager validation ([#992](https://github.com/nuxt/ui/issues/992)) ([d39e2de](https://github.com/nuxt/ui/commit/d39e2de935bcbbaf86c4b4b368e81bb08859b2e6))
* **Icon:** switch to `nuxt-icon` with `dynamic` prop or app config ([#862](https://github.com/nuxt/ui/issues/862)) ([c601fc6](https://github.com/nuxt/ui/commit/c601fc6c5583763a2cdf6c575dda55c46311612a))
* **module:** allow options override of `@egoist/tailwindcss-icons` plugin ([#1013](https://github.com/nuxt/ui/issues/1013)) ([ec58948](https://github.com/nuxt/ui/commit/ec58948153eb9c3048c41187ae505072a817b746))
* **Notification:** customize default timeout ([#1003](https://github.com/nuxt/ui/issues/1003)) ([83c3be7](https://github.com/nuxt/ui/commit/83c3be716aa42eee70a1bbc3b8a28b7fa483c9bf))
* **Popover:** ability to add overlay ([#1014](https://github.com/nuxt/ui/issues/1014)) ([06d4510](https://github.com/nuxt/ui/commit/06d4510d1c485ede49d1572454aeb8581384626e))
* **SelectMenu:** allows to clear search query on close ([#968](https://github.com/nuxt/ui/issues/968)) ([11ccbbb](https://github.com/nuxt/ui/commit/11ccbbb24ef61e6bd3bb703f950955dd21d6a3eb))
* **Textarea:** add default slot for complex usages ([55697e6](https://github.com/nuxt/ui/commit/55697e601e9b94e2159aa27613edd7265d5d06af)), closes [#971](https://github.com/nuxt/ui/issues/971)
* **Toggle:** add `size` prop ([#950](https://github.com/nuxt/ui/issues/950)) ([3c71bf3](https://github.com/nuxt/ui/commit/3c71bf36b0232745765c6860af2be7f44bf948a0))
* **types:** support custom values from `app.config.ts` ([#863](https://github.com/nuxt/ui/issues/863)) ([7339324](https://github.com/nuxt/ui/commit/7339324355362eebd30707fdd1944270e41525f4))
### Bug Fixes
* **Alert:** improve config options ([91511b9](https://github.com/nuxt/ui/commit/91511b921d65150f8da9c71e361d305477234f84)), closes [#760](https://github.com/nuxt/ui/issues/760)
* **Alert:** prevent `gap` when no close button or action ([9a1a1b8](https://github.com/nuxt/ui/commit/9a1a1b8caf1c040c458230458b9fa9cbfb32a1bb)), closes [#831](https://github.com/nuxt/ui/issues/831)
* **ButtonGroup:** handle components with children ([#999](https://github.com/nuxt/ui/issues/999)) ([f4be95d](https://github.com/nuxt/ui/commit/f4be95dcf5a07c964ae9f2555070d437e0388c13))
* **CommandPalette:** activate first option after async search ([#981](https://github.com/nuxt/ui/issues/981)) ([a975939](https://github.com/nuxt/ui/commit/a97593985c93d4cc30ceff0e3bdf8070f17b63f6))
* **defineShortcuts:** support minus `-` key ([#962](https://github.com/nuxt/ui/issues/962)) ([de38afd](https://github.com/nuxt/ui/commit/de38afd97b7bfd9af2619a17a42f27177abfec7e))
* **Dropdown:** pass event to `click` function ([60fa2be](https://github.com/nuxt/ui/commit/60fa2beed0ef0dbac6429033cc96803edf847120))
* **Dropdown:** use `NuxtLink` with `custom` prop to close on select ([f323379](https://github.com/nuxt/ui/commit/f3233799096b18b1d6c86391799a7c98a110fa4d)), closes [#899](https://github.com/nuxt/ui/issues/899)
* **FormGroup:** hydration mismatch on inputId ([#942](https://github.com/nuxt/ui/issues/942)) ([a3046aa](https://github.com/nuxt/ui/commit/a3046aa25626ca50e9d9fc6288321940445e88a1))
* **FormGroup:** remove inputId if the input is a fieldset ([#914](https://github.com/nuxt/ui/issues/914)) ([e81d5cf](https://github.com/nuxt/ui/commit/e81d5cf99831cfc320049051eeaf36f15951282b))
* **Input/Textarea:** add `v-model` modifiers ([#856](https://github.com/nuxt/ui/issues/856)) ([68f6956](https://github.com/nuxt/ui/commit/68f6956d6e0cb5155e19b8d464a42953b8e30475))
* **Link:** handle `active` state when `to` prop is not provided ([6cc77a3](https://github.com/nuxt/ui/commit/6cc77a3e6cbb263b649de0ea044894e0b7c4258a)), closes [#988](https://github.com/nuxt/ui/issues/988)
* **Link:** reactivity issue with `active` prop ([15a40f5](https://github.com/nuxt/ui/commit/15a40f53f218bbe768262efc03dd7eaaf147ed6e)), closes [nuxt/nuxt.com#1432](https://github.com/nuxt/nuxt.com/issues/1432)
* **module:** `boolean` types and bump nuxt to `3.8.2` ([#1006](https://github.com/nuxt/ui/issues/1006)) ([ca62ce1](https://github.com/nuxt/ui/commit/ca62ce13d3238819475528de0340416e6db9e5e6))
* **module:** use correct alias for `[#ui](https://github.com/nuxt/ui/issues/ui)-colors` ([#913](https://github.com/nuxt/ui/issues/913)) ([c84438f](https://github.com/nuxt/ui/commit/c84438f491e7e3f8af5c6d892a2141b9ada2c155))
* **Notification:** improve config options ([7cb987d](https://github.com/nuxt/ui/commit/7cb987de42ad89efc227eef47a8e06e7bc93206f))
* **Notification:** prevent `gap` when no close button or action ([ded6a7f](https://github.com/nuxt/ui/commit/ded6a7f73d9ea57b5e771ce192c9ee36e6f98bba))
* **Notifications:** teleport to `body` ([#909](https://github.com/nuxt/ui/issues/909)) ([8451f4d](https://github.com/nuxt/ui/commit/8451f4d9bbe51972688966f529cf0713060adb7a))
* **Progress:** percentage calculation ([#939](https://github.com/nuxt/ui/issues/939)) ([c55871b](https://github.com/nuxt/ui/commit/c55871b8449e9947e84ecb2f9667eea287b579e6))
* **Radio:** prevent `help` text from inlining with label ([#894](https://github.com/nuxt/ui/issues/894)) ([a2d70f0](https://github.com/nuxt/ui/commit/a2d70f04e98ce181ac217eaf6b66a8728af95805))
* **SelectMenu:** fixes non-strings and nested searchable attributes ([#967](https://github.com/nuxt/ui/issues/967)) ([37fdf22](https://github.com/nuxt/ui/commit/37fdf224c07e47312c731b20080533ad7d8d786c))
## [2.10.0](https://github.com/nuxt/ui/compare/v2.9.0...v2.10.0) (2023-10-31)
@@ -854,4 +970,4 @@
* **Toggle:** add missing `computed` import ([0f09c9b](https://github.com/nuxtlabs/ui/commit/0f09c9baae501458af029f853c78b1c10a3ac133))
* **Tooltip:** missing `ref` import ([b08a8cc](https://github.com/nuxtlabs/ui/commit/b08a8cc0ac79e89817e338281a81c477d5ec645a))
* **useTimer:** remove log ([c6dcbd1](https://github.com/nuxtlabs/ui/commit/c6dcbd1b2b542dab1850504a60451a485e2d4004))
* **VerticalNavigation:** add `v-if` on label ([79d8e08](https://github.com/nuxtlabs/ui/commit/79d8e086f0c61887c52da6fe4a13f1bdf7077227))
* **VerticalNavigation:** add `v-if` on label ([79d8e08](https://github.com/nuxtlabs/ui/commit/79d8e086f0c61887c52da6fe4a13f1bdf7077227))

View File

@@ -71,6 +71,17 @@ Visit https://ui.nuxt.com to explore the documentation.
- [vueuse/vueuse](https://github.com/vueuse/vueuse)
- [egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons)
## Contributing
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.
## 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.
## License
Licensed under the [MIT license](https://github.com/nuxt/ui/blob/dev/LICENSE.md).

View File

@@ -1,6 +1,8 @@
# To link Nuxt UI Pro in development
# Specify the path of @nuxt/ui-pro locally
NUXT_UI_PRO_PATH=
# To use Nuxt UI Pro in production
NUXT_UI_PRO_TOKEN=
# Production token for @nuxt/ui-pro, purchase on https://ui.nuxt.com/pro/purchase
NUXT_UI_PRO_LICENSE=
# Used when pre-rendering the docs for dynamic OG images
NUXT_PUBLIC_SITE_URL=
# Used to fetch `nuxt/ui-pro` docs content
NUXT_GITHUB_TOKEN=

View File

@@ -1,26 +1,22 @@
<!-- eslint-disable vue/no-v-html -->
<template>
<div>
<Header />
<Header v-if="!$route.path.startsWith('/examples')" :links="links" />
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
<Footer />
<Footer v-if="!$route.path.startsWith('/examples')" />
<ClientOnly>
<LazyUDocsSearch ref="searchRef" :files="files" :navigation="navigation" :groups="groups" />
<LazyUDocsSearch ref="searchRef" :files="files" :navigation="navigation" :groups="groups" :links="links" />
</ClientOnly>
<UNotifications>
<template #title="{ title }">
<span v-html="title" />
</template>
<template #description="{ description }">
<span v-html="description" />
</template>
</UNotifications>
</div>
</template>
@@ -42,10 +38,17 @@ const { data: files } = useLazyFetch<ParsedContent[]>('/api/search.json', { defa
// Computed
const navigation = computed(() => {
const main = nav.value.filter(item => item._path !== '/dev')
const dev = nav.value.find(item => item._path === '/dev')?.children
if (branch.value?.name === 'dev') {
const dev = nav.value.find(item => item._path === '/dev')?.children
const pro = nav.value.find(item => item._path === '/pro')
return branch.value?.name === 'dev' ? dev : main
return [
...dev,
...(pro ? [pro] : [])
]
}
return nav.value.filter(item => item._path !== '/dev')
})
const groups = computed(() => {
@@ -58,6 +61,47 @@ const groups = computed(() => {
const color = computed(() => colorMode.value === 'dark' ? '#18181b' : 'white')
const links = computed(() => {
return [{
label: 'Documentation',
icon: 'i-heroicons-book-open',
to: `${branch.value?.name === 'dev' ? '/dev' : ''}/getting-started`
}, {
label: 'Playground',
icon: 'i-simple-icons-stackblitz',
to: '/playground'
}, {
label: 'Roadmap',
icon: 'i-heroicons-academic-cap',
to: '/roadmap'
}, !!navigation.value.find(item => item._path === '/pro') && {
label: 'Pro',
icon: 'i-heroicons-square-3-stack-3d',
to: '/pro',
children: [{
label: 'Features',
to: '/pro',
exact: true,
icon: 'i-heroicons-beaker',
description: 'Discover all the features of Nuxt UI Pro.'
}, {
label: 'Guide',
to: '/pro/guide',
icon: 'i-heroicons-book-open',
description: 'Learn how to use Nuxt UI Pro in your app.'
}, {
label: 'Components',
to: '/pro/components',
icon: 'i-heroicons-cube-transparent',
description: 'Discover all the components available in Nuxt UI Pro.'
}]
}, {
label: 'Releases',
icon: 'i-heroicons-rocket-launch',
to: '/releases'
}].filter(Boolean)
})
// Watch
watch(() => searchRef.value?.commandPaletteRef?.query, debounce((query: string) => {

View File

@@ -1,22 +1,16 @@
<template>
<div v-if="$route.path !== '/playground'" class="w-full h-px bg-gray-200 dark:bg-gray-800 flex items-center justify-center">
<div class="bg-white dark:bg-gray-900 px-4">
<div class="w-full h-px bg-gray-200 dark:bg-gray-800 flex items-center justify-center">
<div v-if="!['/playground', '/roadmap'].includes($route.path)" class="bg-white dark:bg-gray-900 px-4">
<LogoOnly class="w-5 h-5" />
</div>
</div>
<UFooter :links="[]" :ui="{ bottom: { container: 'lg:py-4' } }">
<UFooter>
<template #left>
<div class="text-sm text-gray-500 dark:text-gray-400">
Made by
<NuxtLink to="https://nuxtlabs.com" aria-label="NuxtLabs" class="inline-block">
<LogoLabs class="text-gray-900 dark:text-white h-4 w-auto" />
</NuxtLink>
</div>
</template>
<template #center>
<span class="text-sm text-gray-500 dark:text-gray-400">
<a v-if="$route.path.startsWith('/pro')" class="text-sm text-gray-500 dark:text-gray-400 hover:underline" href="https://ui.nuxt.com/pro/purchase" target="_blank">
Purchase Nuxt UI Pro
</a>
<span v-else class="text-sm text-gray-500 dark:text-gray-400">
Published under <NuxtLink to="https://github.com/nuxt/ui" target="_blank" class="text-gray-900 dark:text-white">
MIT License
</NuxtLink>

View File

@@ -31,42 +31,35 @@
</template>
<template #panel>
<BranchSelect />
<UAsideLinks :links="links" />
<UNavigationTree :links="mapContentNavigation(navigation)" />
<UDivider type="dashed" class="mt-4 mb-3" />
<BranchSelect v-if="!route.path.startsWith('/pro')" />
<UNavigationTree :links="mapContentNavigation(navigation)" :multiple="false" default-open />
</template>
</UHeader>
</template>
<script setup lang="ts">
import type { NavItem } from '@nuxt/content/dist/runtime/types'
import type { Link } from '#ui-pro/types'
defineProps<{
links: Link[]
}>()
const route = useRoute()
const { metaSymbol } = useShortcuts()
const navigation = inject<Ref<NavItem[]>>('navigation')
const nav = inject<Ref<NavItem[]>>('navigation')
const links = computed(() => {
return [{
label: 'Documentation',
icon: 'i-heroicons-book-open-solid',
to: '/getting-started'
}, {
label: 'Examples',
icon: 'i-heroicons-square-3-stack-3d',
to: '/getting-started/examples'
}, {
label: 'Playground',
icon: 'i-simple-icons-stackblitz',
to: '/playground'
}, {
label: 'Pro',
icon: 'i-heroicons-square-3-stack-3d',
to: '/pro'
}, {
label: 'Releases',
icon: 'i-heroicons-rocket-launch-solid',
to: 'https://github.com/nuxt/ui/releases',
target: '_blank'
}]
const navigation = computed(() => {
if (route.path.startsWith('/pro')) {
return nav.value.find(item => item._path === '/pro')?.children
}
return nav.value.filter(item => !item._path.startsWith('/pro'))
})
</script>

View File

@@ -1,11 +0,0 @@
<template>
<svg width="1020" height="200" viewBox="0 0 1020 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M377 200C379.16 200 381 198.209 381 196V103C381 103 386 112 395 127L434 194C435.785 197.74 439.744 200 443 200H470V50H443C441.202 50 439 51.4941 439 54V148L421 116L385 55C383.248 51.8912 379.479 50 376 50H350V200H377Z" fill="currentColor" />
<path d="M726 92H739C742.314 92 745 89.3137 745 86V60H773V92H800V116H773V159C773 169.5 778.057 174 787 174H800V200H783C759.948 200 745 185.071 745 160V116H726V92Z" fill="currentColor" />
<path d="M591 92V154C591 168.004 585.742 179.809 578 188C570.258 196.191 559.566 200 545 200C530.434 200 518.742 196.191 511 188C503.389 179.809 498 168.004 498 154V92H514C517.412 92 520.769 92.622 523 95C525.231 97.2459 526 98.5652 526 102V154C526 162.059 526.457 167.037 530 171C533.543 174.831 537.914 176 545 176C552.217 176 555.457 174.831 559 171C562.543 167.037 563 162.059 563 154V102C563 98.5652 563.769 96.378 566 94C567.96 91.9107 570.028 91.9599 573 92C573.411 92.0055 574.586 92 575 92H591Z" fill="currentColor" />
<path d="M676 144L710 92H684C680.723 92 677.812 93.1758 676 96L660 120L645 97C643.188 94.1758 639.277 92 636 92H611L645 143L608 200H634C637.25 200 640.182 196.787 642 194L660 167L679 195C680.818 197.787 683.75 200 687 200H713L676 144Z" fill="currentColor" />
<path d="M168 200H279C282.542 200 285.932 198.756 289 197C292.068 195.244 295.23 193.041 297 190C298.77 186.959 300.002 183.51 300 179.999C299.998 176.488 298.773 173.04 297 170.001L222 41C220.23 37.96 218.067 35.7552 215 34C211.933 32.2448 207.542 31 204 31C200.458 31 197.067 32.2448 194 34C190.933 35.7552 188.77 37.96 187 41L168 74L130 9.99764C128.228 6.95784 126.068 3.75491 123 2C119.932 0.245087 116.542 0 113 0C109.458 0 106.068 0.245087 103 2C99.9323 3.75491 96.7717 6.95784 95 9.99764L2 170.001C0.226979 173.04 0.00154312 176.488 1.90993e-06 179.999C-0.0015393 183.51 0.229648 186.959 2 190C3.77035 193.04 6.93245 195.244 10 197C13.0675 198.756 16.4578 200 20 200H90C117.737 200 137.925 187.558 152 164L186 105L204 74L259 168H186L168 200ZM89 168H40L113 42L150 105L125.491 147.725C116.144 163.01 105.488 168 89 168Z" fill="#00DC82" />
<path d="M958 60.0001H938C933.524 60.0001 929.926 59.9395 927 63C924.074 65.8905 925 67.5792 925 72V141C925 151.372 923.648 156.899 919 162C914.352 166.931 908.468 169 899 169C889.705 169 882.648 166.931 878 162C873.352 156.899 873 151.372 873 141V72.0001C873 67.5793 872.926 65.8906 870 63.0001C867.074 59.9396 863.476 60.0001 859 60.0001H840V141C840 159.023 845.016 173.458 855 184C865.156 194.542 879.893 200 899 200C918.107 200 932.844 194.542 943 184C953.156 173.458 958 159.023 958 141V60.0001Z" fill="#00DC82" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M1000 60.0233L1020 60V77L1020 128V156.007L1020 181L1020 189.004C1020 192.938 1019.98 194.429 1017 197.001C1014.02 199.725 1009.56 200 1005 200H986.001V181.006L986 130.012V70.0215C986 66.1576 986.016 64.5494 989 62.023C991.819 59.6358 995.437 60.0233 1000 60.0233Z" fill="#00DC82" />
</svg>
</template>

View File

@@ -1,13 +0,0 @@
<template>
<svg width="1240" height="200" viewBox="0 0 1240 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M168 200H279C282.542 200 285.932 198.756 289 197C292.068 195.244 295.23 193.041 297 190C298.77 186.959 300.002 183.51 300 179.999C299.998 176.488 298.773 173.04 297 170.001L222 41C220.23 37.96 218.067 35.7552 215 34C211.933 32.2448 207.542 31 204 31C200.458 31 197.067 32.2448 194 34C190.933 35.7552 188.77 37.96 187 41L168 74L130 9.99764C128.228 6.95784 126.068 3.75491 123 2C119.932 0.245087 116.542 0 113 0C109.458 0 106.068 0.245087 103 2C99.9323 3.75491 96.7717 6.95784 95 9.99764L2 170.001C0.226979 173.04 0.00154312 176.488 1.90993e-06 179.999C-0.0015393 183.51 0.229648 186.959 2 190C3.77035 193.04 6.93245 195.244 10 197C13.0675 198.756 16.4578 200 20 200H90C117.737 200 137.925 187.558 152 164L186 105L204 74L259 168H186L168 200ZM89 168H40L113 42L150 105L125.491 147.725C116.144 163.01 105.488 168 89 168Z" fill="currentColor" />
<path d="M375 200C377.16 200 379 198.209 379 196V103C379 103 384 112 393 127L432 194C433.785 197.74 437.744 200 441 200H468V50H441C439.202 50 437 51.4941 437 54V148L419 116L383 55C381.248 51.8912 377.479 50 374 50H348V200H375Z" fill="currentColor" />
<path d="M724 92H737C740.314 92 743 89.3137 743 86V60H771V92H798V116H771V159C771 169.5 776.057 174 785 174H798V200H781C757.948 200 743 185.071 743 160V116H724V92Z" fill="currentColor" />
<path d="M589 154V92H573L572.832 92.0002L572.498 92.001H572.497C571.979 92.0023 571.294 92.004 571 92L570.912 91.9988C567.987 91.9592 565.941 91.9315 564 94C561.769 96.378 561 98.5652 561 102V154C561 162.059 560.543 167.037 557 171C553.457 174.831 550.217 176 543 176C535.914 176 531.543 174.831 528 171C524.457 167.037 524 162.059 524 154V102C524 98.5652 523.231 97.2459 521 95C518.769 92.622 515.412 92 512 92H496V154C496 168.004 501.389 179.809 509 188C516.742 196.191 528.434 200 543 200C557.566 200 568.258 196.191 576 188C583.742 179.809 589 168.004 589 154Z" fill="currentColor" />
<path d="M674 144L708 92H682C678.723 92 675.812 93.1758 674 96L658 120L643 97C641.188 94.1758 637.277 92 634 92H609L643 143L606 200H632C635.25 200 638.182 196.787 640 194L658 167L677 195C678.818 197.787 681.75 200 685 200H711L674 144Z" fill="currentColor" />
<path d="M931 200V175H868V66C868 62.6863 865.314 60 862 60H838V194C838 197.314 840.686 200 844 200H931Z" fill="currentColor" />
<path d="M1202 200C1225.14 200 1240 187.277 1240 169C1240 143.04 1220.69 140.838 1205.16 139.067C1194.72 137.877 1186 136.882 1186 129C1186 122.908 1190.35 120 1198 120C1205.45 120 1213.82 123.813 1215 132H1232.68C1236.12 132 1238.91 129.086 1238.06 125.757C1234.16 110.512 1218.99 101 1198 101C1177.8 101 1163 113.056 1163 130C1163 153.784 1181.4 156.618 1196.52 158.946C1207.06 160.569 1216 161.946 1216 170C1216 175.331 1209.43 179 1201 179C1190.8 179 1183.98 174.567 1183 166H1166.29C1162.87 166 1160.08 168.888 1160.81 172.233C1164.58 189.368 1180.39 200 1202 200Z" fill="currentColor" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M1151 149C1151 179.068 1133.34 200 1104 200C1092.58 200 1081.51 195.469 1076 188V200H1049V60H1076V111C1081.51 103.914 1091.59 100 1104 100C1132.95 100 1151 118.932 1151 149ZM1075 150C1075 166.088 1084.23 177 1099 177C1113.37 177 1123 166.088 1123 150C1123 133.721 1113.37 122 1099 122C1084.23 122 1075 133.721 1075 150Z" fill="currentColor" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M1005 105C998.647 101.954 991.004 101 983 101C974.487 101 967.353 101.954 961 105C954.647 108.046 949.558 112.669 946 118C943.659 121.424 941.966 124.9 940.973 128.721C940.105 132.063 942.911 135 946.364 135H963C963.254 130.685 964.951 127.919 968 125C971.176 122.081 975.537 120 981 120C986.336 120 990.951 121.462 994 124C997.049 126.412 999 129.938 999 134C999 136.031 998.271 137.604 997 139C995.729 140.269 993.287 141 991 141H975C964.454 141 956.48 143.542 950 149C943.647 154.331 940 161.608 940 171C940 176.458 941.332 181.558 944 186C946.668 190.315 950.299 193.462 955 196C959.828 198.412 965.901 200 972 200C978.607 200 984.172 198.667 989 196.002C993.955 193.21 997.348 189.442 999 185V200H1025V137C1025 129.892 1022.68 123.331 1019 118C1015.44 112.542 1011.35 107.919 1005 105ZM993.173 174.679C989.615 178.74 984.66 180.771 978.307 180.771C974.623 180.771 971.573 179.819 969.159 177.915C966.745 175.885 965.538 173.283 965.538 170.11C965.538 166.429 966.809 163.446 969.35 161.162C971.891 158.877 975.194 157.735 979.26 157.735H998.7V159.067C998.7 165.413 996.857 170.617 993.173 174.679Z" fill="currentColor" />
</svg>
</template>

View File

@@ -11,23 +11,180 @@ defineProps({
description: {
type: String,
required: true
},
headline: {
type: String,
default: ''
}
})
</script>
<template>
<div class="w-full h-full flex flex-col justify-between items-start bg-[#020420] p-20 pt-32 pb-16">
<div
style="position: absolute;width: 1156px;height: 1000px;left: -215px;top: -337px;background: radial-gradient(50% 50% at 50% 50%, #00DC82 0%, rgba(0, 220, 130, 0) 100%);filter: blur(180.5px);opacity: 0.5;"
/>
<div>
<h1 class="text-8xl mb-4 text-white">
{{ title }}
<div class="w-full h-full flex flex-col justify-center bg-slate-900">
<svg
class="absolute right-0 top-0"
width="629"
height="593"
viewBox="0 0 629 593"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g filter="url(#filter0_f_199_94966)">
<path d="M628.5 -578L639.334 -94.4223L806.598 -548.281L659.827 -87.387L965.396 -462.344L676.925 -74.0787L1087.69 -329.501L688.776 -55.9396L1160.22 -164.149L694.095 -34.9354L1175.13 15.7948L692.306 -13.3422L1130.8 190.83L683.602 6.50012L1032.04 341.989L668.927 22.4412L889.557 452.891L649.872 32.7537L718.78 511.519L628.5 36.32L538.22 511.519L607.128 32.7537L367.443 452.891L588.073 22.4412L224.955 341.989L573.398 6.50012L126.198 190.83L564.694 -13.3422L81.8734 15.7948L562.905 -34.9354L96.7839 -164.149L568.224 -55.9396L169.314 -329.501L580.075 -74.0787L291.604 -462.344L597.173 -87.387L450.402 -548.281L617.666 -94.4223L628.5 -578Z" fill="#00DC82" />
</g>
<defs>
<filter
id="filter0_f_199_94966"
x="0.873535"
y="-659"
width="1255.25"
height="1251.52"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feGaussianBlur stdDeviation="40.5" result="effect1_foregroundBlur_199_94966" />
</filter>
</defs>
</svg>
<div class="w-[700px] pl-[100px]">
<p v-if="headline" class="uppercase text-[24px] text-[#00DC82] mb-4 font-semibold">
{{ headline }}
</p>
<h1 class="m-0 text-[75px] font-semibold mb-2 text-white flex items-center">
<span>{{ title }}</span>
</h1>
<p class="text-5xl text-gray-200 leading-tight pr-10">
{{ description }}
<p v-if="description" class="text-[32px] text-[#94a3b8] leading-tight">
{{ description.slice(0, 200) }}
</p>
</div>
<LogoGreen class="w-[306px] h-[60px] text-white" />
<svg
class="absolute top-[160px] right-[90px]"
width="340"
height="340"
viewBox="0 0 340 340"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M86.6286 103.106C88.2099 94.7477 94.7477 88.2099 103.106 86.6286L104.427 86.3788C146.343 78.4485 189.386 78.5576 231.262 86.7002L232.272 86.8967C239.615 88.3244 245.4 93.99 246.981 101.301L247.277 102.671C256.565 145.63 256.438 190.092 246.903 232.997C245.361 239.939 239.939 245.361 232.997 246.903C190.092 256.438 145.63 256.565 102.671 247.277L101.301 246.981C93.99 245.4 88.3244 239.615 86.8967 232.272L86.7002 231.262C78.5576 189.386 78.4485 146.343 86.3788 104.426L86.6286 103.106Z" fill="url(#paint0_linear_199_94959)" />
<path d="M86.6286 103.106C88.2099 94.7477 94.7477 88.2099 103.106 86.6286L104.427 86.3788C146.343 78.4485 189.386 78.5576 231.262 86.7002L232.272 86.8967C239.615 88.3244 245.4 93.99 246.981 101.301L247.277 102.671C256.565 145.63 256.438 190.092 246.903 232.997C245.361 239.939 239.939 245.361 232.997 246.903C190.092 256.438 145.63 256.565 102.671 247.277L101.301 246.981C93.99 245.4 88.3244 239.615 86.8967 232.272L86.7002 231.262C78.5576 189.386 78.4485 146.343 86.3788 104.426L86.6286 103.106Z" fill="url(#paint1_radial_199_94959)" fill-opacity="0.06" />
<path d="M103.028 86.2151C94.4994 87.8286 87.8286 94.4994 86.2151 103.028L85.9653 104.348C78.0252 146.318 78.1344 189.414 86.2872 231.342L86.4836 232.353C87.9434 239.86 93.7366 245.776 101.212 247.392L102.582 247.688C145.601 256.989 190.124 256.862 233.089 247.314C240.19 245.736 245.736 240.19 247.314 233.089C256.862 190.124 256.989 145.601 247.688 102.582L247.392 101.212C245.776 93.7366 239.86 87.9434 232.353 86.4836L231.342 86.2872C189.414 78.1344 146.318 78.0252 104.348 85.9653L103.028 86.2151Z" stroke="url(#paint2_linear_199_94959)" stroke-opacity="0.2" stroke-width="0.841584" />
<path d="M86.5693 66.0418C76.1888 68.0728 68.0728 76.1888 66.0418 86.5693L65.7807 87.9041C55.4495 140.708 55.5631 195.024 66.1151 247.784L66.3095 248.756C68.1871 258.144 75.4486 265.527 84.8039 267.561L86.1767 267.86C140.001 279.561 195.755 279.425 249.525 267.477C258.483 265.486 265.485 258.489 267.475 249.53C279.429 195.737 279.558 139.989 267.852 86.1413L267.553 84.7671C265.524 75.4341 258.158 68.19 248.793 66.3169L247.784 66.1151C195.024 55.5631 140.708 55.4495 87.904 65.7807L86.5693 66.0418Z" stroke="url(#paint3_linear_199_94959)" stroke-opacity="0.6" stroke-width="1.7" />
<path d="M66.1749 44.2983C55.2117 46.6476 46.6475 55.2117 44.2983 66.1749L43.1523 71.5228C29.5422 135.037 29.5422 200.713 43.1523 264.227L44.425 270.166C46.7026 280.795 54.917 289.15 65.5055 291.608C132.857 307.243 203.127 307.189 270.477 291.554C280.924 289.129 289.129 280.924 291.554 270.477C307.189 203.127 307.243 132.857 291.608 65.5055C289.15 54.917 280.795 46.7026 270.166 44.425L264.227 43.1523C200.713 29.5422 135.037 29.5422 71.5228 43.1523L66.1749 44.2983Z" stroke="url(#paint4_linear_199_94959)" stroke-opacity="0.4" stroke-width="1.7" />
<path d="M47.0949 24.9846C36.0029 27.3375 27.3375 36.0029 24.9846 47.0949L19.3193 73.8027C5.86738 137.219 5.96967 202.762 19.6195 266.137L25.0028 291.131C27.3518 302.037 35.8106 310.592 46.6894 313.064L67.2583 317.739C134.879 333.107 205.098 332.991 272.667 317.398L291.54 313.043C302.229 310.576 310.576 302.229 313.043 291.54L317.398 272.667C332.991 205.098 333.107 134.879 317.739 67.2583L313.064 46.6894C310.592 35.8106 302.037 27.3518 291.131 25.0028L266.137 19.6195C202.762 5.96966 137.219 5.86738 73.8027 19.3193L47.0949 24.9846Z" stroke="url(#paint5_linear_199_94959)" stroke-opacity="0.2" stroke-width="2.125" />
<path d="M174.667 190.325H203.105C204.009 190.325 204.896 190.084 205.678 189.626C206.461 189.168 207.11 188.509 207.561 187.715C208.013 186.921 208.25 186.021 208.25 185.105C208.25 184.188 208.011 183.288 207.559 182.495L188.461 148.938C188.009 148.145 187.36 147.486 186.578 147.028C185.796 146.57 184.909 146.328 184.006 146.328C183.103 146.328 182.215 146.57 181.433 147.028C180.651 147.486 180.002 148.145 179.551 148.938L174.667 157.524L165.119 140.734C164.668 139.941 164.018 139.282 163.236 138.824C162.453 138.366 161.566 138.125 160.663 138.125C159.76 138.125 158.872 138.366 158.09 138.824C157.308 139.282 156.658 139.941 156.206 140.734L132.441 182.495C131.989 183.288 131.75 184.188 131.75 185.105C131.75 186.021 131.987 186.921 132.439 187.715C132.89 188.509 133.539 189.168 134.322 189.626C135.104 190.084 135.991 190.325 136.895 190.325H154.746C161.819 190.325 167.035 187.173 170.624 181.025L179.337 165.717L184.004 157.524L198.011 182.133H179.337L174.667 190.325ZM154.455 182.124L141.997 182.121L160.671 149.312L169.989 165.717L163.75 176.681C161.367 180.671 158.659 182.124 154.455 182.124Z" fill="#00DC82" />
<path d="M176.761 189.109H203.105H203.106C203.792 189.109 204.467 188.926 205.064 188.576C205.66 188.227 206.158 187.723 206.504 187.113L207.561 187.715L206.504 187.113C206.851 186.504 207.034 185.811 207.034 185.105C207.033 184.399 206.85 183.707 206.502 183.098L206.502 183.097L187.404 149.54L187.404 149.54C187.057 148.93 186.56 148.427 185.963 148.077C185.367 147.728 184.692 147.545 184.006 147.545C183.32 147.545 182.645 147.728 182.048 148.077C181.452 148.427 180.954 148.93 180.608 149.539C180.608 149.539 180.608 149.54 180.608 149.54L175.725 158.126L174.667 159.985L173.61 158.125L164.062 141.336L176.761 189.109ZM176.761 189.109L180.044 183.349H198.011H200.103L199.069 181.531L185.061 156.922L184.005 155.066L182.947 156.922L178.28 165.115L178.28 165.115L169.57 180.417C166.187 186.208 161.362 189.109 154.746 189.109H136.895H136.894C136.208 189.109 135.533 188.926 134.936 188.576C134.34 188.227 133.842 187.723 133.496 187.113L132.44 187.714L133.496 187.113C133.149 186.504 132.966 185.811 132.966 185.105C132.967 184.399 133.15 183.707 133.498 183.098L133.498 183.097L157.263 141.336C157.263 141.336 157.263 141.336 157.263 141.336C157.61 140.727 158.108 140.223 158.705 139.874C159.301 139.525 159.976 139.341 160.663 139.341C161.349 139.341 162.025 139.525 162.621 139.874L163.236 138.824L162.621 139.874C163.218 140.223 163.715 140.727 164.062 141.336L176.761 189.109ZM154.454 183.34H154.455C156.699 183.34 158.653 182.952 160.391 181.953C162.126 180.957 163.533 179.417 164.794 177.305L164.801 177.294L164.807 177.283L171.046 166.318L171.388 165.717L171.047 165.116L161.729 148.711L160.672 146.851L159.614 148.71L140.94 181.52L139.905 183.337L141.997 183.338L154.454 183.34Z" stroke="url(#paint6_linear_199_94959)" stroke-opacity="0.2" stroke-width="2.43271" />
<g filter="url(#filter0_f_199_94959)">
<path d="M174.667 190.325H203.105C204.009 190.325 204.896 190.084 205.678 189.626C206.461 189.168 207.11 188.509 207.561 187.715C208.013 186.921 208.25 186.021 208.25 185.105C208.25 184.188 208.011 183.288 207.559 182.495L188.461 148.938C188.009 148.145 187.36 147.486 186.578 147.028C185.796 146.57 184.909 146.328 184.006 146.328C183.103 146.328 182.215 146.57 181.433 147.028C180.651 147.486 180.002 148.145 179.551 148.938L174.667 157.524L165.119 140.734C164.668 139.941 164.018 139.282 163.236 138.824C162.453 138.366 161.566 138.125 160.663 138.125C159.76 138.125 158.872 138.366 158.09 138.824C157.308 139.282 156.658 139.941 156.206 140.734L132.441 182.495C131.989 183.288 131.75 184.188 131.75 185.105C131.75 186.021 131.987 186.921 132.439 187.715C132.89 188.509 133.539 189.168 134.322 189.626C135.104 190.084 135.991 190.325 136.895 190.325H154.746C161.819 190.325 167.035 187.173 170.624 181.025L179.337 165.717L184.004 157.524L198.011 182.133H179.337L174.667 190.325ZM154.455 182.124L141.997 182.121L160.671 149.312L169.989 165.717L163.75 176.681C161.367 180.671 158.659 182.124 154.455 182.124Z" fill="#00DC82" />
<path d="M176.761 189.109H203.105H203.106C203.792 189.109 204.467 188.926 205.064 188.576C205.66 188.227 206.158 187.723 206.504 187.113L207.561 187.715L206.504 187.113C206.851 186.504 207.034 185.811 207.034 185.105C207.033 184.399 206.85 183.707 206.502 183.098L206.502 183.097L187.404 149.54L187.404 149.54C187.057 148.93 186.56 148.427 185.963 148.077C185.367 147.728 184.692 147.545 184.006 147.545C183.32 147.545 182.645 147.728 182.048 148.077C181.452 148.427 180.954 148.93 180.608 149.539C180.608 149.539 180.608 149.54 180.608 149.54L175.725 158.126L174.667 159.985L173.61 158.125L164.062 141.336L176.761 189.109ZM176.761 189.109L180.044 183.349H198.011H200.103L199.069 181.531L185.061 156.922L184.005 155.066L182.947 156.922L178.28 165.115L178.28 165.115L169.57 180.417C166.187 186.208 161.362 189.109 154.746 189.109H136.895H136.894C136.208 189.109 135.533 188.926 134.936 188.576C134.34 188.227 133.842 187.723 133.496 187.113L132.44 187.714L133.496 187.113C133.149 186.504 132.966 185.811 132.966 185.105C132.967 184.399 133.15 183.707 133.498 183.098L133.498 183.097L157.263 141.336C157.263 141.336 157.263 141.336 157.263 141.336C157.61 140.727 158.108 140.223 158.705 139.874C159.301 139.525 159.976 139.341 160.663 139.341C161.349 139.341 162.025 139.525 162.621 139.874L163.236 138.824L162.621 139.874C163.218 140.223 163.715 140.727 164.062 141.336L176.761 189.109ZM154.454 183.34H154.455C156.699 183.34 158.653 182.952 160.391 181.953C162.126 180.957 163.533 179.417 164.794 177.305L164.801 177.294L164.807 177.283L171.046 166.318L171.388 165.717L171.047 165.116L161.729 148.711L160.672 146.851L159.614 148.71L140.94 181.52L139.905 183.337L141.997 183.338L154.454 183.34Z" stroke="url(#paint7_linear_199_94959)" stroke-opacity="0.2" stroke-width="2.43271" />
</g>
<defs>
<filter
id="filter0_f_199_94959"
x="124.176"
y="130.551"
width="91.6485"
height="67.3485"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feGaussianBlur stdDeviation="3.78713" result="effect1_foregroundBlur_199_94959" />
</filter>
<linearGradient
id="paint0_linear_199_94959"
x1="167.875"
y1="74.375"
x2="88"
y2="261"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#0F172A" />
<stop offset="1" stop-color="#0F172A" stop-opacity="0" />
</linearGradient>
<radialGradient
id="paint1_radial_199_94959"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(167.875 167.875) rotate(-90) scale(100.596 107.502)"
>
<stop stop-color="white" />
<stop offset="1" stop-opacity="0" />
</radialGradient>
<linearGradient
id="paint2_linear_199_94959"
x1="247.183"
y1="96.4978"
x2="194.172"
y2="229.234"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="white" />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<linearGradient
id="paint3_linear_199_94959"
x1="267.01"
y1="78.6537"
x2="200.746"
y2="244.574"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#00DC82" />
<stop offset="1" stop-opacity="0" />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<linearGradient
id="paint4_linear_199_94959"
x1="292.405"
y1="57.8159"
x2="209.877"
y2="264.463"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#00DC82" />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<linearGradient
id="paint5_linear_199_94959"
x1="314.196"
y1="40.2232"
x2="217.813"
y2="281.562"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#00DC82" />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<linearGradient
id="paint6_linear_199_94959"
x1="202.444"
y1="144.3"
x2="191.546"
y2="184.293"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="white" />
<stop offset="1" stop-opacity="0" />
</linearGradient>
<linearGradient
id="paint7_linear_199_94959"
x1="202.444"
y1="144.3"
x2="191.546"
y2="184.293"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="white" />
<stop offset="1" stop-opacity="0" />
</linearGradient>
</defs>
</svg>
</div>
</template>

View File

@@ -0,0 +1,45 @@
<template>
<div ref="carbonads" class="carbon" />
</template>
<script setup lang="ts">
const carbonads = ref(null)
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('id', '_carbonads_js')
carbonads.value.appendChild(script)
}
})
</script>
<style lang="postcss">
.carbon > #carbonads {
@apply relative border border-gray-200 dark:border-gray-800 rounded-lg bg-white dark:bg-gray-800/50 hover:border-gray-300 dark:hover:border-gray-700 w-full transition-colors min-h-[220px];
&:hover {
.carbon-text {
@apply text-gray-700 dark:text-gray-200;
}
}
.carbon-img {
@apply flex justify-center p-2 w-full;
& > img {
@apply !max-w-full w-full rounded;
}
}
.carbon-text {
@apply flex px-2 text-sm text-gray-500 dark:text-gray-400 transition-colors text-center w-full;
}
.carbon-poweredby {
@apply block text-xs text-center text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 pt-1 pb-2 px-2 transition-colors;
}
}
</style>

View File

@@ -0,0 +1,27 @@
<template>
<div class="relative group/ad border border-gray-200 dark:border-gray-800 rounded-lg bg-white dark:bg-gray-800/50 hover:border-gray-300 dark:hover:border-gray-700 p-2 w-full transition-colors">
<NuxtLink to="/pro" class="focus:outline-none" tabindex="-1">
<span class="absolute inset-0" aria-hidden="true" />
</NuxtLink>
<UColorModeImage
light="/pro/illustrations/docs-light.svg"
dark="/pro/illustrations/docs-dark.svg"
alt="Nuxt UI Pro"
loading="lazy"
class="w-full"
/>
<div class="flex flex-col items-center mt-2 text-center">
<div class="inline-flex gap-1.5">
<Logo class="h-4 w-auto" />
<UBadge variant="subtle" size="xs" label="Pro" class="font-semibold" />
</div>
<p class="text-sm text-gray-500 dark:text-gray-400 group-hover/ad:text-gray-700 dark:group-hover/ad:text-gray-200 mt-1 transition-colors">
The Building Blocks for Modern Web Apps.
</p>
</div>
</div>
</template>

View File

@@ -36,8 +36,8 @@
</div>
</div>
<div class="flex border border-b-0 border-gray-200 dark:border-gray-700 relative not-prose" :class="[{ 'p-4': padding }, propsToSelect.length ? 'border-t-0' : 'rounded-t-md', backgroundClass, overflowClass]">
<component :is="name" v-model="vModel" v-bind="fullProps">
<div class="flex border border-b-0 border-gray-200 dark:border-gray-700 relative not-prose" :class="[{ 'p-4': padding }, propsToSelect.length ? 'border-t-0' : 'rounded-t-md', backgroundClass, extraClass]">
<component :is="name" v-model="vModel" v-bind="fullProps" :class="componentClass">
<ContentSlot v-if="$slots.default" :use="$slots.default" />
<template v-for="slot in Object.keys(slots || {})" :key="slot" #[slot]>
@@ -99,13 +99,21 @@ const props = defineProps({
type: String,
default: 'bg-white dark:bg-gray-900'
},
overflowClass: {
extraClass: {
type: String,
default: ''
},
previewOnly: {
type: Boolean,
default: false
},
componentClass: {
type: String,
default: ''
},
ignoreVModel: {
type: Boolean,
default: false
}
})
@@ -116,10 +124,16 @@ const componentProps = reactive({ ...props.props })
const { $prettier } = useNuxtApp()
const appConfig = useAppConfig()
const route = useRoute()
// eslint-disable-next-line vue/no-dupe-keys
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
const camelName = camelCase(slug)
const name = `U${upperFirst(camelName)}`
let name = props.slug || `U${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
// TODO: Remove once merged on `main` branch
if (['AvatarGroup', 'ButtonGroup', 'MeterGroup'].includes(name)) {
name = `U${name}`
}
if (['avatar-group', 'button-group', 'radio'].includes(name)) {
name = `U${upperFirst(camelCase(name))}`
}
const meta = await fetchComponentMeta(name)
@@ -143,6 +157,23 @@ const generateOptions = (key: string, schema: { kind: string, schema: [], type:
options = [...appConfig.ui.colors]
}
if (key.toLowerCase() === 'size' && schema?.schema?.length > 0) {
const baseSizeOrder = { 'xs': 1, 'sm': 2, 'md': 3, 'lg': 4, 'xl': 5 }
schema.schema.sort((a: string, b: string) => {
const aBase = a.match(/[a-zA-Z]+/)[0].toLowerCase()
const bBase = b.match(/[a-zA-Z]+/)[0].toLowerCase()
const aNum = parseInt(a.match(/\d+/)?.[0]) || 1
const bNum = parseInt(b.match(/\d+/)?.[0]) || 1
if (aBase === bBase) {
return aBase === 'xs' ? bNum - aNum : aNum - bNum
}
return baseSizeOrder[aBase] - baseSizeOrder[bBase]
})
}
if (schema?.schema?.length > 0 && schema?.kind === 'enum' && !hasIgnoredTypes && optionItem?.restriction !== 'only') {
options = schema.schema.filter(option => typeof option === 'string').map((option: string) => option.replaceAll('"', ''))
}
@@ -191,8 +222,11 @@ const code = computed(() => {
if (value === 'undefined' || value === null) {
continue
}
if (key === 'modelValue' && props.ignoreVModel) {
continue
}
code += ` ${(typeof value === 'boolean' && value !== true) || typeof value === 'object' || typeof value === 'number' ? ':' : ''}${key === 'modelValue' ? 'value' : kebabCase(key)}${typeof value === 'boolean' && !!value && key !== 'modelValue' ? '' : `="${typeof value === 'object' ? renderObject(value) : value}"`}`
code += ` ${(typeof value === 'boolean' && (value !== true || key === 'modelValue')) || typeof value === 'object' || typeof value === 'number' ? ':' : ''}${key === 'modelValue' ? 'model-value' : kebabCase(key)}${typeof value === 'boolean' && !!value && key !== 'modelValue' ? '' : `="${typeof value === 'object' ? renderObject(value) : value}"`}`
}
if (props.slots) {
@@ -237,7 +271,7 @@ function renderObject (obj: any) {
const shikiHighlighter = useShikiHighlighter({})
const codeHighlighter = async (code: string, lang: string, theme: any, highlights: number[]) => shikiHighlighter.getHighlightedAST(code, lang, theme, { highlights })
const { data: ast } = await useAsyncData(
`${name}-ast-${JSON.stringify({ props: componentProps, slots: props.slots })}`,
`${name}-ast-${JSON.stringify({ props: componentProps, slots: props.slots, code: props.code })}`,
async () => {
let formatted = ''
try {

View File

@@ -1,10 +1,14 @@
<template>
<div class="[&>div>pre]:!rounded-t-none [&>div>pre]:!mt-0">
<div
class="flex border border-gray-200 dark:border-gray-700 relative not-prose rounded-t-md"
:class="[{ 'p-4': padding, 'rounded-b-md': !hasCode, 'border-b-0': hasCode }, backgroundClass, overflowClass]"
class="flex border border-gray-200 dark:border-gray-700 relative rounded-t-md"
:class="[{ 'p-4': padding, 'rounded-b-md': !hasCode, 'border-b-0': hasCode, 'not-prose': !prose }, backgroundClass, extraClass]"
>
<component :is="camelName" v-if="component" v-bind="componentProps" />
<template v-if="component">
<iframe v-if="iframe" :src="`/examples/${component}`" v-bind="iframeProps" :class="backgroundClass" class="w-full" />
<component :is="camelName" v-else v-bind="componentProps" :class="componentClass" />
</template>
<ContentSlot v-if="$slots.default" :use="$slots.default" />
</div>
<template v-if="hasCode">
@@ -43,18 +47,36 @@ const props = defineProps({
type: Boolean,
default: true
},
prose: {
type: Boolean,
default: false
},
iframe: {
type: Boolean,
default: false
},
iframeProps: {
type: Object,
default: () => ({})
},
backgroundClass: {
type: String,
default: 'bg-white dark:bg-gray-900'
},
overflowClass: {
extraClass: {
type: String,
default: ''
}
})
let component = props.component
// TODO: Remove once merged on `main` branch
if (['command-palette-theme-algolia', 'command-palette-theme-raycast', 'vertical-navigation-theme-tailwind', 'pagination-theme-rounded'].includes(component)) {
component = component.replace('-theme', '-example-theme')
}
const instance = getCurrentInstance()
const camelName = camelCase(props.component)
const camelName = camelCase(component)
const data = await fetchContentExampleCode(camelName)
const hasCode = computed(() => !props.hiddenCode && (data?.code || instance.slots.code))

View File

@@ -24,7 +24,7 @@ const name = `U${upperFirst(camelName)}`
const preset = config[camelName]
const { data: ast } = await useAsyncData(`${name}-preset`, () => transformContent('content:_markdown.md', `
\`\`\`json [${name}.vue]
\`\`\`json
${JSON.stringify(preset, null, 2)}
\`\`\`\
`, {

View File

@@ -17,10 +17,16 @@ const props = defineProps({
})
const route = useRoute()
// eslint-disable-next-line vue/no-dupe-keys
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
const camelName = camelCase(slug)
const name = `U${upperFirst(camelName)}`
let name = props.slug || `U${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
// TODO: Remove once merged on `main` branch
if (['AvatarGroup', 'ButtonGroup', 'MeterGroup'].includes(name)) {
name = `U${name}`
}
if (['avatar-group', 'button-group', 'radio'].includes(name)) {
name = `U${upperFirst(camelCase(name))}`
}
const meta = await fetchComponentMeta(name)
</script>

View File

@@ -1,26 +1,29 @@
<template>
<Field v-bind="prop">
<code v-if="prop.default">{{ prop.default }}</code>
<code v-if="prop.default" class="leading-6">{{ prop.default }}</code>
<p v-if="prop.description">
{{ prop.description }}
</p>
<Collapsible v-if="prop.schema?.kind === 'array' && prop.schema?.schema?.filter(schema => schema.kind === 'object').length">
<FieldGroup v-for="schema in prop.schema.schema" :key="schema.name" class="!mt-0">
<FieldGroup v-for="schema in prop.schema.schema" :key="schema.name">
<ComponentPropsField v-for="subProp in Object.values(schema.schema)" :key="(subProp as any).name" :prop="subProp" />
</FieldGroup>
</Collapsible>
<Collapsible v-else-if="prop.schema?.kind === 'array' && prop.schema?.schema?.filter(schema => schema.kind === 'array').length">
<FieldGroup v-for="schema in prop.schema.schema" :key="schema.name" class="!mt-0">
<FieldGroup v-for="schema in prop.schema.schema" :key="schema.name">
<template v-for="subSchema in schema.schema" :key="subSchema.name">
<ComponentPropsField v-for="subProp in Object.values(subSchema.schema)" :key="(subProp as any).name" :prop="subProp" />
</template>
</FieldGroup>
</Collapsible>
<Collapsible v-else-if="prop.schema?.kind === 'object' && prop.schema.type !== 'Function' && Object.values(prop.schema.schema)?.length">
<FieldGroup class="!mt-0">
<FieldGroup>
<ComponentPropsField v-for="subProp in Object.values(prop.schema.schema)" :key="(subProp as any).name" :prop="subProp" />
</FieldGroup>
</Collapsible>
<div v-else-if="prop.schema?.kind === 'enum' && prop.schema.type !== 'boolean' && startsWithCapital(prop.schema.type) && !prop.schema.type.startsWith(prop.schema.schema[0])" class="space-x-1 leading-7 -my-1">
<code v-for="value in prop.schema.schema.filter(value => typeof value === 'string')" :key="value" class="whitespace-pre-wrap break-words">{{ value }}</code>
<div v-else-if="prop.schema?.kind === 'enum' && prop.schema.type !== 'boolean' && startsWithCapital(prop.schema.type) && !prop.schema.type.startsWith(prop.schema.schema[0])" class="flex items-center flex-wrap gap-1 -my-1">
<code v-for="value in prop.schema.schema.filter(value => typeof value === 'string')" :key="value" class="whitespace-pre-wrap break-words leading-6">{{ value }}</code>
</div>
</Field>
</template>

View File

@@ -1,19 +1,8 @@
<template>
<div>
<table>
<thead>
<tr>
<th>Slot</th>
</tr>
</thead>
<tbody>
<tr v-for="slot in (meta.meta.slots as any[])" :key="slot.name">
<td class="whitespace-nowrap">
<code>{{ slot.name }}</code>
</td>
</tr>
</tbody>
</table>
<FieldGroup>
<Field v-for="slot in meta?.meta.slots" :key="slot.name" v-bind="slot" />
</FieldGroup>
</div>
</template>
@@ -28,10 +17,8 @@ const props = defineProps({
})
const route = useRoute()
// eslint-disable-next-line vue/no-dupe-keys
const slug = props.slug || route.params.slug[route.params.slug.length - 1]
const camelName = camelCase(slug)
const name = `U${upperFirst(camelName)}`
const name = props.slug || `U${upperFirst(camelCase(route.params.slug[route.params.slug.length - 1]))}`
const meta = await fetchComponentMeta(name)
</script>

View File

@@ -1,5 +1,5 @@
<template>
<div class="relative overflow-hidden rounded border border-dashed border-gray-400 dark:border-gray-500 opacity-75">
<div class="relative overflow-hidden rounded border border-dashed border-gray-400 dark:border-gray-500 opacity-75 px-4 flex items-center justify-center">
<svg class="absolute inset-0 h-full w-full stroke-gray-900/10 dark:stroke-white/10" fill="none">
<defs>
<pattern

View File

@@ -1,17 +0,0 @@
<template>
<iframe :src="src" class="w-full min-h-[calc(100vh/1.5)] border border-gray-200 dark:border-gray-800 rounded-md" />
</template>
<script setup lang="ts">
const props = defineProps({
token: {
type: String,
required: true
}
})
const appConfig = useAppConfig()
const colorMode = useColorMode()
const src = computed(() => `https://volta.net/embed/${props.token}?theme=${colorMode.value}&gray=${appConfig.ui.gray}&primary=${appConfig.ui.primary}`)
</script>

View File

@@ -0,0 +1,17 @@
<script setup>
const links = [{
label: 'Home',
icon: 'i-heroicons-home',
to: '/'
}, {
label: 'Navigation',
icon: 'i-heroicons-square-3-stack-3d'
}, {
label: 'Breadcrumb',
icon: 'i-heroicons-link'
}]
</script>
<template>
<UBreadcrumb :links="links" />
</template>

View File

@@ -0,0 +1,20 @@
<script setup>
const links = [{
label: 'Home',
to: '/'
}, {
label: 'Navigation'
}, {
label: 'Breadcrumb'
}]
</script>
<template>
<UBreadcrumb :links="links">
<template #default="{ link, isActive, index }">
<UBadge :color="isActive ? 'primary' : 'gray'" class="rounded-full">
{{ index + 1 }}. {{ link.label }}
</UBadge>
</template>
</UBreadcrumb>
</template>

View File

@@ -0,0 +1,21 @@
<script setup>
const links = [{
label: 'Home',
icon: 'i-heroicons-home',
to: '/'
}, {
label: 'Navigation',
icon: 'i-heroicons-square-3-stack-3d'
}, {
label: 'Breadcrumb',
icon: 'i-heroicons-link'
}]
</script>
<template>
<UBreadcrumb :links="links" :ui="{ ol: 'gap-x-3', li: 'gap-x-3' }">
<template #divider>
<span class="w-8 h-1 rounded-full bg-gray-300 dark:bg-gray-700" />
</template>
</UBreadcrumb>
</template>

View File

@@ -0,0 +1,25 @@
<script setup>
const links = [{
label: 'Home',
to: '/'
}, {
label: 'Navigation'
}, {
label: 'Breadcrumb'
}]
</script>
<template>
<UBreadcrumb :links="links" :divider="null" :ui="{ ol: 'gap-x-3' }">
<template #icon="{ link, index, isActive }">
<UAvatar
:alt="(index + 1 ).toString()"
:ui="{
background: isActive ? 'bg-primary-500 dark:bg-primary-400' : undefined,
placeholder: isActive ? 'text-white dark:text-gray-900' : !!link.to ? 'group-hover:text-gray-700 dark:group-hover:text-gray-200' : ''
}"
size="xs"
/>
</template>
</UBreadcrumb>
</template>

View File

@@ -0,0 +1,19 @@
<template>
<UChip size="md" position="bottom-right" inset :ui="{ base: '-mx-2 rounded-none ring-0', background: '' }">
<UAvatar
src="https://avatars.githubusercontent.com/u/739984?v=4"
alt="Avatar"
size="lg"
/>
<template #content>
<UAvatar
src="https://avatars.githubusercontent.com/in/80442?v=4"
alt="Avatar"
size="xs"
:ui="{ rounded: 'rounded-md' }"
class="shadow-md"
/>
</template>
</UChip>
</template>

View File

@@ -0,0 +1,19 @@
<script setup>
const items = [{
name: 'messages',
icon: 'i-heroicons-chat-bubble-oval-left',
count: 3
}, {
name: 'notifications',
icon: 'i-heroicons-bell',
count: 0
}]
</script>
<template>
<div class="flex gap-3">
<UChip v-for="{ name, icon, count } in items" :key="name" :show="count > 0">
<UButton :icon="icon" color="gray" />
</UChip>
</div>
</template>

View File

@@ -0,0 +1,22 @@
<script setup>
const items = [
[{
label: 'Profile',
avatar: {
src: 'https://avatars.githubusercontent.com/u/739984?v=4'
}
}]
]
const open = ref(true)
defineShortcuts({
o: () => open.value = !open.value
})
</script>
<template>
<UDropdown v-model:open="open" :items="items" :popper="{ placement: 'bottom-start' }">
<UButton color="white" label="Options" trailing-icon="i-heroicons-chevron-down-20-solid" />
</UDropdown>
</template>

View File

@@ -20,7 +20,7 @@ async function onSubmit (event: FormSubmitEvent<any>) {
</script>
<template>
<UForm :validate="validate" :state="state" @submit="onSubmit">
<UForm :validate="validate" :state="state" class="space-y-4" @submit="onSubmit">
<UFormGroup label="Email" name="email">
<UInput v-model="state.email" />
</UFormGroup>

View File

@@ -10,6 +10,7 @@ const options = [
const state = reactive({
input: undefined,
inputMenu: undefined,
textarea: undefined,
select: undefined,
selectMenu: undefined,
@@ -23,6 +24,9 @@ const state = reactive({
const schema = z.object({
input: z.string().min(10),
inputMenu: z.any().refine(option => option?.value === 'option-2', {
message: 'Select Option 2'
}),
textarea: z.string().min(10),
select: z.string().refine(value => value === 'option-2', {
message: 'Select Option 2'
@@ -56,11 +60,15 @@ async function onSubmit (event: FormSubmitEvent<Schema>) {
</script>
<template>
<UForm ref="form" :schema="schema" :state="state" @submit="onSubmit">
<UForm ref="form" :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormGroup name="input" label="Input">
<UInput v-model="state.input" />
</UFormGroup>
<UFormGroup name="inputMenu" label="Input Menu">
<UInputMenu v-model="state.inputMenu" :options="options" />
</UFormGroup>
<UFormGroup name="textarea" label="Textarea">
<UTextarea v-model="state.textarea" />
</UFormGroup>

View File

@@ -21,7 +21,7 @@ async function onSubmit (event: FormSubmitEvent<any>) {
</script>
<template>
<UForm :schema="schema" :state="state" @submit="onSubmit">
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormGroup label="Email" name="email">
<UInput v-model="state.email" />
</UFormGroup>

View File

@@ -26,7 +26,7 @@ async function onError (event: FormErrorEvent) {
</script>
<template>
<UForm :validate="validate" :state="state" @submit="onSubmit" @error="onError">
<UForm :validate="validate" :state="state" class="space-y-4" @submit="onSubmit" @error="onError">
<UFormGroup label="Email" name="email">
<UInput v-model="state.email" />
</UFormGroup>

View File

@@ -21,7 +21,7 @@ async function onSubmit (event: FormSubmitEvent<Schema>) {
</script>
<template>
<UForm :schema="schema" :state="state" @submit="onSubmit">
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormGroup label="Email" name="email">
<UInput v-model="state.email" />
</UFormGroup>

View File

@@ -23,7 +23,7 @@ async function onSubmit (event: FormSubmitEvent<Schema>) {
</script>
<template>
<UForm :schema="schema" :state="state" @submit="onSubmit">
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormGroup label="Email" name="email">
<UInput v-model="state.email" />
</UFormGroup>

View File

@@ -21,7 +21,7 @@ async function onSubmit (event: FormSubmitEvent<Schema>) {
</script>
<template>
<UForm :schema="schema" :state="state" @submit="onSubmit">
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormGroup label="Email" name="email">
<UInput v-model="state.email" />
</UFormGroup>

View File

@@ -0,0 +1,19 @@
<template>
<UForm :schema="schema" :state="state" class="space-y-4">
<UFormGroup label="Username" name="username" eager-validation>
<UInput v-model="state.username" placeholder="Choose Username" />
</UFormGroup>
</UForm>
</template>
<script setup>
import { z } from 'zod'
const schema = z.object({
username: z.string().min(10, 'Must be at least 10 characters')
})
const state = reactive({
username: undefined
})
</script>

View File

@@ -0,0 +1,9 @@
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" />
</template>

View File

@@ -0,0 +1,13 @@
<script setup>
const people = []
const selected = ref()
</script>
<template>
<UInputMenu v-model="selected" :options="people">
<template #empty>
No people
</template>
</UInputMenu>
</template>

View File

@@ -0,0 +1,36 @@
<script setup>
const people = [{
id: 'benjamincanac',
label: 'benjamincanac',
href: 'https://github.com/benjamincanac',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/739984?v=4' }
}, {
id: 'Atinux',
label: 'Atinux',
href: 'https://github.com/Atinux',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/904724?v=4' }
}, {
id: 'smarroufin',
label: 'smarroufin',
href: 'https://github.com/smarroufin',
target: '_blank',
avatar: { src: 'https://avatars.githubusercontent.com/u/7547335?v=4' }
}, {
id: 'nobody',
label: 'Nobody',
icon: 'i-heroicons-user-circle'
}]
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people">
<template #leading>
<UIcon v-if="selected.icon" :name="selected.icon" class="w-4 h-4 mx-0.5" />
<UAvatar v-else-if="selected.avatar" v-bind="selected.avatar" size="3xs" class="mx-0.5" />
</template>
</UInputMenu>
</template>

View File

@@ -0,0 +1,26 @@
<script setup>
const people = [{
id: 1,
name: 'Wade Cooper'
}, {
id: 2,
name: 'Arlene Mccoy'
}, {
id: 3,
name: 'Devon Webb'
}, {
id: 4,
name: 'Tom Cook'
}]
const selected = ref(people[0].name)
</script>
<template>
<UInputMenu
v-model="selected"
:options="people"
value-attribute="name"
option-attribute="name"
/>
</template>

View File

@@ -0,0 +1,13 @@
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" searchable>
<template #option-empty="{ query }">
<q>{{ query }}</q> not found
</template>
</UInputMenu>
</template>

View File

@@ -0,0 +1,25 @@
<script setup>
const people = [
{ name: 'Wade Cooper', online: true },
{ name: 'Arlene Mccoy', online: false },
{ name: 'Devon Webb', online: false },
{ name: 'Tom Cook', online: true },
{ name: 'Tanya Fox', online: false },
{ name: 'Hellen Schmidt', online: true },
{ name: 'Caroline Schultz', online: true },
{ name: 'Mason Heaney', online: false },
{ name: 'Claudie Smitham', online: true },
{ name: 'Emil Schaefer', online: false }
]
const selected = ref(people[3])
</script>
<template>
<UInputMenu v-model="selected" :options="people" option-attribute="name">
<template #option="{ option: person }">
<span :class="[person.online ? 'bg-green-400' : 'bg-gray-200', 'inline-block h-2 w-2 flex-shrink-0 rounded-full']" aria-hidden="true" />
<span class="truncate">{{ person.name }}</span>
</template>
</UInputMenu>
</template>

View File

@@ -0,0 +1,9 @@
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" :popper="{ arrow: true }" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" :popper="{ offsetDistance: 0 }" />
</template>

View File

@@ -0,0 +1,9 @@
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref(people[0])
</script>
<template>
<UInputMenu v-model="selected" :options="people" :popper="{ placement: 'right-start' }" />
</template>

View File

@@ -0,0 +1,26 @@
<script setup>
const loading = ref(false)
const selected = ref()
async function search (q) {
loading.value = true
const users = await $fetch('https://jsonplaceholder.typicode.com/users', { params: { q } })
loading.value = false
return users
}
</script>
<template>
<UInputMenu
v-model="selected"
:search="search"
:loading="loading"
placeholder="Search for a user..."
option-attribute="name"
trailing
by="id"
/>
</template>

View File

@@ -0,0 +1,28 @@
<script setup>
const options = [
{ id: 1, name: 'Wade Cooper', colors: ['red', 'yellow'] },
{ id: 2, name: 'Arlene Mccoy', colors: ['blue', 'yellow'] },
{ id: 3, name: 'Devon Webb', colors: ['green', 'blue'] },
{ id: 4, name: 'Tom Cook', colors: ['blue', 'red'] },
{ id: 5, name: 'Tanya Fox', colors: ['green', 'red'] },
{ id: 5, name: 'Hellen Schmidt', colors: ['green', 'yellow'] }
]
const selected = ref(options[1])
</script>
<template>
<UInputMenu
v-model="selected"
:options="options"
placeholder="Select a person"
by="id"
option-attribute="name"
:search-attributes="['name', 'colors']"
>
<template #option="{ option: person }">
<span v-for="color in person.colors" :key="color.id" class="h-2 w-2 rounded-full" :class="`bg-${color}-500 dark:bg-${color}-400`" />
<span class="truncate">{{ person.name }}</span>
</template>
</UInputMenu>
</template>

View File

@@ -0,0 +1,15 @@
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref()
const query = ref('Wade')
</script>
<template>
<UInputMenu
v-model="selected"
v-model:query="query"
:options="people"
placeholder="Select a person"
/>
</template>

View File

@@ -3,5 +3,5 @@ const toast = useToast()
</script>
<template>
<UButton label="Show toast" @click="toast.add({ title: 'Notification <i>italic</i>', description: 'This is an <u>underlined</u> and <b>bold</b> notification.' })" />
<UButton label="Show toast" @click="toast.add({ title: 'This is an <u>underlined</u> and <b>bold</b> notification.' })" />
</template>

View File

@@ -1,18 +1,19 @@
<script setup>
const open = ref(false)
const open = ref(true)
defineShortcuts({
o: () => open.value = !open.value
})
</script>
<template>
<div class="flex gap-4 items-center">
<UToggle v-model="open" />
<UPopover :open="open">
<UButton color="white" label="Open" trailing-icon="i-heroicons-chevron-down-20-solid" />
<UPopover v-model:open="open">
<UButton color="white" :label="open.toString()" trailing-icon="i-heroicons-chevron-down-20-solid" />
<template #panel>
<div class="p-4">
<Placeholder class="h-20 w-48" />
</div>
</template>
</UPopover>
</div>
<template #panel>
<div class="p-4">
<Placeholder class="h-20 w-48" />
</div>
</template>
</UPopover>
</template>

View File

@@ -0,0 +1,11 @@
<template>
<UPopover overlay>
<UButton color="white" label="Open" trailing-icon="i-heroicons-chevron-down-20-solid" />
<template #panel>
<div class="p-4">
<Placeholder class="h-20 w-48" />
</div>
</template>
</UPopover>
</template>

View File

@@ -3,6 +3,5 @@ const value = ref(50)
</script>
<template>
<label for="range" class="sr-only" />
<URange id="range" v-model="value" name="range" />
<URange v-model="value" name="range" />
</template>

View File

@@ -23,6 +23,7 @@ const labels = computed({
// In a real app, you would make an API call to create the label
const response = {
id: options.value.length + 1,
name: label.name,
color: generateColorFromString(label.name)
}

View File

@@ -0,0 +1,53 @@
<script setup>
const options = ref([
{ id: 1, name: 'bug' },
{ id: 2, name: 'documentation' },
{ id: 3, name: 'duplicate' },
{ id: 4, name: 'enhancement' },
{ id: 5, name: 'good first issue' },
{ id: 6, name: 'help wanted' },
{ id: 7, name: 'invalid' },
{ id: 8, name: 'question' },
{ id: 9, name: 'wontfix' }
])
const selected = ref([])
const labels = computed({
get: () => selected.value,
set: async (labels) => {
const promises = labels.map(async (label) => {
if (label.id) {
return label
}
// In a real app, you would make an API call to create the label
const response = {
id: options.value.length + 1,
name: label.name
}
options.value.push(response)
return response
})
selected.value = await Promise.all(promises)
}
})
</script>
<template>
<USelectMenu
v-model="labels"
by="id"
name="labels"
:options="options"
option-attribute="name"
multiple
searchable
creatable
show-create-option-when="always"
placeholder="Select labels"
/>
</template>

View File

@@ -0,0 +1,13 @@
<script setup>
const people = []
const selected = ref()
</script>
<template>
<USelectMenu v-model="selected" :options="people">
<template #empty>
No people
</template>
</USelectMenu>
</template>

View File

@@ -28,11 +28,9 @@ const selected = ref(people[0])
<template>
<USelectMenu v-model="selected" :options="people">
<template #label>
<UIcon v-if="selected.icon" :name="selected.icon" class="w-4 h-4" />
<UAvatar v-else-if="selected.avatar" v-bind="selected.avatar" size="3xs" />
{{ selected.label }}
<template #leading>
<UIcon v-if="selected.icon" :name="selected.icon" class="w-4 h-4 mx-0.5" />
<UAvatar v-else-if="selected.avatar" v-bind="selected.avatar" size="3xs" class="mx-0.5" />
</template>
</USelectMenu>
</template>

View File

@@ -13,9 +13,7 @@ const people = [{
name: 'Tom Cook'
}]
const selected = ref(people[0].id)
const current = computed(() => people.find(person => person.id === selected.value))
const selected = ref(people[0].name)
</script>
<template>
@@ -23,11 +21,7 @@ const current = computed(() => people.find(person => person.id === selected.valu
v-model="selected"
:options="people"
placeholder="Select people"
value-attribute="id"
value-attribute="name"
option-attribute="name"
>
<template #label>
{{ current.name }}
</template>
</USelectMenu>
/>
</template>

View File

@@ -1,19 +1,27 @@
<script setup>
const search = async (q) => {
const loading = ref(false)
const selected = ref([])
async function search (q) {
loading.value = true
const users = await $fetch('https://jsonplaceholder.typicode.com/users', { params: { q } })
return users.map(user => ({ id: user.id, label: user.name, suffix: user.email })).filter(Boolean)
}
loading.value = false
const selected = ref([])
return users
}
</script>
<template>
<USelectMenu
v-model="selected"
:loading="loading"
:searchable="search"
placeholder="Search for a user..."
option-attribute="name"
multiple
trailing
by="id"
/>
</template>

View File

@@ -0,0 +1,30 @@
<script setup>
const options = [
{ id: 1, name: 'Wade Cooper', colors: ['red', 'yellow'] },
{ id: 2, name: 'Arlene Mccoy', colors: ['blue', 'yellow'] },
{ id: 3, name: 'Devon Webb', colors: ['green', 'blue'] },
{ id: 4, name: 'Tom Cook', colors: ['blue', 'red'] },
{ id: 5, name: 'Tanya Fox', colors: ['green', 'red'] },
{ id: 5, name: 'Hellen Schmidt', colors: ['green', 'yellow'] }
]
const selected = ref(options[1])
</script>
<template>
<USelectMenu
v-model="selected"
:options="options"
placeholder="Select a person"
searchable
searchable-placeholder="Search by name or color"
option-attribute="name"
by="id"
:search-attributes="['name', 'colors']"
>
<template #option="{ option: person }">
<span v-for="color in person.colors" :key="color.id" class="h-2 w-2 rounded-full" :class="`bg-${color}-500 dark:bg-${color}-400`" />
<span class="truncate">{{ person.name }}</span>
</template>
</USelectMenu>
</template>

View File

@@ -0,0 +1,16 @@
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref()
const query = ref('Wade')
</script>
<template>
<USelectMenu
v-model="selected"
v-model:query="query"
:options="people"
placeholder="Select a person"
searchable
/>
</template>

View File

@@ -77,6 +77,7 @@ const resetFilters = () => {
}
// Pagination
const sort = ref({ column: 'id', direction: 'asc' as const })
const page = ref(1)
const pageCount = ref(10)
const pageTotal = ref(200) // This value should be dynamic coming from the API
@@ -84,19 +85,21 @@ const pageFrom = computed(() => (page.value - 1) * pageCount.value + 1)
const pageTo = computed(() => Math.min(page.value * pageCount.value, pageTotal.value))
// Data
const { data: todos, pending } = await useLazyAsyncData('todos', () => $fetch<{
const { data: todos, pending } = await useLazyAsyncData<{
id: number
title: string
completed: string
}[]>(`https://jsonplaceholder.typicode.com/todos${searchStatus.value}`, {
}[]>('todos', () => ($fetch as any)(`https://jsonplaceholder.typicode.com/todos${searchStatus.value}`, {
query: {
q: search.value,
'_page': page.value,
'_limit': pageCount.value
'_limit': pageCount.value,
'_sort': sort.value.column,
'_order': sort.value.direction
}
}), {
default: () => [],
watch: [page, search, searchStatus, pageCount]
watch: [page, search, searchStatus, pageCount, sort]
})
</script>
@@ -175,11 +178,13 @@ const { data: todos, pending } = await useLazyAsyncData('todos', () => $fetch<{
<!-- Table -->
<UTable
v-model="selectedRows"
v-model:sort="sort"
:rows="todos"
:columns="columnsTable"
:loading="pending"
sort-asc-icon="i-heroicons-arrow-up"
sort-desc-icon="i-heroicons-arrow-down"
sort-mode="manual"
class="w-full"
:ui="{ td: { base: 'max-w-[0] truncate' } }"
@select="select"

View File

@@ -60,5 +60,5 @@ const people = [{
</script>
<template>
<UTable :columns="columns" :rows="people" :sort="{ column: 'title' }" />
<UTable :columns="columns" :rows="people" />
</template>

View File

@@ -32,7 +32,10 @@ const links = [{
</script>
<template>
<UVerticalNavigation :links="links">
<UVerticalNavigation
:links="links"
:ui="{ wrapper: 'truncate' }"
>
<template #icon="{ link }">
<UIcon v-if="link.type" :name="types[link.type].icon" :class="types[link.type].color" class="text-base" />
<UIcon v-else :name="types.default.icon" :class="types.default.color" class="text-base" />

View File

@@ -0,0 +1,41 @@
<script setup>
const links = [
[
{
label: 'Profile',
avatar: {
src: 'https://avatars.githubusercontent.com/u/739984?v=4'
},
badge: 100
}, {
label: 'Installation',
icon: 'i-heroicons-home',
to: '/getting-started/installation'
}, {
label: 'Vertical Navigation',
icon: 'i-heroicons-chart-bar',
to: '/navigation/vertical-navigation'
}, {
label: 'Command Palette',
icon: 'i-heroicons-command-line',
to: '/navigation/command-palette'
}
],
[
{
label: 'Examples',
icon: 'i-heroicons-light-bulb',
to: '/getting-started/examples#verticalnavigation'
},
{
label: 'Help',
icon: 'i-heroicons-question-mark-circle',
to: '/getting-started/examples'
}
]
]
</script>
<template>
<UVerticalNavigation :links="links" />
</template>

View File

@@ -14,9 +14,6 @@ const links = [{
}, {
label: 'Examples',
to: '/getting-started/examples'
}, {
label: 'Roadmap',
to: '/getting-started/roadmap'
}]
</script>

View File

@@ -0,0 +1,54 @@
<template>
<div ref="target" class="flex flex-col transition-opacity duration-500" :class="targetIsVisible ? 'opacity-100' : 'opacity-25'">
<time :datetime="date.day.toISOString()" class="flex-shrink-0 text-sm/6 font-semibold text-gray-500 dark:text-gray-400">{{ date.day.toLocaleString('en-us', { year: 'numeric', month: 'short', day: 'numeric' })
}}</time>
<NuxtLink v-if="date.release" :to="`https://github.com/nuxt/ui/releases/tag/${date.release.name}`" target="_blank" class="text-gray-900 dark:text-white font-bold text-3xl mt-2 group hover:text-primary-500 dark:hover:text-primary-400 transition-[color]">
{{ date.release.name }}
</NuxtLink>
<ul v-if="date.pulls?.length" class="mt-2 space-y-1 text-gray-600 dark:text-gray-300">
<li v-for="pull in date.pulls" :key="pull.id" class="text-sm/6 break-all">
<NuxtLink :to="`https://github.com/${pull.user.login}`" target="_blank" class="text-gray-900 dark:text-white transition-colors inline-flex items-center gap-1 rounded-full bg-gray-100/50 dark:bg-gray-800/50 dark:hover:bg-gray-800 p-0.5 pr-1 ring-1 ring-gray-300 dark:ring-gray-700 text-xs font-medium flex-shrink-0 align-middle">
<UAvatar :src="`https://github.com/${pull.user.login}.png`" size="3xs" />
{{ pull.user.login }}
</NuxtLink>
pushed <NuxtLink :to="pull.html_url" target="_blank" class="font-medium text-gray-700 dark:text-gray-200 hover:text-primary-500 dark:hover:text-primary-400 transition-[color]">
#{{ pull.number }} {{ pull.title }}
</NuxtLink>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { useIntersectionObserver } from '@vueuse/core'
defineProps<{
date: {
day: Date
release?: {
name: string
}
pulls?: {
id: number
number: number
title: string
html_url: string
user: {
login: string
}
}[]
}
}>()
const target = ref(null)
const targetIsVisible = ref(false)
useIntersectionObserver(target, ([{ isIntersecting }]) => {
targetIsVisible.value = isIntersecting
}, {
rootMargin: '-68px 0px -68px 0px'
})
</script>

View File

@@ -20,6 +20,10 @@ yarn add @nuxt/ui
npm install @nuxt/ui
```
```bash [bun]
bun add @nuxt/ui
```
::
2. Add it to your `modules` section in your `nuxt.config`:
@@ -32,8 +36,114 @@ export default defineNuxtConfig({
That's it! You can now use all the components and composables in your Nuxt app ✨
## Modules
Nuxt UI will automatically install the [@nuxtjs/tailwindcss](https://tailwindcss.nuxtjs.org/), [@nuxtjs/color-mode](https://color-mode.nuxtjs.org/) and [nuxt-icon](https://github.com/nuxt-modules/icon) modules for you.
::callout{icon="i-heroicons-exclamation-triangle"}
As this module installs [@nuxtjs/tailwindcss](https://tailwindcss.nuxtjs.org/) and [@nuxtjs/color-mode](https://color-mode.nuxtjs.org/) for you, you should remove them from your `modules` and `dependencies` if you've previously installed them manually.
You should remove them from your `modules` and `dependencies` if you've previously installed them.
::
### `@nuxtjs/tailwindcs`
This module is pre-configured and will automatically load the following plugins:
- [@tailwindcss/forms](https://github.com/tailwindlabs/tailwindcss-forms)
- [@tailwindcss/typography](https://github.com/tailwindlabs/tailwindcss-typography)
- [@tailwindcss/aspect-ratio](https://github.com/tailwindlabs/tailwindcss-aspect-ratio)
- [@tailwindcss/container-queries](https://github.com/tailwindlabs/tailwindcss-container-queries)
- [@headlessui/tailwindcss](https://github.com/tailwindlabs/headlessui/tree/main/packages/%40headlessui-vue)
Note that the `@tailwindcss/aspect-ratio` plugin disables the default aspect ratio utilities:
- `aspect-auto`
- `aspect-square`
- `aspect-video`
You can re-enable them by adding the following to your `tailwind.config.ts`:
```ts [tailwind.config.ts]
import type { Config } from 'tailwindcss'
export default <Partial<Config>>{
theme: {
extend: {
aspectRatio: {
auto: 'auto',
square: '1 / 1',
video: '16 / 9'
}
}
}
}
```
### `@nuxtjs/color-mode`
This module is installed to provide dark mode support out of the box thanks to the Tailwind CSS dark mode `class` strategy.
::callout{icon="i-heroicons-light-bulb"}
You can read more about this in the [Theming](/getting-started/theming#dark-mode) section.
::
### `nuxt-icon`
This module is installed when using the `dynamic` prop on the `Icon` component or globally through the `ui.icons.dynamic` option in your `app.config.ts`.
::callout{icon="i-heroicons-light-bulb"}
You can read more about this in the [Theming](/getting-started/theming#dynamic-icons) section and on the [Icon](/elements/icon) component page.
::
## 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.
::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.
::
You can use those types in your own components by importing them from `#ui/types`, for example when defining wrapper components:
```vue
<template>
<UBreadcrumb :links="links">
<template #icon="{ link }">
<UIcon :name="link.icon" />
</template>
</UBreadcrumb>
</template>
<script setup lang="ts">
import type { BreadcrumbLink } from '#ui/types'
export interface Props {
links: BreadcrumbLink[]
}
defineProps<Props>()
</script>
```
You don't have to use TypeScript yourself, but doing so will give you access to prop validation and autocomplete.
We've managed to provide dynamic typings on props such as `color`, `size`, `variant`, etc. based on your custom config. For example, you'll be suggested the `custom` color and the `subtle` variant when using the `Button` component with an `app.config.ts` as such:
```ts [app.config.ts]
export default defineAppConfig({
ui: {
button: {
color: {
custom: {
subtle: '...'
}
}
}
}
})
```
::callout{icon="i-heroicons-light-bulb"}
You can read more about components configuration in the [Theming](/getting-started/theming#appconfigts) section.
::
## IntelliSense
@@ -142,10 +252,11 @@ To use the latest updates pushed on the [`dev`](https://github.com/nuxt/ui/tree/
Update your `package.json` to the following:
```json [package.json]
```diff [package.json]
{
"devDependencies": {
"@nuxt/ui": "npm:@nuxt/ui-edge@latest"
- "@nuxt/ui": "^2.11.0"
+ "@nuxt/ui": "npm:@nuxt/ui-edge@latest"
}
}
```

View File

@@ -70,7 +70,7 @@ The `primary` color also has a `DEFAULT` shade that changes based on the theme.
### Smart Safelisting
Components having a `color` prop like [Avatar](/elements/avatar#chip), [Badge](/elements/badge#style), [Button](/elements/button#style), [Input](/forms/input#style) (inherited in [Select](/forms/select) and [SelectMenu](/forms/select-menu)), [Radio](/forms/radio), [Checkbox](/forms/checkbox), [Toggle](/forms/toggle), [Range](/forms/range) and [Notification](/overlays/notification#timeout) will use the `primary` color by default but will handle all the colors defined in your `tailwind.config.ts` or the default Tailwind CSS colors.
Components having a `color` prop like [Avatar](/elements/avatar#chip), [Badge](/elements/badge#style), [Button](/elements/button#style), [Input](/forms/input#style) (inherited in [Select](/forms/select) and [SelectMenu](/forms/select-menu)), [RadioGroup](/forms/radio-group), [Checkbox](/forms/checkbox), [Toggle](/forms/toggle), [Range](/forms/range) and [Notification](/overlays/notification#timeout) will use the `primary` color by default but will handle all the colors defined in your `tailwind.config.ts` or the default Tailwind CSS colors.
Variant classes of those components are defined with a syntax like `bg-{color}-500 dark:bg-{color}-400` so they can be used with any color. However, this means that Tailwind will not find those classes and therefore will not generate the corresponding CSS.
@@ -265,6 +265,8 @@ You can also use the [Icon](/elements/icon) component to add an icon anywhere in
</template>
```
### Collections
By default, the module uses [Heroicons](https://heroicons.com/) but you can change it from the module options in your `nuxt.config.ts`.
```ts [nuxt.config.ts]
@@ -279,12 +281,14 @@ export default defineNuxtConfig({
Search the icon you want to use on https://icones.js.org built by [@antfu](https://github.com/antfu).
::
Unlike the official [nuxt-icon](https://github.com/nuxt-modules/icon/) module, this module will not fetch any icon from the web and will only bundle the icons you use in your app thanks to [egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons).
However, you will need to install either `@iconify/json` (full icon collections, 50MB) or the individual icon packages you want to use in your app.
Thanks to [@egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons) plugin, only the icons you use in your app will be bundled in your CSS. However, you need to install the icon collections you specified in the `ui.icons` key:
::code-group
```bash [pnpm]
pnpm i @iconify-json/{collection_name}
```
```bash [yarn]
yarn add @iconify-json/{collection_name}
```
@@ -293,22 +297,60 @@ yarn add @iconify-json/{collection_name}
npm install @iconify-json/{collection_name}
```
```sh [pnpm]
pnpm i @iconify-json/{collection_name}
```
::
When using `@iconify/json`, you can specifiy `icons: 'all'` in your `nuxt.config.ts` to use any icon in your app.
If you choose to use the full `@iconify/json` icon collection (50MB), you can specifiy `icons: 'all'` or `icons: {}` in your `nuxt.config.ts` to use any icon in your app.
```ts [nuxt.config.ts]
export default defineNuxtConfig({
ui: {
icons: 'all'
icons: {}
}
})
```
### Custom config
If you have specific needs, like using a custom icon collection, you can use the `icons` option in your `nuxt.config.ts` as an object to override the config of the [@egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons#plugin-options) plugin.
```ts [nuxt.config.ts]
import { getIconCollections } from '@egoist/tailwindcss-icons'
export default defineNuxtConfig({
ui: {
icons: {
// might solve stretch bug on generate, see https://github.com/egoist/tailwindcss-icons/issues/23
extraProperties: {
'-webkit-mask-size': 'contain',
'-webkit-mask-position': 'center'
},
collections: {
foo: {
icons: {
'arrow-left': {
// svg body
body: '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />',
// svg width and height, optional
width: 24,
height: 24
}
}
},
...getIconCollections(['heroicons', 'simple-icons'])
}
}
}
})
```
### Dynamic icons
The `Icon` component also has a `dynamic` prop to use the [nuxt-icon](https://github.com/nuxt-modules/icon/) module instead of the [@egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons#plugin-options) plugin.
Read more about this in the [Icon](/elements/icon#dynamic) component page.
### Defaults
You can easily replace all the default icons of the components in your `app.config.ts`.
```ts [app.config.ts]
@@ -369,13 +411,29 @@ export default defineAppConfig({
},
pagination: {
default: {
firstButton: {
icon: 'i-octicon-chevron-left-24'
},
prevButton: {
icon: 'i-octicon-arrow-left-24'
},
nextButton: {
icon: 'i-octicon-arrow-right-24'
},
lastButton: {
icon: 'i-octicon-chevron-right-24'
}
}
},
accordion: {
default: {
openIcon: 'i-octicon-chevron-down-24'
}
},
breadcrumb: {
default: {
divider: 'i-octicon-chevron-right-24'
}
}
}
})

View File

@@ -98,9 +98,9 @@ _`enter` shortcut will only trigger when `queryInput` is focused._
### `whenever`
Prop: `whenever?: WatchSource<Boolean>[]`
Prop: `whenever?: WatchSource<boolean>[]`
`whenever` allows to add constraints on the shortcut triggering behavior. This array can contain `Ref<Boolean>`, `ComputedRef<Boolean>` or `() => Boolean`.
`whenever` allows to add constraints on the shortcut triggering behavior. This array can contain `Ref<boolean>`, `ComputedRef<boolean>` or `() => boolean`.
```ts
defineShortcuts({

View File

@@ -134,14 +134,14 @@ Here is some examples of what you can do with the [CommandPalette](/navigation/c
::component-example
---
padding: false
component: 'command-palette-theme-algolia'
component: 'command-palette-example-theme-algolia'
componentProps:
class: 'max-h-[480px] rounded-md'
hiddenCode: true
---
::
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeAlgolia.vue#L23" target="_blank"}
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/CommandPaletteExampleThemeAlgolia.vue#L23" target="_blank"}
Take a look at the component!
::
@@ -150,24 +150,24 @@ Take a look at the component!
::component-example
---
padding: false
component: 'command-palette-theme-raycast'
component: 'command-palette-example-theme-raycast'
componentProps:
class: 'max-h-[480px] rounded-md'
hiddenCode: true
---
::
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/themes/CommandPaletteThemeRaycast.vue#L30" target="_blank"}
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/CommandPaletteExampleThemeRaycast.vue#L30" target="_blank"}
Take a look at the component!
::
### VerticalNavigation
:component-example{component="vertical-navigation-theme-tailwind"}
:component-example{component="vertical-navigation-example-theme-tailwind"}
### Pagination
:component-example{component="pagination-theme-rounded"}
:component-example{component="pagination-example-theme-rounded"}
## RTL Support

View File

@@ -9,7 +9,7 @@ Nuxt UI thrives thanks to its fantastic community ❤️, which contributes by s
Before reporting a bug or reporting a feature, please make sure that you have read through our documentation and existing [issues](https://github.com/nuxt/ui/issues).
## Submitting a Pull Request
## Submitting a Pull Request (PR)
### 1. Before You Start
@@ -27,22 +27,33 @@ To begin local development, follow these steps:
git clone https://github.com/nuxt/ui.git
```
2. Install dependencies and prepare the project:
2. Enable [Corepack](https://github.com/nodejs/corepack):
```sh
corepack enable
```
3. Install dependencies:
```sh
pnpm install
```
4. Generate type stubs:
```sh
pnpm run dev:prepare
```
3. To configure your local development environment, use the following commands:
5. Configure your local development environment:
- To work on the **documentation** in the `docs` folder, run:
- To work on the **documentation** located in the `docs` folder, run:
```sh
pnpm run dev
```
- To test the components located in the `playground` folder within `app.vue`, run:
- To test the components using **playground**, run:
```sh
pnpm run play
@@ -84,46 +95,26 @@ pnpm run typecheck
### 3. Commit Conventions
Use Conventional Commits for commit messages with the following format:
We use [Conventional Commits](https://www.conventionalcommits.org/) for commit messages, which allows a changelog to be auto-generated based on the commits. Please read the [guide](https://www.conventionalcommits.org/en/v1.0.0/#summary) through if you aren't familiar with it already.
```
<type>(optional scope): <description>
#### Note
[optional body]
- `fix` and `feat` are for actual code changes (that might affect logic). For typo or document changes, use `docs` or `chore` instead:
[optional footer(s)]
```
~~`fix: typo`~~ -> `docs: fix typo`
#### Types
- `feat` : for new features.
- `fix` : for bug fixes.
- `refactor` : for code changes that are neither bug fixes nor new features.
- `perf` : for code refactoring that improves performance.
- `test` : for code related to automatic testing.
- `style` : for refactoring related to code style (not for CSS).
- `docs` : for changes related to documentation.
- `chore` : for anything else.
#### Scope
Where the change occurred (e.g., `Table`, `Alert`, `Accordion`, etc.).
#### Description
A summary of the changes made.
#### Examples
- If you are working on a specific component, ensure that you specify the main scope of your commit in brackets. e.g.
```
feat(Alert): new component
chore(Table): improve accessibility
docs: migrate to @nuxt/ui-pro
```
### 4. Making the Pull Request
### 4. Making a Pull Request
- Follow the guide for creating a pull request and ensure your PR's title adheres to the Commit Convention. Mention any related issues in the PR description.
- Follow along the [instructions](https://github.com/nuxt/ui/blob/main/.github/PULL_REQUEST_TEMPLATE.md?plain=1) provided when creating a PR
- Ensure your PR's title adheres to the [Conventional Commits](https://www.conventionalcommits.org/) since it will be used once the code is merged.
- Multiple commits are fine; no need to rebase or force push. We'll use `Squash and Merge` when merging.

View File

@@ -1,7 +0,0 @@
---
title: Roadmap
description: Discover our Volta board for @nuxt/ui development status.
toc: false
---
:volta-embed{token="eyJ2aWV3IjoiYm9hcmQiLCJib2FyZFN0YXR1c2VzIjpbInRyaWFnZSIsImJhY2tsb2ciLCJ0b2RvIiwiaW5fcHJvZ3Jlc3MiLCJpbl9yZXZpZXciLCJkb25lIiwicmVsZWFzZWQiLCJjYW5jZWxsZWQiXSwiYm9hcmRMaW5rZWRQcnMiOnRydWUsImxpc3RHcm91cCI6InN0YXR1cyIsImxpc3RPcmRlciI6ImNyZWF0ZWRfYXQiLCJ0aW1lbGluZVpvb20iOiJtb250aCIsInRpbWVsaW5lT3JkZXIiOiJzdGF0ZSIsInRpbWVsaW5lRGlzcGxheSI6ImFsbF9taWxlc3RvbmVzIiwiZmlsdGVycyI6e30sIm93bmVyIjoibnV4dCIsIm5hbWUiOiJ1aSJ9"}

View File

@@ -1,8 +1,6 @@
---
title: 'Progress'
description: Show a horizontal bar to indicate task progression.
navigation:
badge: New
links:
- label: GitHub
icon: i-simple-icons-github

View File

@@ -1,8 +1,6 @@
---
title: 'Meter'
description: Display a gauge meter that fills or depletes.
navigation:
badge: New
links:
- label: GitHub
icon: i-simple-icons-github
@@ -119,7 +117,7 @@ To group multiple meters into a group, adding all values, use the `MeterGroup` c
- To show a label for each meter, use the `label` prop on each meter.
- To change the icon for each meter, use the `icon` prop.
::component-card{slug="MeterGroup"}
::component-card{slug="UMeterGroup"}
---
baseProps:
icon: i-heroicons-minus
@@ -167,14 +165,14 @@ The `label` slot can be used to change how the label below the meter bar is show
## Props
:component-props
:u-divider{label="MeterGroup" type="dashed" class="my-12"}
:component-props{slug="MeterGroup"}
::tabs
:component-props{label="Meter"}
:component-props{label="MeterGroup" slug="UMeterGroup"}
::
## Config
:component-preset
:component-preset{slug="MeterGroup"}
::tabs
:component-preset{label="Meter"}
:component-preset{label="MeterGroup" slug="MeterGroup"}
::

View File

@@ -0,0 +1,132 @@
---
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
---
## Usage
Wrap any component with the `Chip` component to display a chip indicator.
::component-card
---
code: >-
<UButton icon="i-heroicons-inbox" color="gray" />
---
#default
:u-button{icon="i-heroicons-inbox" color="gray"}
::
### Size
Use the `size` prop to change the size of the chip.
::component-card
---
props:
size: '2xl'
code: >-
<UButton icon="i-heroicons-inbox" color="gray" />
---
#default
:u-button{icon="i-heroicons-inbox" color="gray"}
::
### Color
Use the `color` prop to change the color of the chip.
::component-card
---
props:
color: 'red'
code: >-
<UButton icon="i-heroicons-inbox" color="gray" />
---
#default
:u-button{icon="i-heroicons-inbox" color="gray"}
::
### Position
Use the `position` prop to change the position of the chip.
::component-card
---
props:
position: 'bottom-right'
code: >-
<UButton icon="i-heroicons-inbox" color="gray" />
---
#default
:u-button{icon="i-heroicons-inbox" color="gray"}
::
### Text
Use the `text` prop to display text in the chip.
::component-card
---
props:
text: '3'
size: '2xl'
excludedProps:
- size
code: >-
<UButton icon="i-heroicons-inbox" color="gray" />
---
#default
:u-button{icon="i-heroicons-inbox" color="gray"}
::
### Show
Use the `show` prop to conditionally display the chip.
:component-example{component="chip-example-show"}
### Inset
Use the `inset` prop to display the chip inside the component. This is useful when dealing with rounded components.
::component-card
---
props:
inset: true
code: >-
<UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" alt="Avatar" />
---
#default
:u-avatar{src="https://avatars.githubusercontent.com/u/739984?v=4" alt="Avatar"}
::
## Slots
### `content`
Use the `#content` slot to fully customize the chip.
:component-example{component="chip-example-content-slot"}
## Props
:component-props
## Config
:component-preset

View File

@@ -90,7 +90,7 @@ To stack avatars as a group, use the `AvatarGroup` component.
- To size all the avatars equally, pass the `size` prop
- To adjust the spacing or the ring between avatars, customize with `ui.avatarGroup.margin` or `ui.avatarGroup.ring`
::component-card{slug="AvatarGroup"}
::component-card{slug="UAvatarGroup"}
---
props:
size: 'sm'
@@ -109,14 +109,14 @@ code: |
## Props
:component-props
:u-divider{label="AvatarGroup" type="dashed" class="my-12"}
:component-props{slug="avatar-group"}
::tabs
:component-props{label="Avatar"}
:component-props{label="AvatarGroup" slug="UAvatarGroup"}
::
## Config
:component-preset
:component-preset{slug="avatar-group"}
::tabs
:component-preset{label="Avatar"}
:component-preset{label="AvatarGroup" slug="AvatarGroup"}
::

View File

@@ -295,7 +295,7 @@ To stack buttons as a group, use the `ButtonGroup` component.
- To change the orientation of the buttons, set the `orientation` prop to `vertical`
- To adjust the rounded or the shadow around buttons, customize with `ui.buttonGroup.rounded` or `ui.buttonGroup.shadow`
::component-card{slug="ButtonGroup"}
::component-card{slug="UButtonGroup"}
---
props:
size: 'sm'
@@ -312,7 +312,7 @@ code: |
This can also work with an [Input](/forms/input) component for example:
::component-card{slug="ButtonGroup"}
::component-card{slug="UButtonGroup"}
---
props:
size: 'sm'
@@ -371,14 +371,14 @@ excludedProps:
## Props
:component-props
:u-divider{label="ButtonGroup" type="dashed" class="my-12"}
:component-props{slug="ButtonGroup"}
::tabs
:component-props{label="Button"}
:component-props{label="ButtonGroup" slug="UButtonGroup"}
::
## Config
:component-preset
:component-preset{slug="ButtonGroup"}
::tabs
:component-preset{label="Button"}
:component-preset{label="ButtonGroup" slug="ButtonGroup"}
::

View File

@@ -14,12 +14,14 @@ links:
Pass an array of arrays to the `items` prop of the Dropdown component. Each array represents a group of items. Each item can have the following properties:
- `label` - The label of the item.
- `labelClass` - The class of the item label. :u-badge{label="New" class="!rounded-full" variant="subtle"}
- `icon` - The icon of the item.
- `iconClass` - The class of the icon of the item.
- `iconClass` - The class of the item icon.
- `avatar` - The avatar of the item. You can pass all the props of the [Avatar](/elements/avatar) component.
- `shortcuts` - The shortcuts of the item.
- `slot` - The slot of the item.
- `disabled` - Whether the item is disabled.
- `class` - The class of the item.
- `click` - The click handler of the item.
You can also pass any property from the [NuxtLink](https://nuxt.com/docs/api/components/nuxt-link#props) component such as `to`, `exact`, etc.
@@ -32,6 +34,12 @@ Use the `mode` prop to switch between `click` and `hover` modes.
:component-example{component="dropdown-example-mode"}
### Manual :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
Use a `v-model:open` to manually control the state. In this example, press :shortcut{value="O"} to toggle the dropdown.
:component-example{component="dropdown-example-open"}
## Popper
Use the `popper` prop to customize the popper instance.

View File

@@ -1,5 +1,5 @@
---
description: Display an icon from Iconify library.
description: Display any icon (100,000+) from Iconify.
links:
- label: GitHub
icon: i-simple-icons-github
@@ -8,6 +8,8 @@ links:
## Usage
Use the `name` prop by following this pattern: `i-{collection_name}-{icon_name}`. You can search any icon from [Iconify](https://iconify.design/) using https://icones.js.org.
::component-card
---
props:
@@ -16,9 +18,35 @@ props:
::
::callout{icon="i-heroicons-exclamation-triangle"}
When playing with the `name` prop above, you won't be able to use any icon you want as icons are bundled on build as explained in the [theming section](/getting-started/theming#icons).
You won't be able to use any icon in the `name` prop here as icons are bundled using [egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons), read more about this in [Theming](/getting-started/theming#icons).
::
### Dynamic
You can use the `dynamic` prop to enable dynamic icon loading. This will use [`nuxt-icon`](https://github.com/nuxt-modules/icon) instead and allow you to use any icon from [Iconify](https://iconify.design/) as well as the `{collection_name}:{icon_name}` pattern.
This can be quite useful when using [dynamic class names](https://tailwindcss.com/docs/content-configuration#dynamic-class-names) or for icons that are not bundled by default (fetched from a database for example).
::component-card
---
props:
name: 'i-ph-rocket-launch'
dynamic: true
---
::
You can also change the default behavior of the `dynamic` prop by setting the `ui.icons.dynamic` option in your `app.config.ts`.
```ts [app.config.ts]
export default defineAppConfig({
ui: {
icons: {
dynamic: true
}
}
})
```
## Props
:component-props

View File

@@ -71,7 +71,7 @@ props:
Use the `type` prop to change the input type, the default `type` is set to `text`, you can check all the available types at [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types).
We have improved the implementation of certain types such as [Checkbox](/forms/checkbox), [Radio](/forms/radio), etc.
We have improved the implementation of certain types such as [Checkbox](/forms/checkbox), [Radio](/forms/radio-group), etc.
::component-card
---
@@ -148,6 +148,21 @@ excludedProps:
---
::
### Padded
Use the `padded` prop to remove the padding of the Input.
::component-card
---
props:
padded: false
baseProps:
placeholder: 'Search...'
variant: 'none'
class: 'w-full'
---
::
## Slots
### `leading`
@@ -157,13 +172,13 @@ 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" />
leading: <UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs" class="mx-0.5" />
baseProps:
placeholder: 'Search...'
---
#leading
:u-avatar{src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs"}
:u-avatar{src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs" class="mx-0.5"}
::
### `trailing`

View File

@@ -17,7 +17,13 @@ The Form component requires the `validate` and `state` props for form validation
- `message` - the error message to display.
- `path` - the path to the form element matching the `name`.
:component-example{component="form-example-basic" :componentProps='{"class": "space-y-4 w-60"}'}
::component-example
---
component: 'form-example-basic'
componentProps:
class: 'w-60'
---
::
## Schema
@@ -25,19 +31,43 @@ You can provide a schema from [Yup](#yup), [Zod](#zod) or [Joi](#joi), [Valibot]
### Yup
:component-example{component="form-example-yup" :componentProps='{"class": "space-y-4 w-60"}'}
::component-example
---
component: 'form-example-yup'
componentProps:
class: 'w-60'
---
::
### Zod
:component-example{component="form-example-zod" :componentProps='{"class": "space-y-4 w-60"}'}
::component-example
---
component: 'form-example-zod'
componentProps:
class: 'w-60'
---
::
### Joi
:component-example{component="form-example-joi" :componentProps='{"class": "space-y-4 w-60"}'}
::component-example
---
component: 'form-example-joi'
componentProps:
class: 'w-60'
---
::
### Valibot
:component-example{component="form-example-valibot" :componentProps='{"class": "space-y-4 w-60"}'}
::component-example
---
component: 'form-example-valibot'
componentProps:
class: 'w-60'
---
::
## Other libraries
@@ -131,13 +161,24 @@ async function onSubmit (event: FormSubmitEvent<any>) {
The Form component automatically triggers validation upon `submit`, `input`, `blur` or `change` events. This ensures that any errors are displayed as soon as the user interacts with the form elements. You can control when validation happens this using the `validate-on` prop.
:component-example{component="form-example-elements" :componentProps='{"class": "space-y-4 w-60"}' hiddenCode }
::callout{icon="i-heroicons-light-bulb"}
Note that the `input` event is not triggered until after the initial `blur` event. This is to prevent the form from being validated as the user is typing. You can override this behavior by setting the [`eager-validation`](/forms/form-group#eager-validation) prop on [`FormGroup`](/forms/form-group) to `true`.
::
::component-example
---
component: 'form-example-elements'
componentProps:
class: 'w-60'
hiddenCode: true
---
::
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/FormExampleElements.vue" target="_blank"}
Take a look at the component!
::
## Error event :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
## Error event
You can listen to the `@error` event to handle errors. This event is triggered when the form is validated and contains an array of `FormError` objects with the following fields:
@@ -147,7 +188,13 @@ You can listen to the `@error` event to handle errors. This event is triggered w
Here is an example of how to focus the first form element with an error:
:component-example{component="form-example-on-error" :componentProps='{"class": "space-y-4 w-60"}'}
::component-example
---
component: 'form-example-on-error'
componentProps:
class: 'w-60'
---
::
## Props
@@ -156,6 +203,9 @@ Here is an example of how to focus the first form element with an error:
## API
::field-group
::field{name="submit ()" type="Promise<void>"}
Triggers form submission.
::
::field{name="validate (path?: string, opts: { silent?: boolean })" type="Promise<T>"}
Triggers form validation. Will raise any errors unless `opts.silent` is set to true.
::
@@ -170,5 +220,5 @@ Here is an example of how to focus the first form element with an error:
::
::field{name="errors" type="Ref<FormError[]>"}
A reference to the array containing validation errors. Use this to access or manipulate the error information.
::
::
::

View File

@@ -0,0 +1,210 @@
---
title: InputMenu
description: Display an autocomplete input with real-time suggestions.
links:
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/InputMenu.vue
- label: 'Combobox'
icon: i-simple-icons-headlessui
to: 'https://headlessui.com/vue/combobox'
navigation:
badge: New
---
## Usage
The `InputMenu` component renders by default an [Input](/forms/input) component and is based on the `ui.input` preset. You can use most of the `Input` props to configure the display such as [color](/forms/input#style), [variant](/forms/input#style), [size](/forms/input#size), [placeholder](/forms/input#placeholder), [icon](/forms/input#icon), [disabled](/forms/input#disabled), etc.
You can use the `ui` prop like the `Input` component to override the default config. The `uiMenu` prop can be used to override the default menu config.
Pass an array of strings or objects to the `options` prop to display in the menu.
::component-example
---
component: 'input-menu-example-basic'
componentProps:
class: 'w-full lg:w-48'
---
::
::callout{icon="i-heroicons-exclamation-triangle"}
This component does not support multiple values. Use the [SelectMenu](/forms/select-menu#multiple) component instead.
::
### Objects
You can pass an array of objects to `options` and either compare on the whole object or use the `by` prop to compare on a specific key. You can configure which field will be used to display the label through the `option-attribute` prop that defaults to `label`.
::component-example
---
component: 'input-menu-example-objects'
componentProps:
class: 'w-full lg:w-48'
---
::
Use the `search-attributes` prop with an array of property names to search on each option object. Nested attributes can be accessed using `dot.notation`. When the property value is an array or object, these are cast to string so these can be searched within.
::component-example
---
component: 'input-menu-example-search-attributes'
componentProps:
class: 'w-full lg:w-48'
---
::
If you only want to select a single object property rather than the whole object as value, you can set the `value-attribute` property. This prop defaults to `null`.
::component-example
---
component: 'input-menu-example-objects-value-attribute'
componentProps:
class: 'w-full lg:w-48'
---
::
### Icon
The `InputMenu` has a button on the right to toggle the menu. Use the `trailing-icon` prop to set a different icon or change it globally in `ui.inputMenu.default.trailingIcon`. Defaults to `i-heroicons-chevron-down-20-solid`.
::component-card
---
baseProps:
class: 'w-full lg:w-48'
placeholder: 'Select a person'
options: ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
props:
trailingIcon: 'i-heroicons-chevron-up-down-20-solid'
excludedProps:
- trailingIcon
---
::
Use the `selected-icon` prop to set a different icon or change it globally in `ui.inputMenu.default.selectedIcon`. Defaults to `i-heroicons-check-20-solid`.
::component-card
---
baseProps:
class: 'w-full lg:w-48'
placeholder: 'Select a person'
options: ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
props:
selectedIcon: 'i-heroicons-hand-thumb-up-solid'
excludedProps:
- selectedIcon
---
::
::callout{icon="i-heroicons-light-bulb"}
Learn how to customize icons from the [Input](/forms/input#icon) component.
::
## Searchable
### Attributes
Use the `search-attributes` prop with an array of property names to search on each option object. Nested attributes can be accessed using `dot.notation`. When the property value is an array or object, these are cast to string so these can be searched within.
::component-example
---
component: 'input-menu-example-search-attributes'
componentProps:
class: 'w-full lg:w-48'
---
::
### Control the query
Use a `v-model:query` to control the search query.
::component-example
---
component: 'input-menu-example-search-query'
componentProps:
class: 'w-full lg:w-48'
---
::
### Async search
Pass a function to the `search` prop to customize the search behavior and filter options according to your needs. The function will receive the query as its first argument and should return an array.
Use the `debounce` prop to adjust the delay of the function.
::component-example
---
component: 'input-menu-example-search-async'
componentProps:
class: 'w-full lg:w-48'
---
::
## Popper
Use the `popper` prop to customize the popper instance.
### Arrow
:component-example{component="input-menu-example-popper-arrow"}
### Placement
:component-example{component="input-menu-example-popper-placement"}
### Offset
:component-example{component="input-menu-example-popper-offset"}
## Slots
### `option`
Use the `#option` slot to customize the option content. You will have access to the `option`, `active` and `selected` properties in the slot scope.
::component-example
---
component: 'input-menu-example-option-slot'
componentProps:
class: 'w-full lg:w-48'
---
::
### `option-empty`
Use the `#option-empty` slot to customize the content displayed when the `searchable` prop is `true` and there is no options. You will have access to the `query` property in the slot scope.
::component-example
---
component: 'input-menu-example-option-empty-slot'
componentProps:
class: 'w-full lg:w-48'
---
::
### `empty`
Use the `#empty` slot to customize the content displayed when there is no options. Defaults to `No options.`.
::component-example
---
component: 'input-menu-example-empty-slot'
componentProps:
class: 'w-full lg:w-48'
---
::
## Props
:component-props
## Config
::callout{icon="i-heroicons-light-bulb"}
Use the `ui` prop to override the input config and the `uiMenu` prop to override the menu config.
::
::tabs{:selectedIndex="1"}
:component-preset{label="Input (ui)" slug="Input"}
:component-preset{label="InputMenu (uiMenu)"}
::

View File

@@ -132,6 +132,21 @@ props:
---
::
### Padded
Use the `padded` prop to remove the padding of the Textarea.
::component-card
---
props:
padded: false
baseProps:
placeholder: 'Search...'
variant: 'none'
class: 'w-full'
---
::
## Props
:component-props

View File

@@ -175,6 +175,25 @@ excludedProps:
---
::
### Padded
Use the `padded` prop to remove the padding of the Select.
::component-card
---
props:
padded: false
baseProps:
placeholder: 'Search...'
options:
- 'United States'
- 'Canada'
- 'Mexico'
variant: 'none'
class: 'w-full'
---
::
## Slots
### `leading`
@@ -184,7 +203,7 @@ 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" />
leading: <UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs" class="mx-0.5" />
baseProps:
options:
- 'United States'
@@ -194,7 +213,7 @@ baseProps:
---
#leading
:u-avatar{src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs"}
:u-avatar{src="https://avatars.githubusercontent.com/u/739984?v=4" size="3xs" class="mx-0.5"}
::
### `trailing`

View File

@@ -14,25 +14,51 @@ links:
The `SelectMenu` component renders by default a [Select](/forms/select) component and is based on the `ui.select` preset. You can use most of the `Select` props to configure the display if you don't want to override the default slot such as [color](/forms/select#style), [variant](/forms/select#style), [size](/forms/select#size), [placeholder](/forms/select#placeholder), [icon](/forms/select#icon), [disabled](/forms/select#disabled), etc.
You can use the `ui` prop like the `Select` component to override the default config. The `uiMenu` prop can be used to override the default menu config.
Like the `Select` component, you can use the `options` prop to pass an array of strings or objects.
:component-example{component="select-menu-example-basic" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-basic'
componentProps:
class: 'w-full lg:w-48'
---
::
### Multiple
You can use the `multiple` prop to select multiple values.
:component-example{component="select-menu-example-multiple" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-multiple'
componentProps:
class: 'w-full lg:w-48'
---
::
### Objects
You can pass an array of objects to `options` and either compare on the whole object or use the `by` prop to compare on a specific key. You can configure which field will be used to display the label through the `option-attribute` prop that defaults to `label`.
:component-example{component="select-menu-example-objects" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-objects'
componentProps:
class: 'w-full lg:w-48'
---
::
If you only want to select a single object property rather than the whole object as value, you can set the `value-attribute` property. This prop defaults to `null`.
:component-example{component="select-menu-example-objects-value-attribute" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-objects-value-attribute'
componentProps:
class: 'w-full lg:w-48'
---
::
### Icon
@@ -41,7 +67,7 @@ Use the `selected-icon` prop to set a different icon or change it globally in `u
::component-card
---
baseProps:
class: 'w-full lg:w-40'
class: 'w-full lg:w-48'
placeholder: 'Select a person'
options: ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
props:
@@ -55,7 +81,7 @@ excludedProps:
Learn how to customize icons from the [Select](/forms/select#icon) component.
::
### Search
## Searchable
Use the `searchable` prop to enable search.
@@ -66,7 +92,7 @@ This will use Headless UI [Combobox](https://headlessui.com/vue/combobox) compon
::component-card
---
baseProps:
class: 'w-full lg:w-40'
class: 'w-full lg:w-48'
placeholder: 'Select a person'
options: ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
props:
@@ -75,21 +101,90 @@ props:
---
::
### Attributes
Use the `search-attributes` prop with an array of property names to search on each option object. Nested attributes can be accessed using `dot.notation`. When the property value is an array or object, these are cast to string so these can be searched within.
::component-example
---
component: 'select-menu-example-search-attributes'
componentProps:
class: 'w-full lg:w-48'
---
::
### Clear on close
By default, the search query will be kept after the menu is closed. To clear it on close, set the `clear-search-on-close` prop.
You can also configure this globally through the `ui.selectMenu.default.clearSearchOnClose` config. Defaults to `false`.
::component-card
---
baseProps:
class: 'w-full lg:w-48'
placeholder: 'Select a person'
searchable: true
searchablePlaceholder: 'Search a person...'
options: ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
props:
clearSearchOnClose: true
---
::
### Control the query :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
Use a `v-model:query` to control the search query.
::component-example
---
component: 'select-menu-example-search-query'
componentProps:
class: 'w-full lg:w-48'
---
::
### Async search
Pass a function to the `searchable` prop to customize the search behavior and filter options according to your needs. The function will receive the query as its first argument and should return an array.
Use the `debounce` prop to adjust the delay of the function.
:component-example{component="select-menu-example-async-search" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-search-async'
componentProps:
class: 'w-full lg:w-48'
---
::
### Create option
## Creatable
Use the `creatable` prop to enable the creation of new options when the search doesn't return any results (only works with `searchable`).
Try to search for something that doesn't exist in the example below.
:component-example{component="select-menu-example-creatable" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-creatable'
componentProps:
class: 'w-full lg:w-48'
---
::
However, if you want to create options despite search query (apart from exact match), you can set the `show-create-option-when` prop to `'always'`.
You can also configure this globally through the `ui.selectMenu.default.showCreateOptionWhen` config. Defaults to `empty`.
Try to search for something that exists in the example below, but not an exact match.
::component-example
---
component: 'select-menu-example-creatable-always'
componentProps:
class: 'w-full lg:w-48'
---
::
## Popper
@@ -113,25 +208,49 @@ Use the `popper` prop to customize the popper instance.
You can override the `#label` slot and handle the display yourself.
:component-example{component="select-menu-example-multiple-slot" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-multiple-slot'
componentProps:
class: 'w-full lg:w-48'
---
::
### `default`
You can also override the `#default` slot entirely.
:component-example{component="select-menu-example-button" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-button'
componentProps:
class: 'w-full lg:w-48'
---
::
### `option`
Use the `#option` slot to customize the option content. You will have access to the `option`, `active` and `selected` properties in the slot scope.
:component-example{component="select-menu-example-option-slot" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-option-slot'
componentProps:
class: 'w-full lg:w-48'
---
::
### `option-empty`
Use the `#option-empty` slot to customize the content displayed when the `searchable` prop is `true` and there is no options. You will have access to the `query` property in the slot scope.
:component-example{component="select-menu-example-option-empty-slot" :componentProps='{"class": "w-full lg:w-40"}'}
::component-example
---
component: 'select-menu-example-option-empty-slot'
componentProps:
class: 'w-full lg:w-48'
---
::
### `option-create`
@@ -141,10 +260,29 @@ Use the `#option-create` slot to customize the content displayed when the `creat
An example is available in the [Create option](#create-option) section.
::
### `empty` :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
Use the `#empty` slot to customize the content displayed when there is no options. Defaults to `No options.`.
::component-example
---
component: 'select-menu-example-empty-slot'
componentProps:
class: 'w-full lg:w-48'
---
::
## Props
:component-props
## Config
:component-preset
::callout{icon="i-heroicons-light-bulb"}
Use the `ui` prop to override the select config and the `uiMenu` prop to override the menu config.
::
::tabs{:selectedIndex="1"}
:component-preset{label="Select (ui)" slug="Select"}
:component-preset{label="SelectMenu (uiMenu)"}
::

View File

@@ -1,8 +1,6 @@
---
title: RadioGroup
description: Display a set of radio buttons.
navigation:
badge: New
links:
- label: GitHub
icon: i-simple-icons-github
@@ -62,7 +60,7 @@ Use the `disabled` prop to disable the RadioGroup.
::component-card
---
baseProps:
options: [{ value: 'email', label: 'Email' }, { value: 'sms', label: 'Phone (SMS)' }, { value: 'push', label: 'Push notification' }]
options: [{ value: 'email', label: 'Email' }, { value: 'sms', label: 'Phone (SMS)' }, { value: 'push', label: 'Push notification', disabled: true }]
modelValue: 'sms'
props:
disabled: true
@@ -70,14 +68,14 @@ props:
::
::callout{icon="i-heroicons-light-bulb"}
This prop also work on the Radio component.
This prop also work on the Radio component and you can set the `disabled` field in the `options` to disable a specific Radio.
::
### Label
Use the `label` prop to display a label on the right of the Radio.
::component-card{slug="radio"}
::component-card{slug="URadio"}
---
props:
label: 'Label'
@@ -88,7 +86,7 @@ props:
Use the `required` prop to display a red star next to the label of the Radio.
::component-card{slug="radio"}
::component-card{slug="URadio"}
---
props:
label: 'Label'
@@ -100,7 +98,7 @@ props:
Use the `help` prop to display some text under the Radio.
::component-card{slug="radio"}
::component-card{slug="URadio"}
---
props:
label: 'Label'
@@ -118,7 +116,7 @@ Use the `#label` slot to override the label of each option.
Alternatively, you can do the same with individual Radio:
::component-card{slug="radio"}
::component-card{slug="URadio"}
---
slots:
label: <span class="italic">Label</span>
@@ -147,14 +145,14 @@ slots:
## Props
:component-props
:u-divider{label="Radio" type="dashed" class="my-12"}
:component-props{slug="radio"}
::tabs
:component-props{label="Radio" slug="URadio"}
:component-props{label="RadioGroup"}
::
## Config
:component-preset
:component-preset{slug="radio"}
::tabs
:component-preset{label="Radio" slug="Radio"}
:component-preset{label="RadioGroup"}
::

View File

@@ -13,7 +13,7 @@ links:
Use a `v-model` to make the Toggle reactive.
:component-example{component="toggle-example"}
### Style
@@ -26,6 +26,17 @@ props:
---
::
### Size
Use the `size` prop to change the size of the Toggle.
::component-card
---
props:
size: 'md'
---
::
### Icon
Use any icon from [Iconify](https://icones.js.org) by setting the `on-icon` and `off-icon` props by using this pattern: `i-{collection_name}-{icon_name}` or change it globally in `ui.toggle.default.onIcon` and `ui.toggle.default.offIcon`.

View File

@@ -163,6 +163,12 @@ code: >-
This will only work with form elements that support the `size` prop.
::
### Eager Validation
By default, validation is only triggered after the initial `blur` event. This is to prevent the form from being validated as the user is typing. You can override this behavior by setting the `eager-validation` prop to `true`
:component-example{component="form-group-eager-validation-example"}
## Slots
### `label`
@@ -247,7 +253,13 @@ props:
Use the `#error` slot to set the custom content for error.
:component-example{component="form-group-error-slot-example" :componentProps='{"class": "w-60"}'}
::component-example
---
component: 'form-group-error-slot-example'
componentProps:
class: 'w-60'
---
::
## Props

View File

@@ -6,6 +6,10 @@ links:
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/data/Table.vue
---
::callout{icon="i-heroicons-puzzle-piece" to="/getting-started/examples#table"}
Check out an example of a Table with advanced features like sorting, pagination, search, etc.
::
## Usage
Use the `rows` prop to set the data to display in the table. By default, the table will display all the fields of the rows.
@@ -13,7 +17,6 @@ Use the `rows` prop to set the data to display in the table. By default, the tab
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-basic'
componentProps:
class: 'flex-1'
@@ -29,11 +32,11 @@ 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.
- `sort` - Pass your own `sort` function. Defaults to a simple _greater than_ / _less than_ comparison.
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-columns'
componentProps:
class: 'flex-1'
@@ -45,7 +48,6 @@ You can easily use the [SelectMenu](/forms/select-menu) component to change the
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-columns-selectable'
componentProps:
class: 'flex-1'
@@ -56,33 +58,100 @@ componentProps:
You can make the columns sortable by setting the `sortable` property to `true` in the column configuration.
You may specify the default direction of each column through the `direction` property. It can be either `asc` or `desc`, but it will default to `asc`.
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-columns-sortable'
componentProps:
class: 'flex-1'
---
::
You may specify the default direction of each column through the `direction` property. It can be either `asc` or `desc`, but it will default to `asc`.
#### Default sorting
You can specify a default sort for the table through the `sort` prop. It's an object with the following properties:
- `column` - The column to sort by.
- `direction` - The sort direction. Can be either `asc` or `desc` and defaults to `asc`.
::callout{icon="i-heroicons-light-bulb"}
This will set the default sort and will work even if no column is set as `sortable`.
```vue
<script setup>
const sort = ref({
column: 'name',
direction: 'desc'
})
const columns = [{
label: 'Name',
key: 'name',
sortable: true
}]
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'
}]
</script>
<template>
<UTable :sort="sort" :columns="columns" :rows="people" />
</template>
```
#### Reactive sorting
You can use a `v-model:sort` to make the sorting reactive. You may also use `@update:sort` to call your own function with the sorting data.
When fetching data from an API, we can take advantage of the [`useFetch`](https://nuxt.com/docs/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/api/composables/use-async-data) composables to fetch the data based on the sorting column and direction every time the `sort` reactive element changes.
When doing so, you might want to set the `sort-mode` prop to `manual` to disable the automatic sorting and return the rows as is. :u-badge{label="New" class="!rounded-full" variant="subtle"}
```vue
<script setup>
// Ensure it uses `ref` instead of `reactive`.
const sort = ref({
column: 'name',
direction: 'desc'
})
const columns = [{
label: 'Name',
key: 'name',
sortable: true
}]
const { data, pending } = await useLazyFetch(() => `/api/users?orderBy=${sort.value.column}&order=${sort.value.direction}`)
</script>
<template>
<UTable v-model:sort="sort" :loading="pending" :columns="columns" :rows="data" sort-mode="manual" />
</template>
```
::callout{icon="i-heroicons-light-bulb" to="https://nuxt.com/docs/api/composables/use-fetch#params" target="_blank"}
We pass a function to `useLazyFetch` here make the url reactive but you can use the `query` / `params` options alongside `watch`.
::
#### Custom sorting
Use the `sort-button` prop to customize the sort button in the header. You can pass all the props of the [Button](/elements/button) component to customize it through this prop or globally through `ui.table.default.sortButton`. Its icon defaults to `i-heroicons-arrows-up-down-20-solid`.
::component-card{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
baseProps:
class: 'w-full'
columns:
@@ -156,44 +225,6 @@ Use the `sort-desc-icon` prop to set a different icon or change it globally in `
You can also customize the entire header cell, read more in the [Slots](#slots) section.
::
#### Reactive sorting :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
Sometimes you will want to fetch new data depending on the sorted column and direction. You can use the `v-model:sort` to automatically update the `ref` reactive element every time the sorting changes on the Table. You may also use `@update:sort` to call your own function with the sorting data.
For example, we can take advantage of `useLazyRefresh` computed URL to automatically fetch the data depending on the sorting column and direction every time the `sort` reactive element changes.
```vue
<script setup>
// Ensure it uses `ref` instead of `reactive`.
const sort = ref({
column: 'name',
direction: 'desc'
})
const columns = [...]
const { data, pending } = useLazyFetch(() => {
return `/api/users?orderBy=${sort.value.column}&order=${sort.value.direction}`
})
</script>
<template>
<UTable v-model:sort="sort" :loading="pending" :columns="columns" :rows="data" />
</template>
```
The initial value of `sort` will be respected as the initial sort column and direction, as well as each column default sorting direction.
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-reactive-sorting'
componentProps:
class: 'flex-1'
---
::
### Selectable
Use a `v-model` to make the table selectable. The `v-model` will be an array of the selected rows.
@@ -201,7 +232,6 @@ Use a `v-model` to make the table selectable. The `v-model` will be an array of
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-selectable'
componentProps:
class: 'flex-1'
@@ -219,7 +249,6 @@ You can use this to navigate to a page, open a modal or even to select the row m
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-clickable'
componentProps:
class: 'flex-1'
@@ -233,7 +262,6 @@ You can easily use the [Input](/forms/input) component to filter the rows.
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-searchable'
componentProps:
class: 'flex-1'
@@ -247,7 +275,6 @@ You can easily use the [Pagination](/navigation/pagination) component to paginat
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-paginable'
componentProps:
class: 'flex-1'
@@ -265,7 +292,6 @@ You can also set it to `null` to hide the loading state.
::component-card
---
padding: false
overflowClass: 'overflow-x-auto'
baseProps:
class: 'w-full'
columns:
@@ -314,7 +340,6 @@ You can also set it to `null` to hide the empty state.
::component-card
---
padding: false
overflowClass: 'overflow-x-auto'
baseProps:
class: 'w-full'
columns:
@@ -380,7 +405,6 @@ You can for example create an extra column for actions with a [Dropdown](/elemen
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-slots'
componentProps:
class: 'flex-1'
@@ -394,7 +418,6 @@ Use the `#loading-state` slot to customize the loading state.
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-loading-slot'
componentProps:
class: 'flex-1'
@@ -408,7 +431,6 @@ Use the `#empty-state` slot to customize the empty state.
::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'table-example-empty-slot'
componentProps:
class: 'flex-1'

View File

@@ -12,8 +12,9 @@ links:
Pass an array to the `links` prop of the VerticalNavigation component. Each link can have the following properties:
- `label` - The label of the link.
- `labelClass` - The class of the link label. :u-badge{label="New" class="!rounded-full" variant="subtle"}
- `icon` - The icon of the link.
- `iconClass` - The class of the icon of the link.
- `iconClass` - The class of the link icon.
- `avatar` - The avatar of the link. You can pass all the props of the [Avatar](/elements/avatar) component.
- `badge` - A badge to display next to the label.
- `click` - The click handler of the link.
@@ -26,6 +27,12 @@ You can also pass any property from the [NuxtLink](https://nuxt.com/docs/api/com
Learn how to build a Tailwind like vertical navigation in the [Examples](/getting-started/examples#verticalnavigation) page.
::
## Sections
Group your navigation links into distinct sections, separated by a divider. You can do this by passing an array of arrays to the `links` prop of the VerticalNavigation component.
:component-example{component="vertical-navigation-example-sections"}
## Slots
You can use slots to customize links display.

View File

@@ -225,7 +225,6 @@ Use the `#empty-state` slot to customize the empty state.
::component-example
---
padding: false
overflowClass: 'overflow-x-auto'
component: 'command-palette-example-empty-slot'
componentProps:
class: 'flex-1'

View File

@@ -46,6 +46,22 @@ props:
---
::
### Disabled :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
Use the `disabled` prop to disable all the buttons.
::component-card
---
baseProps:
modelValue: 1
total: 100
showLast: true
showFirst: true
props:
disabled: true
---
::
### Active / Inactive
Use the `active-button` and `inactive-button` props to customize the active and inactive buttons of the Pagination.
@@ -91,7 +107,7 @@ excludedProps:
---
::
### First / Last :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
### First / Last
Use the `first-button` and `last-button` props to customize the first and last buttons of the Pagination.
@@ -126,7 +142,7 @@ Use the `#prev` and `#next` slots to set the content of the previous and next bu
:component-example{component="pagination-example-prev-next-slots"}
### `first` / `last` :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
### `first` / `last`
Use the `#first` and `#last` slots to set the content of the first and last buttons.

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