mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-16 04:58:12 +01:00
Compare commits
13 Commits
v3.0.0-alp
...
fix/form-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a56de3be0 | ||
|
|
503f701c7e | ||
|
|
d9822db6e8 | ||
|
|
0ceafe1d54 | ||
|
|
f943f88fcc | ||
|
|
e831813aa3 | ||
|
|
37a359701f | ||
|
|
557e0c92a4 | ||
|
|
7f6db45f1e | ||
|
|
a64a7104c5 | ||
|
|
40fc8f3718 | ||
|
|
8059d540e3 | ||
|
|
42fce998e4 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -28,3 +28,5 @@ logs
|
||||
|
||||
playground-vue/auto-imports.d.ts
|
||||
playground-vue/components.d.ts
|
||||
playground-vue/tsconfig.app.tsbuildinfo
|
||||
playground-vue/tsconfig.node.tsbuildinfo
|
||||
|
||||
@@ -20,33 +20,31 @@ const searchTerm = ref('')
|
||||
// useTrackEvent('Search', { props: { query: `${query} - ${searchTerm.value?.commandPaletteRef.results.length} results` } })
|
||||
// }, 500))
|
||||
|
||||
const links = computed(() => {
|
||||
return [{
|
||||
label: 'Docs',
|
||||
icon: 'i-lucide-book-open',
|
||||
to: '/getting-started',
|
||||
active: route.path.startsWith('/getting-started') || route.path.startsWith('/components')
|
||||
}, ...(navigation.value?.find(item => item.path === '/pro')
|
||||
? [{
|
||||
label: 'Pro',
|
||||
icon: 'i-lucide-layers-3',
|
||||
to: '/pro',
|
||||
active: route.path.startsWith('/pro/getting-started') || route.path.startsWith('/pro/components') || route.path.startsWith('/pro/prose')
|
||||
}, {
|
||||
label: 'Pricing',
|
||||
icon: 'i-lucide-credit-card',
|
||||
to: '/pro/pricing'
|
||||
}, {
|
||||
label: 'Templates',
|
||||
icon: 'i-lucide-monitor',
|
||||
to: '/pro/templates'
|
||||
}]
|
||||
: []), {
|
||||
label: 'Releases',
|
||||
icon: 'i-lucide-rocket',
|
||||
to: '/releases'
|
||||
}].filter(Boolean)
|
||||
})
|
||||
const links = computed(() => [{
|
||||
label: 'Docs',
|
||||
icon: 'i-lucide-square-play',
|
||||
to: '/getting-started',
|
||||
active: route.path.startsWith('/getting-started')
|
||||
}, {
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-square-code',
|
||||
to: '/components',
|
||||
active: route.path.startsWith('/components')
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
}, {
|
||||
label: 'Figma',
|
||||
icon: 'i-lucide-figma',
|
||||
to: 'https://www.figma.com/community/file/1288455405058138934',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-lucide-rocket',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}].filter(Boolean))
|
||||
|
||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { ContentNavigationItem } from '@nuxt/content'
|
||||
import type { NavigationMenuItem } from '@nuxt/ui'
|
||||
|
||||
defineProps<{
|
||||
const props = defineProps<{
|
||||
links: NavigationMenuItem[]
|
||||
}>()
|
||||
|
||||
@@ -10,7 +10,7 @@ const config = useRuntimeConfig().public
|
||||
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
|
||||
// const items = computed(() => props.links.map(({ icon, ...link }) => link))
|
||||
const items = computed(() => props.links.map(({ icon, ...link }) => link))
|
||||
|
||||
defineShortcuts({
|
||||
meta_g: () => {
|
||||
@@ -29,7 +29,7 @@ defineShortcuts({
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<!-- <UNavigationMenu :items="items" variant="link" /> -->
|
||||
<UNavigationMenu :items="items" variant="link" />
|
||||
|
||||
<template #right>
|
||||
<ThemePicker />
|
||||
@@ -51,9 +51,9 @@ defineShortcuts({
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<!-- <UNavigationMenu orientation="vertical" :items="items" class="-ml-2.5" />
|
||||
<UNavigationMenu orientation="vertical" :items="links" class="-ml-2.5" />
|
||||
|
||||
<USeparator type="dashed" class="my-4" /> -->
|
||||
<USeparator type="dashed" class="my-4" />
|
||||
|
||||
<UContentNavigation :navigation="navigation" highlight />
|
||||
</template>
|
||||
|
||||
@@ -13,33 +13,31 @@ const colorMode = useColorMode()
|
||||
const { data: navigation } = await useAsyncData('navigation', () => queryCollectionNavigation('content'))
|
||||
const { data: files } = await useAsyncData('files', () => queryCollectionSearchSections('content', { ignoredTags: ['style'] }))
|
||||
|
||||
const links = computed(() => {
|
||||
return [{
|
||||
label: 'Docs',
|
||||
icon: 'i-lucide-book-open',
|
||||
to: '/getting-started',
|
||||
active: route.path.startsWith('/getting-started') || route.path.startsWith('/components')
|
||||
}, ...(navigation.value?.find(item => item.path === '/pro')
|
||||
? [{
|
||||
label: 'Pro',
|
||||
icon: 'i-lucide-layers-3',
|
||||
to: '/pro',
|
||||
active: route.path.startsWith('/pro/getting-started') || route.path.startsWith('/pro/components') || route.path.startsWith('/pro/prose')
|
||||
}, {
|
||||
label: 'Pricing',
|
||||
icon: 'i-lucide-credit-card',
|
||||
to: '/pro/pricing'
|
||||
}, {
|
||||
label: 'Templates',
|
||||
icon: 'i-lucide-monitor',
|
||||
to: '/pro/templates'
|
||||
}]
|
||||
: []), {
|
||||
label: 'Releases',
|
||||
icon: 'i-lucide-rocket',
|
||||
to: '/releases'
|
||||
}].filter(Boolean)
|
||||
})
|
||||
const links = computed(() => [{
|
||||
label: 'Docs',
|
||||
icon: 'i-lucide-square-play',
|
||||
to: '/getting-started',
|
||||
active: route.path.startsWith('/getting-started')
|
||||
}, {
|
||||
label: 'Components',
|
||||
icon: 'i-lucide-square-code',
|
||||
to: '/components',
|
||||
active: route.path.startsWith('/components')
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
}, {
|
||||
label: 'Figma',
|
||||
icon: 'i-lucide-figma',
|
||||
to: 'https://www.figma.com/community/file/1288455405058138934',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Releases',
|
||||
icon: 'i-lucide-rocket',
|
||||
to: 'https://github.com/nuxt/ui/releases',
|
||||
target: '_blank'
|
||||
}].filter(Boolean))
|
||||
|
||||
const color = computed(() => colorMode.value === 'dark' ? (colors as any)[appConfig.ui.colors.neutral][900] : 'white')
|
||||
const radius = computed(() => `:root { --ui-radius: ${appConfig.theme.radius}rem; }`)
|
||||
|
||||
@@ -19,14 +19,14 @@ const { data: surround } = await useAsyncData(`${route.path}-surround`, () => qu
|
||||
|
||||
const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
|
||||
|
||||
const breadcrumb = computed(() => mapContentNavigation(findPageBreadcrumb(navigation?.value, page.value)))
|
||||
const breadcrumb = computed(() => mapContentNavigation(findPageBreadcrumb(navigation?.value, page.value)).map(({ icon, ...link }) => link))
|
||||
|
||||
useSeoMeta({
|
||||
titleTemplate: '%s - Nuxt UI v3',
|
||||
title: typeof page.value.navigation === 'object' ? page.value.navigation.title : page.value.title,
|
||||
ogTitle: `${typeof page.value.navigation === 'object' ? page.value.navigation.title : page.value.title} - Nuxt UI v3`,
|
||||
description: page.value.seo?.description || page.value.description,
|
||||
ogDescription: page.value.seo?.description || page.value.description
|
||||
description: page.value.description,
|
||||
ogDescription: page.value.description
|
||||
})
|
||||
|
||||
defineOgImageComponent('Docs', {
|
||||
@@ -34,7 +34,7 @@ defineOgImageComponent('Docs', {
|
||||
})
|
||||
|
||||
const communityLinks = computed(() => [{
|
||||
icon: 'i-lucide-square-pen',
|
||||
icon: 'i-lucide-file-pen',
|
||||
label: 'Edit this page',
|
||||
to: `https://github.com/nuxt/ui/edit/v3/docs/content/${page?.value?.stem}.md`,
|
||||
target: '_blank'
|
||||
@@ -43,10 +43,6 @@ const communityLinks = computed(() => [{
|
||||
label: 'Star on GitHub',
|
||||
to: 'https://github.com/nuxt/ui',
|
||||
target: '_blank'
|
||||
}, {
|
||||
label: 'Roadmap',
|
||||
icon: 'i-lucide-map',
|
||||
to: '/roadmap'
|
||||
}])
|
||||
|
||||
// const resourcesLinks = [{
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
title: Getting Started
|
||||
icon: i-lucide-square-play
|
||||
|
||||
@@ -254,6 +254,8 @@ Nuxt UI provides a comprehensive set of design tokens for the `neutral` color pa
|
||||
|
||||
/* Main background color */
|
||||
--ui-bg: var(--color-white);
|
||||
/* Subtle background */
|
||||
--ui-bg-muted: var(--ui-color-neutral-50);
|
||||
/* Slightly elevated background */
|
||||
--ui-bg-elevated: var(--ui-color-neutral-100);
|
||||
/* More prominent background */
|
||||
@@ -263,6 +265,8 @@ Nuxt UI provides a comprehensive set of design tokens for the `neutral` color pa
|
||||
|
||||
/* Default border color */
|
||||
--ui-border: var(--ui-color-neutral-200);
|
||||
/* Subtle border */
|
||||
--ui-border-muted: var(--ui-color-neutral-200);
|
||||
/* More prominent border */
|
||||
--ui-border-accented: var(--ui-color-neutral-300);
|
||||
/* Inverted border color */
|
||||
@@ -285,6 +289,8 @@ Nuxt UI provides a comprehensive set of design tokens for the `neutral` color pa
|
||||
|
||||
/* Main background color */
|
||||
--ui-bg: var(--ui-color-neutral-900);
|
||||
/* Subtle background */
|
||||
--ui-bg-muted: var(--ui-color-neutral-800);
|
||||
/* Slightly elevated background */
|
||||
--ui-bg-elevated: var(--ui-color-neutral-800);
|
||||
/* More prominent background */
|
||||
@@ -294,6 +300,8 @@ Nuxt UI provides a comprehensive set of design tokens for the `neutral` color pa
|
||||
|
||||
/* Default border color */
|
||||
--ui-border: var(--ui-color-neutral-800);
|
||||
/* Subtle border */
|
||||
--ui-border-muted: var(--ui-color-neutral-700);
|
||||
/* More prominent border */
|
||||
--ui-border-accented: var(--ui-color-neutral-700);
|
||||
/* Inverted border color */
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
---
|
||||
title: Icons
|
||||
description: 'Nuxt UI integrates with `@nuxt/icon` to access over 200,000+ icons from [Iconify](https://iconify.design/).'
|
||||
seo.description: 'Nuxt UI integrates with `@nuxt/icon` to access over 200,000+ icons from Iconify.'
|
||||
description: 'Nuxt UI integrates with Nuxt Icon to access over 200,000+ icons from Iconify.'
|
||||
links:
|
||||
- label: 'Iconify'
|
||||
to: https://iconify.design/
|
||||
target: _blank
|
||||
icon: i-simple-icons-iconify
|
||||
- label: 'nuxt/icon'
|
||||
to: https://github.com/nuxt/icon
|
||||
target: _blank
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Fonts
|
||||
description: 'Nuxt UI integrates with `@nuxt/fonts` to provide plug-and-play font optimization.'
|
||||
description: 'Nuxt UI integrates with Nuxt Fonts to provide plug-and-play font optimization.'
|
||||
links:
|
||||
- label: 'nuxt/fonts'
|
||||
to: https://github.com/nuxt/fonts
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Color Mode
|
||||
description: 'Nuxt UI integrates with `@nuxtjs/color-mode` to allow for easy switching between light and dark themes.'
|
||||
description: 'Nuxt UI integrates with Nuxt Color Mode to allow for easy switching between light and dark themes.'
|
||||
links:
|
||||
- label: 'nuxtjs/color-mode'
|
||||
to: https://github.com/nuxt-modules/color-mode
|
||||
@@ -10,7 +10,7 @@ links:
|
||||
|
||||
## Usage
|
||||
|
||||
Nuxt UI automatically registers the `@nuxtjs/color-mode` module for you, so there's no additional setup required.
|
||||
Nuxt UI automatically registers the [`@nuxtjs/color-mode`](https://github.com/nuxt-modules/color-mode) module for you, so there's no additional setup required.
|
||||
|
||||
You can disable dark mode by setting the `preference` to `light` instead of `system` in your `nuxt.config.ts`.
|
||||
|
||||
|
||||
2
docs/content/2.composables/.navigation.yml
Normal file
2
docs/content/2.composables/.navigation.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
title: Composables
|
||||
icon: i-lucide-square-function
|
||||
2
docs/content/3.components/.navigation.yml
Normal file
2
docs/content/3.components/.navigation.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
title: Components
|
||||
icon: i-lucide-square-code
|
||||
@@ -1,9 +1,10 @@
|
||||
---
|
||||
title: CommandPalette
|
||||
description: A command palette with full-text search powered by [Fuse.js](https://fusejs.io/) for efficient fuzzy matching.
|
||||
seo:
|
||||
description: A command palette with full-text search powered by Fuse.js for efficient fuzzy matching.
|
||||
description: A command palette with full-text search powered by Fuse.js for efficient fuzzy matching.
|
||||
links:
|
||||
- label: Fuse.js
|
||||
to: https://fusejs.io/
|
||||
target: _blank
|
||||
- label: Combobox
|
||||
icon: i-custom-radix-vue
|
||||
to: https://www.radix-vue.com/components/combobox.html
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"@iconify-json/lucide": "^1.2.12",
|
||||
"@iconify-json/simple-icons": "^1.2.11",
|
||||
"@iconify-json/vscode-icons": "^1.2.2",
|
||||
"@nuxt/content": "3.0.0-alpha.6",
|
||||
"@nuxt/content": "3.0.0-alpha.5",
|
||||
"@nuxt/image": "^1.8.1",
|
||||
"@nuxt/ui": "latest",
|
||||
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@62862c8",
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
"embla-carousel-fade": "^8.3.1",
|
||||
"embla-carousel-vue": "^8.3.1",
|
||||
"embla-carousel-wheel-gestures": "^8.0.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fuse.js": "^7.0.0",
|
||||
"get-port-please": "^3.1.2",
|
||||
"knitwork": "^1.1.0",
|
||||
|
||||
@@ -30,6 +30,6 @@ export default defineConfig({
|
||||
],
|
||||
optimizeDeps: {
|
||||
// prevents reloading page when navigating between components
|
||||
include: ['radix-vue/namespaced', 'vaul-vue', 'fast-deep-equal', 'embla-carousel-vue', 'embla-carousel-autoplay', 'embla-carousel-auto-scroll', 'embla-carousel-auto-height', 'embla-carousel-class-names', 'embla-carousel-fade', 'embla-carousel-wheel-gestures']
|
||||
include: ['radix-vue/namespaced', 'vaul-vue', 'embla-carousel-vue', 'embla-carousel-autoplay', 'embla-carousel-auto-scroll', 'embla-carousel-auto-height', 'embla-carousel-class-names', 'embla-carousel-fade', 'embla-carousel-wheel-gestures']
|
||||
}
|
||||
})
|
||||
|
||||
20
pnpm-lock.yaml
generated
20
pnpm-lock.yaml
generated
@@ -79,9 +79,6 @@ importers:
|
||||
embla-carousel-wheel-gestures:
|
||||
specifier: ^8.0.1
|
||||
version: 8.0.1(embla-carousel@8.3.1)
|
||||
fast-deep-equal:
|
||||
specifier: ^3.1.3
|
||||
version: 3.1.3
|
||||
fuse.js:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0
|
||||
@@ -243,8 +240,8 @@ importers:
|
||||
specifier: ^1.2.2
|
||||
version: 1.2.2
|
||||
'@nuxt/content':
|
||||
specifier: 3.0.0-alpha.6
|
||||
version: 3.0.0-alpha.6(magicast@0.3.5)(pg@8.13.1)(rollup@4.24.4)
|
||||
specifier: 3.0.0-alpha.5
|
||||
version: 3.0.0-alpha.5(magicast@0.3.5)(pg@8.13.1)(rollup@4.24.4)
|
||||
'@nuxt/image':
|
||||
specifier: ^1.8.1
|
||||
version: 1.8.1(ioredis@5.4.1)(magicast@0.3.5)(rollup@4.24.4)
|
||||
@@ -1338,8 +1335,8 @@ packages:
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@nuxt/content@3.0.0-alpha.6':
|
||||
resolution: {integrity: sha512-vxn1iMa3YrrnYs3f9DNx9/R/AncK87kFbysNmjH634JBcLC1yCMWqCq4VvasdFx4ko3x5ip+9m9J3z3SjUaPZQ==}
|
||||
'@nuxt/content@3.0.0-alpha.5':
|
||||
resolution: {integrity: sha512-q1eNWF+nTVqDzdMZjwBmq2IQTGf2ycf1wcBTZg3jEBlPm0B4T8CP4p3lt3QNZUZpmihmdFbW3aggdZX07WnkGw==}
|
||||
peerDependencies:
|
||||
pg: '*'
|
||||
|
||||
@@ -5142,6 +5139,9 @@ packages:
|
||||
pako@0.2.9:
|
||||
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
|
||||
|
||||
pako@2.1.0:
|
||||
resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
|
||||
|
||||
parent-module@1.0.1:
|
||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -7738,13 +7738,12 @@ snapshots:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.17.1
|
||||
|
||||
'@nuxt/content@3.0.0-alpha.6(magicast@0.3.5)(pg@8.13.1)(rollup@4.24.4)':
|
||||
'@nuxt/content@3.0.0-alpha.5(magicast@0.3.5)(pg@8.13.1)(rollup@4.24.4)':
|
||||
dependencies:
|
||||
'@nuxt/kit': 3.14.159(magicast@0.3.5)(rollup@4.24.4)
|
||||
'@nuxtjs/mdc': 0.9.2(magicast@0.3.5)(rollup@4.24.4)
|
||||
'@sqlite.org/sqlite-wasm': 3.47.0-build1
|
||||
better-sqlite3: 11.5.0
|
||||
c12: 2.0.1(magicast@0.3.5)
|
||||
chokidar: 4.0.1
|
||||
consola: 3.2.3
|
||||
defu: 6.1.4
|
||||
@@ -7762,6 +7761,7 @@ snapshots:
|
||||
micromark-util-sanitize-uri: 2.0.0
|
||||
micromatch: 4.0.8
|
||||
ohash: 1.1.4
|
||||
pako: 2.1.0
|
||||
pathe: 1.1.2
|
||||
pg: 8.13.1
|
||||
remark-mdc: 3.2.1
|
||||
@@ -12765,6 +12765,8 @@ snapshots:
|
||||
|
||||
pako@0.2.9: {}
|
||||
|
||||
pako@2.1.0: {}
|
||||
|
||||
parent-module@1.0.1:
|
||||
dependencies:
|
||||
callsites: 3.1.0
|
||||
|
||||
@@ -127,8 +127,6 @@ export default defineNuxtModule<ModuleOptions>({
|
||||
|
||||
addTemplates(options, nuxt, resolve)
|
||||
|
||||
nuxt.options.vite = defu(nuxt.options?.vite, { optimizeDeps: { include: ['fast-deep-equal'] } })
|
||||
|
||||
if (nuxt.options.dev && nuxt.options.devtools.enabled && options.devtools?.enabled) {
|
||||
const templates = buildTemplates(options)
|
||||
nuxt.options.vite = defu(nuxt.options?.vite, { plugins: [devtoolsMetaPlugin({ resolve, templates, options })] })
|
||||
|
||||
@@ -196,7 +196,7 @@ provide(formOptionsInjectionKey, computed(() => ({
|
||||
validateOnInputDelay: props.validateOnInputDelay
|
||||
})))
|
||||
|
||||
defineExpose<Form<T>>({
|
||||
defineExpose<{ $el: HTMLFormElement | HTMLDivElement } & Form<T>>({
|
||||
validate: _validate,
|
||||
errors,
|
||||
|
||||
@@ -230,7 +230,7 @@ defineExpose<Form<T>>({
|
||||
},
|
||||
|
||||
disabled
|
||||
})
|
||||
} as { $el: HTMLFormElement | HTMLDivElement } & Form<T>)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -92,7 +92,7 @@ export interface InputMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends Ma
|
||||
* When `items` is an array of objects, select the field to use as the label.
|
||||
* @defaultValue 'label'
|
||||
*/
|
||||
labelKey?: keyof T
|
||||
labelKey?: V
|
||||
items?: I
|
||||
/** Highlight the ring color like a focus state. */
|
||||
highlight?: boolean
|
||||
@@ -131,7 +131,7 @@ extendDevtoolsMeta({ defaultProps: { items: ['Option 1', 'Option 2', 'Option 3']
|
||||
import { computed, ref, toRef, onMounted } from 'vue'
|
||||
import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, useForwardPropsEmits } from 'radix-vue'
|
||||
import { defu } from 'defu'
|
||||
import * as isEqual from 'fast-deep-equal'
|
||||
import { isEqual } from 'ohash'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
import { useAppConfig } from '#imports'
|
||||
import { useButtonGroup } from '../composables/useButtonGroup'
|
||||
@@ -149,7 +149,7 @@ const props = withDefaults(defineProps<InputMenuProps<T, I, V, M>>(), {
|
||||
autofocusDelay: 0,
|
||||
portal: true,
|
||||
filter: () => ['label'],
|
||||
labelKey: 'label' as keyof T
|
||||
labelKey: 'label' as never
|
||||
})
|
||||
const emits = defineEmits<InputMenuEmits<T, V, M>>()
|
||||
const slots = defineSlots<InputMenuSlots<T>>()
|
||||
@@ -157,9 +157,11 @@ const slots = defineSlots<InputMenuSlots<T>>()
|
||||
const searchTerm = defineModel<string>('searchTerm', { default: '' })
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'multiple', 'resetSearchTermOnBlur'), emits)
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'resetSearchTermOnBlur'), emits)
|
||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, position: 'popper' }) as ComboboxContentProps)
|
||||
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
||||
// This is a hack due to generic boolean casting (see https://github.com/nuxt/ui/issues/2541)
|
||||
const multiple = toRef(() => typeof props.multiple === 'string' ? true : props.multiple)
|
||||
|
||||
const { emitFormBlur, emitFormChange, emitFormInput, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
|
||||
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
||||
@@ -175,17 +177,21 @@ const ui = computed(() => inputMenu({
|
||||
highlight: highlight.value,
|
||||
leading: isLeading.value || !!props.avatar || !!slots.leading,
|
||||
trailing: isTrailing.value || !!slots.trailing,
|
||||
multiple: props.multiple,
|
||||
multiple: multiple.value,
|
||||
buttonGroup: orientation.value
|
||||
}))
|
||||
|
||||
function displayValue(value: AcceptableValue): string {
|
||||
const item = items.value.find(item => props.valueKey ? isEqual.default(get(item as Record<string, any>, props.valueKey as string), value) : isEqual.default(item, value))
|
||||
function displayValue(value: T): string {
|
||||
if (!props.valueKey) {
|
||||
return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
|
||||
}
|
||||
|
||||
const item = items.value.find(item => isEqual(get(item as Record<string, any>, props.valueKey as string), value))
|
||||
|
||||
return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
|
||||
}
|
||||
|
||||
function filterFunction(items: ArrayOrWrapped<AcceptableValue>, searchTerm: string): ArrayOrWrapped<AcceptableValue> {
|
||||
function filterFunction(items: ArrayOrWrapped<T>, searchTerm: string): ArrayOrWrapped<T> {
|
||||
if (props.filter === false) {
|
||||
return items
|
||||
}
|
||||
@@ -265,6 +271,7 @@ defineExpose({
|
||||
v-model:search-term="searchTerm"
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:multiple="multiple"
|
||||
:display-value="displayValue"
|
||||
:filter-function="filterFunction"
|
||||
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
||||
|
||||
@@ -70,7 +70,7 @@ export interface SelectProps<T extends MaybeArrayOfArrayItem<I>, I extends Maybe
|
||||
* When `items` is an array of objects, select the field to use as the label.
|
||||
* @defaultValue 'label'
|
||||
*/
|
||||
labelKey?: SelectItemKey<T>
|
||||
labelKey?: V
|
||||
items?: I
|
||||
/** Highlight the ring color like a focus state. */
|
||||
highlight?: boolean
|
||||
|
||||
@@ -83,7 +83,7 @@ export interface SelectMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends M
|
||||
* When `items` is an array of objects, select the field to use as the label.
|
||||
* @defaultValue 'label'
|
||||
*/
|
||||
labelKey?: SelectItemKey<T>
|
||||
labelKey?: V
|
||||
items?: I
|
||||
/** Highlight the ring color like a focus state. */
|
||||
highlight?: boolean
|
||||
@@ -121,7 +121,7 @@ extendDevtoolsMeta({ defaultProps: { items: ['Option 1', 'Option 2', 'Option 3']
|
||||
import { computed, toRef } from 'vue'
|
||||
import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, useForwardPropsEmits } from 'radix-vue'
|
||||
import { defu } from 'defu'
|
||||
import * as isEqual from 'fast-deep-equal'
|
||||
import { isEqual } from 'ohash'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
import { useAppConfig } from '#imports'
|
||||
import { useButtonGroup } from '../composables/useButtonGroup'
|
||||
@@ -147,9 +147,11 @@ const slots = defineSlots<SelectMenuSlots<T>>()
|
||||
const searchTerm = defineModel<string>('searchTerm', { default: '' })
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'multiple', 'resetSearchTermOnBlur'), emits)
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'resetSearchTermOnBlur'), emits)
|
||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, position: 'popper' }) as ComboboxContentProps)
|
||||
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
||||
// This is a hack due to generic boolean casting (see https://github.com/nuxt/ui/issues/2541)
|
||||
const multiple = toRef(() => typeof props.multiple === 'string' ? true : props.multiple)
|
||||
|
||||
const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
|
||||
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
||||
@@ -169,11 +171,15 @@ const ui = computed(() => selectMenu({
|
||||
}))
|
||||
|
||||
function displayValue(value: T | T[]): string {
|
||||
if (props.multiple && Array.isArray(value)) {
|
||||
return value.map(v => displayValue(v)).join(', ')
|
||||
if (multiple.value && Array.isArray(value)) {
|
||||
return value.map(v => displayValue(v)).filter(Boolean).join(', ')
|
||||
}
|
||||
|
||||
const item = items.value.find(item => props.valueKey ? isEqual.default(get(item as Record<string, any>, props.valueKey as string), value) : isEqual.default(item, value))
|
||||
if (!props.valueKey) {
|
||||
return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
|
||||
}
|
||||
|
||||
const item = items.value.find(item => isEqual(get(item as Record<string, any>, props.valueKey as string), value))
|
||||
|
||||
return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
|
||||
}
|
||||
@@ -232,6 +238,7 @@ function onUpdateOpen(value: boolean) {
|
||||
as-child
|
||||
:name="name"
|
||||
:disabled="disabled"
|
||||
:multiple="multiple"
|
||||
:display-value="() => searchTerm"
|
||||
:filter-function="filterFunction"
|
||||
@update:model-value="onUpdate"
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
--ui-text-highlighted: var(--ui-color-neutral-900);
|
||||
|
||||
--ui-bg: var(--color-white);
|
||||
--ui-bg-muted: var(--ui-color-neutral-50);
|
||||
--ui-bg-elevated: var(--ui-color-neutral-100);
|
||||
--ui-bg-accented: var(--ui-color-neutral-200);
|
||||
--ui-bg-inverted: var(--ui-color-neutral-900);
|
||||
|
||||
--ui-border: var(--ui-color-neutral-200);
|
||||
--ui-border-muted: var(--ui-color-neutral-200);
|
||||
--ui-border-accented: var(--ui-color-neutral-300);
|
||||
--ui-border-inverted: var(--ui-color-neutral-900);
|
||||
|
||||
@@ -42,11 +44,13 @@
|
||||
--ui-text-highlighted: var(--color-white);
|
||||
|
||||
--ui-bg: var(--ui-color-neutral-900);
|
||||
--ui-bg-muted: var(--ui-color-neutral-800);
|
||||
--ui-bg-elevated: var(--ui-color-neutral-800);
|
||||
--ui-bg-accented: var(--ui-color-neutral-700);
|
||||
--ui-bg-inverted: var(--color-white);
|
||||
|
||||
--ui-border: var(--ui-color-neutral-800);
|
||||
--ui-border-muted: var(--ui-color-neutral-700);
|
||||
--ui-border-accented: var(--ui-color-neutral-700);
|
||||
--ui-border-inverted: var(--color-white);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user