@nuxt/ui 3.0.0-alpha.8 → 3.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.nuxt/ui/accordion.ts +2 -2
- package/.nuxt/ui/alert.ts +122 -95
- package/.nuxt/ui/avatar-group.ts +14 -2
- package/.nuxt/ui/avatar.ts +16 -4
- package/.nuxt/ui/badge.ts +139 -93
- package/.nuxt/ui/breadcrumb.ts +5 -5
- package/.nuxt/ui/button-group.ts +13 -0
- package/.nuxt/ui/button.ts +167 -136
- package/.nuxt/ui/calendar.ts +103 -0
- package/.nuxt/ui/card.ts +27 -1
- package/.nuxt/ui/carousel.ts +9 -7
- package/.nuxt/ui/checkbox.ts +45 -27
- package/.nuxt/ui/chip.ts +44 -15
- package/.nuxt/ui/color-picker.ts +47 -0
- package/.nuxt/ui/command-palette.ts +28 -18
- package/.nuxt/ui/container.ts +1 -1
- package/.nuxt/ui/context-menu.ts +64 -46
- package/.nuxt/ui/drawer.ts +83 -15
- package/.nuxt/ui/dropdown-menu.ts +65 -47
- package/.nuxt/ui/form-field.ts +15 -7
- package/.nuxt/ui/index.ts +7 -1
- package/.nuxt/ui/input-menu.ts +150 -116
- package/.nuxt/ui/input-number.ts +235 -0
- package/.nuxt/ui/input.ts +111 -76
- package/.nuxt/ui/kbd.ts +18 -6
- package/.nuxt/ui/link.ts +3 -3
- package/.nuxt/ui/modal.ts +8 -7
- package/.nuxt/ui/navigation-menu.ts +244 -131
- package/.nuxt/ui/pin-input.ts +171 -0
- package/.nuxt/ui/popover.ts +2 -2
- package/.nuxt/ui/progress.ts +111 -72
- package/.nuxt/ui/radio-group.ts +45 -22
- package/.nuxt/ui/select-menu.ts +127 -96
- package/.nuxt/ui/select.ts +120 -84
- package/.nuxt/ui/separator.ts +60 -31
- package/.nuxt/ui/skeleton.ts +1 -1
- package/.nuxt/ui/slideover.ts +17 -9
- package/.nuxt/ui/slider.ts +61 -38
- package/.nuxt/ui/stepper.ts +202 -0
- package/.nuxt/ui/switch.ts +40 -22
- package/.nuxt/ui/table.ts +49 -31
- package/.nuxt/ui/tabs.ts +101 -73
- package/.nuxt/ui/textarea.ts +111 -76
- package/.nuxt/ui/toast.ts +53 -33
- package/.nuxt/ui/toaster.ts +31 -15
- package/.nuxt/ui/tooltip.ts +2 -2
- package/.nuxt/ui/tree.ts +154 -0
- package/.nuxt/ui.css +92 -0
- package/README.md +69 -18
- package/cli/commands/{init.mjs → make/component.mjs} +16 -4
- package/cli/commands/make/index.mjs +14 -0
- package/cli/commands/make/locale.mjs +64 -0
- package/cli/index.mjs +2 -2
- package/cli/package.json +2 -2
- package/cli/templates.mjs +62 -12
- package/cli/utils.mjs +14 -0
- package/dist/module.cjs +9 -170
- package/dist/module.d.cts +5 -15
- package/dist/module.d.mts +5 -15
- package/dist/module.d.ts +5 -15
- package/dist/module.json +2 -2
- package/dist/module.mjs +12 -167
- package/dist/runtime/components/Accordion.vue +8 -39
- package/dist/runtime/components/Alert.vue +25 -21
- package/dist/runtime/components/App.vue +15 -15
- package/dist/runtime/components/Avatar.vue +33 -21
- package/dist/runtime/components/AvatarGroup.vue +5 -7
- package/dist/runtime/components/Badge.vue +10 -8
- package/dist/runtime/components/Breadcrumb.vue +13 -34
- package/dist/runtime/components/Button.vue +5 -8
- package/dist/runtime/components/ButtonGroup.vue +5 -7
- package/dist/runtime/components/Calendar.vue +194 -0
- package/dist/runtime/components/Card.vue +10 -9
- package/dist/runtime/components/Carousel.vue +26 -17
- package/dist/runtime/components/Checkbox.vue +32 -38
- package/dist/runtime/components/Chip.vue +6 -8
- package/dist/runtime/components/Collapsible.vue +10 -11
- package/dist/runtime/components/ColorPicker.vue +297 -0
- package/dist/runtime/components/CommandPalette.vue +114 -98
- package/dist/runtime/components/Container.vue +4 -7
- package/dist/runtime/components/ContextMenu.vue +16 -69
- package/dist/runtime/components/ContextMenuContent.vue +14 -10
- package/dist/runtime/components/Drawer.vue +23 -12
- package/dist/runtime/components/DropdownMenu.vue +18 -59
- package/dist/runtime/components/DropdownMenuContent.vue +14 -10
- package/dist/runtime/components/Form.vue +78 -49
- package/dist/runtime/components/FormField.vue +28 -15
- package/dist/runtime/components/Icon.vue +1 -1
- package/dist/runtime/components/Input.vue +15 -7
- package/dist/runtime/components/InputMenu.vue +133 -66
- package/dist/runtime/components/InputNumber.vue +197 -0
- package/dist/runtime/components/Kbd.vue +5 -6
- package/dist/runtime/components/Link.vue +24 -13
- package/dist/runtime/components/LinkBase.vue +1 -1
- package/dist/runtime/components/Modal.vue +56 -34
- package/dist/runtime/components/NavigationMenu.vue +129 -112
- package/dist/runtime/components/OverlayProvider.vue +28 -0
- package/dist/runtime/components/Pagination.vue +18 -14
- package/dist/runtime/components/PinInput.vue +95 -0
- package/dist/runtime/components/Popover.vue +28 -14
- package/dist/runtime/components/Progress.vue +28 -12
- package/dist/runtime/components/RadioGroup.vue +9 -12
- package/dist/runtime/components/Select.vue +61 -35
- package/dist/runtime/components/SelectMenu.vue +201 -130
- package/dist/runtime/components/Separator.vue +6 -5
- package/dist/runtime/components/Skeleton.vue +4 -7
- package/dist/runtime/components/Slideover.vue +56 -33
- package/dist/runtime/components/Slider.vue +8 -7
- package/dist/runtime/components/Stepper.vue +170 -0
- package/dist/runtime/components/Switch.vue +19 -23
- package/dist/runtime/components/Table.vue +157 -32
- package/dist/runtime/components/Tabs.vue +12 -31
- package/dist/runtime/components/Textarea.vue +18 -9
- package/dist/runtime/components/Toast.vue +39 -25
- package/dist/runtime/components/Toaster.vue +31 -24
- package/dist/runtime/components/Tooltip.vue +9 -12
- package/dist/runtime/components/Tree.vue +196 -0
- package/dist/runtime/composables/defineLocale.d.ts +9 -0
- package/dist/runtime/composables/defineLocale.js +4 -0
- package/dist/runtime/composables/defineShortcuts.d.ts +1 -1
- package/dist/runtime/composables/defineShortcuts.js +2 -2
- package/dist/runtime/composables/useFormField.d.ts +11 -4
- package/dist/runtime/composables/useFormField.js +19 -9
- package/dist/runtime/composables/useLocale.d.ts +4 -0
- package/dist/runtime/composables/useLocale.js +10 -0
- package/dist/runtime/composables/useOverlay.d.ts +30 -0
- package/dist/runtime/composables/useOverlay.js +70 -0
- package/dist/runtime/composables/useToast.d.ts +4 -3
- package/dist/runtime/composables/useToast.js +20 -6
- package/dist/runtime/index.css +1 -1
- package/dist/runtime/keyframes.css +1 -1
- package/dist/runtime/locale/ar.d.ts +2 -0
- package/dist/runtime/locale/ar.js +55 -0
- package/dist/runtime/locale/az.d.ts +2 -0
- package/dist/runtime/locale/az.js +54 -0
- package/dist/runtime/locale/bn.d.ts +2 -0
- package/dist/runtime/locale/bn.js +54 -0
- package/dist/runtime/locale/cs.d.ts +2 -0
- package/dist/runtime/locale/cs.js +54 -0
- package/dist/runtime/locale/da.d.ts +2 -0
- package/dist/runtime/locale/da.js +54 -0
- package/dist/runtime/locale/de.d.ts +2 -0
- package/dist/runtime/locale/de.js +54 -0
- package/dist/runtime/locale/el.d.ts +2 -0
- package/dist/runtime/locale/el.js +54 -0
- package/dist/runtime/locale/en.d.ts +2 -0
- package/dist/runtime/locale/en.js +54 -0
- package/dist/runtime/locale/es.d.ts +2 -0
- package/dist/runtime/locale/es.js +54 -0
- package/dist/runtime/locale/et.d.ts +2 -0
- package/dist/runtime/locale/et.js +54 -0
- package/dist/runtime/locale/fa_ir.d.ts +2 -0
- package/dist/runtime/locale/fa_ir.js +55 -0
- package/dist/runtime/locale/fi.d.ts +2 -0
- package/dist/runtime/locale/fi.js +54 -0
- package/dist/runtime/locale/fr.d.ts +2 -0
- package/dist/runtime/locale/fr.js +54 -0
- package/dist/runtime/locale/he.d.ts +2 -0
- package/dist/runtime/locale/he.js +53 -0
- package/dist/runtime/locale/hi.d.ts +2 -0
- package/dist/runtime/locale/hi.js +54 -0
- package/dist/runtime/locale/hu.d.ts +2 -0
- package/dist/runtime/locale/hu.js +54 -0
- package/dist/runtime/locale/id.d.ts +2 -0
- package/dist/runtime/locale/id.js +54 -0
- package/dist/runtime/locale/index.d.ts +34 -0
- package/dist/runtime/locale/index.js +34 -0
- package/dist/runtime/locale/it.d.ts +2 -0
- package/dist/runtime/locale/it.js +54 -0
- package/dist/runtime/locale/ja.d.ts +2 -0
- package/dist/runtime/locale/ja.js +54 -0
- package/dist/runtime/locale/km.d.ts +2 -0
- package/dist/runtime/locale/km.js +54 -0
- package/dist/runtime/locale/ko.d.ts +2 -0
- package/dist/runtime/locale/ko.js +54 -0
- package/dist/runtime/locale/nb_no.d.ts +2 -0
- package/dist/runtime/locale/nb_no.js +54 -0
- package/dist/runtime/locale/nl.d.ts +2 -0
- package/dist/runtime/locale/nl.js +54 -0
- package/dist/runtime/locale/pl.d.ts +2 -0
- package/dist/runtime/locale/pl.js +54 -0
- package/dist/runtime/locale/pt.d.ts +2 -0
- package/dist/runtime/locale/pt.js +54 -0
- package/dist/runtime/locale/pt_br.d.ts +2 -0
- package/dist/runtime/locale/pt_br.js +54 -0
- package/dist/runtime/locale/ru.d.ts +2 -0
- package/dist/runtime/locale/ru.js +54 -0
- package/dist/runtime/locale/sk.d.ts +2 -0
- package/dist/runtime/locale/sk.js +54 -0
- package/dist/runtime/locale/sv.d.ts +2 -0
- package/dist/runtime/locale/sv.js +54 -0
- package/dist/runtime/locale/th.d.ts +2 -0
- package/dist/runtime/locale/th.js +54 -0
- package/dist/runtime/locale/tr.d.ts +2 -0
- package/dist/runtime/locale/tr.js +54 -0
- package/dist/runtime/locale/uk.d.ts +2 -0
- package/dist/runtime/locale/uk.js +54 -0
- package/dist/runtime/locale/vi.d.ts +2 -0
- package/dist/runtime/locale/vi.js +54 -0
- package/dist/runtime/locale/zh_cn.d.ts +2 -0
- package/dist/runtime/locale/zh_cn.js +54 -0
- package/dist/runtime/locale/zh_tw.d.ts +2 -0
- package/dist/runtime/locale/zh_tw.js +54 -0
- package/dist/runtime/plugins/colors.js +8 -5
- package/dist/runtime/types/form.d.ts +29 -15
- package/dist/runtime/types/form.js +2 -2
- package/dist/runtime/types/index.d.ts +8 -0
- package/dist/runtime/types/index.js +8 -0
- package/dist/runtime/types/locale.d.ts +56 -0
- package/dist/runtime/types/locale.js +0 -0
- package/dist/runtime/types/utils.d.ts +7 -3
- package/dist/runtime/utils/form.d.ts +5 -9
- package/dist/runtime/utils/form.js +113 -50
- package/dist/runtime/utils/index.d.ts +1 -1
- package/dist/runtime/utils/index.js +15 -2
- package/dist/runtime/utils/link.d.ts +1 -1
- package/dist/runtime/utils/locale.d.ts +15 -0
- package/dist/runtime/utils/locale.js +25 -0
- package/dist/runtime/utils/tv.d.ts +1 -0
- package/dist/runtime/utils/tv.js +4 -0
- package/dist/runtime/vue/components/Icon.vue +2 -2
- package/dist/runtime/vue/components/Link.vue +87 -23
- package/dist/runtime/vue/composables/useAppConfig.d.ts +1 -0
- package/dist/runtime/vue/composables/useAppConfig.js +2 -0
- package/dist/runtime/vue/plugins/head.d.ts +1 -1
- package/dist/runtime/vue/plugins/head.js +3 -3
- package/dist/runtime/vue/stubs.d.ts +19 -0
- package/dist/runtime/vue/stubs.js +37 -0
- package/dist/shared/{ui.BufKhDiD.mjs → ui.DSPu6Y8j.mjs} +1071 -409
- package/dist/shared/{ui.BU7wzH0D.cjs → ui.DfK2RX6G.cjs} +1074 -409
- package/dist/unplugin.cjs +62 -26
- package/dist/unplugin.d.cts +17 -3
- package/dist/unplugin.d.mts +17 -3
- package/dist/unplugin.d.ts +17 -3
- package/dist/unplugin.mjs +61 -25
- package/dist/vite.cjs +3 -2
- package/dist/vite.d.cts +2 -0
- package/dist/vite.d.mts +2 -0
- package/dist/vite.d.ts +2 -0
- package/dist/vite.mjs +3 -2
- package/package.json +110 -67
- package/dist/chunks/component-meta.cjs +0 -73264
- package/dist/chunks/component-meta.mjs +0 -73262
- package/dist/client/devtools/200.html +0 -1
- package/dist/client/devtools/404.html +0 -1
- package/dist/client/devtools/_fonts/rP2Wp2ywxg089UriCZaSExd86J3t9jz86MvyyKK58UfivUw4aw-SK92LTmKP0.woff2 +0 -0
- package/dist/client/devtools/_fonts/rP2Wp2ywxg089UriCZaSExd86J3t9jz86MvyyKy58UfivUw-9uYm8d48E4.woff2 +0 -0
- package/dist/client/devtools/_fonts/rP2Yp2ywxg089UriI5-g4vlH9VoD8Cmcqbu0-K6z9mXg-VNw7NHvqnp.woff2 +0 -0
- package/dist/client/devtools/_fonts/rP2Yp2ywxg089UriI5-g4vlH9VoD8Cmcqbu6-K6z9mXgjU0-EkYdMs3MAX.woff2 +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-7DW3w-R7n06NbhGy.woff +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-JDG3w-leGNfkTmsj.woff +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-JDW3w-ciElMF03ku.woff +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8JCm3w-sB722Uoa0f.woff +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8JDW3w-PBDI1JDjwV.woff +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8gCm3w-0q1hqVn09O.woff +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat9XCm3w-ByvzuLy2fa.woff +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat9uCm3w-5TKCIs6EEw.woff +0 -0
- package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat_XDW3w-r2swRDGfn2.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAC5thTQ-ldB60l5U8r.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAIpthTQ-wbFKGFDrgo.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAIpxhTQ-LLUBv5jskj.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwARZthTQ-F71RdTRbNg.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwA_JxhTQ-6nh65gZkc0.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAfJthTQ-aMoWEJLmTt.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAkJxhTQ-WMBvmLOgKm.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAop1hTQ-utGC2hnWq2.woff +0 -0
- package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAopxhTQ-YpyTieVa5B.woff +0 -0
- package/dist/client/devtools/_nuxt/Bj9hdafK.js +0 -1
- package/dist/client/devtools/_nuxt/DM3_wAgz.js +0 -62
- package/dist/client/devtools/_nuxt/builds/latest.json +0 -1
- package/dist/client/devtools/_nuxt/builds/meta/e6b425f7-b919-4014-915b-0ea07c316790.json +0 -1
- package/dist/client/devtools/_nuxt/entry.DaJP-ZMB.css +0 -24
- package/dist/client/devtools/_nuxt/error-404.B0Nmv3fV.css +0 -1
- package/dist/client/devtools/_nuxt/error-500.C8fgTxVz.css +0 -1
- package/dist/client/devtools/_nuxt/hKiujHsR.js +0 -1
- package/dist/client/devtools/favicon.svg +0 -1
- package/dist/client/devtools/index.html +0 -1
- package/dist/devtools/runtime/DevtoolsRenderer.vue +0 -53
- package/dist/devtools/runtime/examples/AvatarGroupExample.vue +0 -7
- package/dist/devtools/runtime/examples/ButtonGroupExample.vue +0 -8
- package/dist/devtools/runtime/examples/CardExample.vue +0 -13
- package/dist/devtools/runtime/examples/CarouselExample.vue +0 -13
- package/dist/devtools/runtime/examples/ChipExample.vue +0 -5
- package/dist/devtools/runtime/examples/CollapsibleExample.vue +0 -8
- package/dist/devtools/runtime/examples/CommandPaletteExample.vue +0 -29
- package/dist/devtools/runtime/examples/ContainerExample.vue +0 -5
- package/dist/devtools/runtime/examples/ContextMenuExample.vue +0 -5
- package/dist/devtools/runtime/examples/DrawerExample.vue +0 -8
- package/dist/devtools/runtime/examples/DropdownMenuExample.vue +0 -5
- package/dist/devtools/runtime/examples/FormExample.vue +0 -30
- package/dist/devtools/runtime/examples/FormFieldExample.vue +0 -5
- package/dist/devtools/runtime/examples/LinkExample.vue +0 -5
- package/dist/devtools/runtime/examples/ModalExample.vue +0 -8
- package/dist/devtools/runtime/examples/PopoverExample.vue +0 -8
- package/dist/devtools/runtime/examples/SkeletonExample.vue +0 -3
- package/dist/devtools/runtime/examples/SlideoverExample.vue +0 -8
- package/dist/devtools/runtime/examples/ToasterExample.vue +0 -11
- package/dist/devtools/runtime/examples/TooltipExample.vue +0 -5
- package/dist/runtime/components/ModalProvider.vue +0 -12
- package/dist/runtime/components/SlideoverProvider.vue +0 -12
- package/dist/runtime/composables/extendDevtoolsMeta.d.ts +0 -7
- package/dist/runtime/composables/extendDevtoolsMeta.js +0 -2
- package/dist/runtime/composables/useModal.d.ts +0 -17
- package/dist/runtime/composables/useModal.js +0 -46
- package/dist/runtime/composables/useSlideover.d.ts +0 -17
- package/dist/runtime/composables/useSlideover.js +0 -46
- package/dist/runtime/plugins/modal.d.ts +0 -2
- package/dist/runtime/plugins/modal.js +0 -10
- package/dist/runtime/plugins/slideover.d.ts +0 -2
- package/dist/runtime/plugins/slideover.js +0 -10
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
3
|
import type { AppConfig } from '@nuxt/schema'
|
|
4
4
|
import _appConfig from '#build/app.config'
|
|
5
5
|
import theme from '#build/ui/form-field'
|
|
6
|
-
import {
|
|
6
|
+
import { tv } from '../utils/tv'
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const appConfigFormField = _appConfig as AppConfig & { ui: { formField: Partial<typeof theme> } }
|
|
9
9
|
|
|
10
|
-
const formField = tv({ extend: tv(theme), ...(
|
|
10
|
+
const formField = tv({ extend: tv(theme), ...(appConfigFormField.ui?.formField || {}) })
|
|
11
11
|
|
|
12
12
|
type FormFieldVariants = VariantProps<typeof formField>
|
|
13
13
|
|
|
14
14
|
export interface FormFieldProps {
|
|
15
|
+
/**
|
|
16
|
+
* The element or component this component should render as.
|
|
17
|
+
* @defaultValue 'div'
|
|
18
|
+
*/
|
|
19
|
+
as?: any
|
|
20
|
+
/** The name of the FormField. Also used to match form errors. */
|
|
15
21
|
name?: string
|
|
22
|
+
/** A regular expression to match form error names. */
|
|
23
|
+
errorPattern?: RegExp
|
|
16
24
|
label?: string
|
|
17
25
|
description?: string
|
|
18
26
|
help?: string
|
|
@@ -34,13 +42,11 @@ export interface FormFieldSlots {
|
|
|
34
42
|
error(props: { error?: string | boolean }): any
|
|
35
43
|
default(props: { error?: string | boolean }): any
|
|
36
44
|
}
|
|
37
|
-
|
|
38
|
-
extendDevtoolsMeta({ example: 'FormFieldExample', defaultProps: { label: 'Label' } })
|
|
39
45
|
</script>
|
|
40
46
|
|
|
41
47
|
<script setup lang="ts">
|
|
42
48
|
import { computed, ref, inject, provide, type Ref, useId } from 'vue'
|
|
43
|
-
import { Label } from '
|
|
49
|
+
import { Primitive, Label } from 'reka-ui'
|
|
44
50
|
import { formFieldInjectionKey, inputIdInjectionKey } from '../composables/useFormField'
|
|
45
51
|
import type { FormError, FormFieldInjectedOptions } from '../types/form'
|
|
46
52
|
|
|
@@ -54,9 +60,12 @@ const ui = computed(() => formField({
|
|
|
54
60
|
|
|
55
61
|
const formErrors = inject<Ref<FormError[]> | null>('form-errors', null)
|
|
56
62
|
|
|
57
|
-
const error = computed(() => props.error || formErrors?.value?.find(error => error.name === props.name)?.message)
|
|
63
|
+
const error = computed(() => props.error || formErrors?.value?.find(error => error.name === props.name || (props.errorPattern && error.name.match(props.errorPattern)))?.message)
|
|
58
64
|
|
|
59
65
|
const id = ref(useId())
|
|
66
|
+
// Copies id's initial value to bind aria-attributes such as aria-describedby.
|
|
67
|
+
// This is required for the RadioGroup component which unsets the id value.
|
|
68
|
+
const ariaId = id.value
|
|
60
69
|
|
|
61
70
|
provide(inputIdInjectionKey, id)
|
|
62
71
|
|
|
@@ -65,12 +74,16 @@ provide(formFieldInjectionKey, computed(() => ({
|
|
|
65
74
|
name: props.name,
|
|
66
75
|
size: props.size,
|
|
67
76
|
eagerValidation: props.eagerValidation,
|
|
68
|
-
validateOnInputDelay: props.validateOnInputDelay
|
|
77
|
+
validateOnInputDelay: props.validateOnInputDelay,
|
|
78
|
+
errorPattern: props.errorPattern,
|
|
79
|
+
hint: props.hint,
|
|
80
|
+
description: props.description,
|
|
81
|
+
ariaId
|
|
69
82
|
}) as FormFieldInjectedOptions<FormFieldProps>))
|
|
70
83
|
</script>
|
|
71
84
|
|
|
72
85
|
<template>
|
|
73
|
-
<
|
|
86
|
+
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
|
74
87
|
<div :class="ui.wrapper({ class: props.ui?.wrapper })">
|
|
75
88
|
<div v-if="label || !!slots.label" :class="ui.labelWrapper({ class: props.ui?.labelWrapper })">
|
|
76
89
|
<Label :for="id" :class="ui.label({ class: props.ui?.label })">
|
|
@@ -78,24 +91,24 @@ provide(formFieldInjectionKey, computed(() => ({
|
|
|
78
91
|
{{ label }}
|
|
79
92
|
</slot>
|
|
80
93
|
</Label>
|
|
81
|
-
<span v-if="hint || !!slots.hint" :class="ui.hint({ class: props.ui?.hint })">
|
|
94
|
+
<span v-if="hint || !!slots.hint" :id="`${ariaId}-hint`" :class="ui.hint({ class: props.ui?.hint })">
|
|
82
95
|
<slot name="hint" :hint="hint">
|
|
83
96
|
{{ hint }}
|
|
84
97
|
</slot>
|
|
85
98
|
</span>
|
|
86
99
|
</div>
|
|
87
100
|
|
|
88
|
-
<p v-if="description || !!slots.description" :class="ui.description({ class: props.ui?.description })">
|
|
101
|
+
<p v-if="description || !!slots.description" :id="`${ariaId}-description`" :class="ui.description({ class: props.ui?.description })">
|
|
89
102
|
<slot name="description" :description="description">
|
|
90
103
|
{{ description }}
|
|
91
104
|
</slot>
|
|
92
105
|
</p>
|
|
93
106
|
</div>
|
|
94
107
|
|
|
95
|
-
<div :class="[label && ui.container({ class: props.ui?.container })]">
|
|
108
|
+
<div :class="[(label || !!slots.label || description || !!slots.description) && ui.container({ class: props.ui?.container })]">
|
|
96
109
|
<slot :error="error" />
|
|
97
110
|
|
|
98
|
-
<p v-if="(typeof error === 'string' && error) || !!slots.error" :class="ui.error({ class: props.ui?.error })">
|
|
111
|
+
<p v-if="(typeof error === 'string' && error) || !!slots.error" :id="`${ariaId}-error`" :class="ui.error({ class: props.ui?.error })">
|
|
99
112
|
<slot name="error" :error="error">
|
|
100
113
|
{{ error }}
|
|
101
114
|
</slot>
|
|
@@ -106,5 +119,5 @@ provide(formFieldInjectionKey, computed(() => ({
|
|
|
106
119
|
</slot>
|
|
107
120
|
</p>
|
|
108
121
|
</div>
|
|
109
|
-
</
|
|
122
|
+
</Primitive>
|
|
110
123
|
</template>
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { InputHTMLAttributes } from 'vue'
|
|
3
|
-
import {
|
|
3
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
4
4
|
import type { AppConfig } from '@nuxt/schema'
|
|
5
5
|
import _appConfig from '#build/app.config'
|
|
6
6
|
import theme from '#build/ui/input'
|
|
7
7
|
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
|
|
8
|
+
import { tv } from '../utils/tv'
|
|
8
9
|
import type { AvatarProps } from '../types'
|
|
9
10
|
import type { PartialString } from '../types/utils'
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
+
const appConfigInput = _appConfig as AppConfig & { ui: { input: Partial<typeof theme> } }
|
|
12
13
|
|
|
13
|
-
const input = tv({ extend: tv(theme), ...(
|
|
14
|
+
const input = tv({ extend: tv(theme), ...(appConfigInput.ui?.input || {}) })
|
|
14
15
|
|
|
15
16
|
type InputVariants = VariantProps<typeof input>
|
|
16
17
|
|
|
17
18
|
export interface InputProps extends UseComponentIconsProps {
|
|
19
|
+
/**
|
|
20
|
+
* The element or component this component should render as.
|
|
21
|
+
* @defaultValue 'div'
|
|
22
|
+
*/
|
|
23
|
+
as?: any
|
|
18
24
|
id?: string
|
|
19
25
|
name?: string
|
|
20
26
|
type?: InputHTMLAttributes['type']
|
|
@@ -49,6 +55,7 @@ export interface InputSlots {
|
|
|
49
55
|
|
|
50
56
|
<script setup lang="ts">
|
|
51
57
|
import { ref, computed, onMounted } from 'vue'
|
|
58
|
+
import { Primitive } from 'reka-ui'
|
|
52
59
|
import { useButtonGroup } from '../composables/useButtonGroup'
|
|
53
60
|
import { useComponentIcons } from '../composables/useComponentIcons'
|
|
54
61
|
import { useFormField } from '../composables/useFormField'
|
|
@@ -68,7 +75,7 @@ const slots = defineSlots<InputSlots>()
|
|
|
68
75
|
|
|
69
76
|
const [modelValue, modelModifiers] = defineModel<string | number>()
|
|
70
77
|
|
|
71
|
-
const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
|
|
78
|
+
const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, emitFormFocus, ariaAttrs } = useFormField<InputProps>(props, { deferInputValidation: true })
|
|
72
79
|
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
|
73
80
|
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props)
|
|
74
81
|
|
|
@@ -147,7 +154,7 @@ onMounted(() => {
|
|
|
147
154
|
</script>
|
|
148
155
|
|
|
149
156
|
<template>
|
|
150
|
-
<
|
|
157
|
+
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
|
151
158
|
<input
|
|
152
159
|
:id="id"
|
|
153
160
|
ref="inputRef"
|
|
@@ -159,10 +166,11 @@ onMounted(() => {
|
|
|
159
166
|
:disabled="disabled"
|
|
160
167
|
:required="required"
|
|
161
168
|
:autocomplete="autocomplete"
|
|
162
|
-
v-bind="
|
|
169
|
+
v-bind="{ ...$attrs, ...ariaAttrs }"
|
|
163
170
|
@input="onInput"
|
|
164
171
|
@blur="onBlur"
|
|
165
172
|
@change="onChange"
|
|
173
|
+
@focus="emitFormFocus"
|
|
166
174
|
>
|
|
167
175
|
|
|
168
176
|
<slot />
|
|
@@ -179,5 +187,5 @@ onMounted(() => {
|
|
|
179
187
|
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
|
180
188
|
</slot>
|
|
181
189
|
</span>
|
|
182
|
-
</
|
|
190
|
+
</Primitive>
|
|
183
191
|
</template>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { InputHTMLAttributes } from 'vue'
|
|
3
|
-
import {
|
|
4
|
-
import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, ComboboxArrowProps } from '
|
|
3
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
4
|
+
import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, ComboboxArrowProps, AcceptableValue } from 'reka-ui'
|
|
5
5
|
import type { AppConfig } from '@nuxt/schema'
|
|
6
6
|
import _appConfig from '#build/app.config'
|
|
7
7
|
import theme from '#build/ui/input-menu'
|
|
8
8
|
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
|
|
9
|
-
import {
|
|
9
|
+
import { tv } from '../utils/tv'
|
|
10
10
|
import type { AvatarProps, ChipProps, InputProps } from '../types'
|
|
11
|
-
import type {
|
|
11
|
+
import type { PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const appConfigInputMenu = _appConfig as AppConfig & { ui: { inputMenu: Partial<typeof theme> } }
|
|
14
14
|
|
|
15
|
-
const inputMenu = tv({ extend: tv(theme), ...(
|
|
15
|
+
const inputMenu = tv({ extend: tv(theme), ...(appConfigInputMenu.ui?.inputMenu || {}) })
|
|
16
16
|
|
|
17
17
|
export interface InputMenuItem {
|
|
18
18
|
label?: string
|
|
@@ -30,7 +30,7 @@ export interface InputMenuItem {
|
|
|
30
30
|
|
|
31
31
|
type InputMenuVariants = VariantProps<typeof inputMenu>
|
|
32
32
|
|
|
33
|
-
export interface InputMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends MaybeArrayOfArray<InputMenuItem | AcceptableValue> = MaybeArrayOfArray<InputMenuItem | AcceptableValue>, V extends SelectItemKey<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, '
|
|
33
|
+
export interface InputMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends MaybeArrayOfArray<InputMenuItem | AcceptableValue | boolean> = MaybeArrayOfArray<InputMenuItem | AcceptableValue | boolean>, V extends SelectItemKey<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'open' | 'defaultOpen' | 'disabled' | 'name' | 'resetSearchTermOnBlur' | 'highlightOnHover'>, UseComponentIconsProps {
|
|
34
34
|
/**
|
|
35
35
|
* The element or component this component should render as.
|
|
36
36
|
* @defaultValue 'div'
|
|
@@ -64,7 +64,7 @@ export interface InputMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends Ma
|
|
|
64
64
|
deleteIcon?: string
|
|
65
65
|
/**
|
|
66
66
|
* The content of the menu.
|
|
67
|
-
* @defaultValue { side: 'bottom', sideOffset: 8, position: 'popper' }
|
|
67
|
+
* @defaultValue { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }
|
|
68
68
|
*/
|
|
69
69
|
content?: Omit<ComboboxContentProps, 'as' | 'asChild' | 'forceMount'>
|
|
70
70
|
/**
|
|
@@ -77,12 +77,6 @@ export interface InputMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends Ma
|
|
|
77
77
|
* @defaultValue true
|
|
78
78
|
*/
|
|
79
79
|
portal?: boolean
|
|
80
|
-
/**
|
|
81
|
-
* Whether to filter items or not, can be an array of fields to filter.
|
|
82
|
-
* When `false`, items will not be filtered which is useful for custom filtering.
|
|
83
|
-
* @defaultValue ['label']
|
|
84
|
-
*/
|
|
85
|
-
filter?: boolean | string[]
|
|
86
80
|
/**
|
|
87
81
|
* When `items` is an array of objects, select the field to use as the value instead of the object itself.
|
|
88
82
|
* @defaultValue undefined
|
|
@@ -92,29 +86,47 @@ export interface InputMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends Ma
|
|
|
92
86
|
* When `items` is an array of objects, select the field to use as the label.
|
|
93
87
|
* @defaultValue 'label'
|
|
94
88
|
*/
|
|
95
|
-
labelKey?:
|
|
89
|
+
labelKey?: V
|
|
96
90
|
items?: I
|
|
91
|
+
/** The value of the InputMenu when initially rendered. Use when you do not need to control the state of the InputMenu. */
|
|
92
|
+
defaultValue?: SelectModelValue<T, V, M>
|
|
93
|
+
/** The controlled value of the InputMenu. Can be binded-with with `v-model`. */
|
|
94
|
+
modelValue?: SelectModelValue<T, V, M>
|
|
95
|
+
/** Whether multiple options can be selected or not. */
|
|
96
|
+
multiple?: M & boolean
|
|
97
97
|
/** Highlight the ring color like a focus state. */
|
|
98
98
|
highlight?: boolean
|
|
99
|
+
/**
|
|
100
|
+
* Determines if custom user input that does not exist in options can be added.
|
|
101
|
+
* @defaultValue false
|
|
102
|
+
*/
|
|
103
|
+
createItem?: boolean | 'always' | { position?: 'top' | 'bottom', when?: 'empty' | 'always' }
|
|
104
|
+
/**
|
|
105
|
+
* Fields to filter items by.
|
|
106
|
+
* @defaultValue [labelKey]
|
|
107
|
+
*/
|
|
108
|
+
filterFields?: string[]
|
|
109
|
+
/**
|
|
110
|
+
* When `true`, disable the default filters, useful for custom filtering (useAsyncData, useFetch, etc.).
|
|
111
|
+
* @defaultValue false
|
|
112
|
+
*/
|
|
113
|
+
ignoreFilter?: boolean
|
|
99
114
|
class?: any
|
|
100
115
|
ui?: PartialString<typeof inputMenu.slots>
|
|
101
|
-
/** The controlled value of the Combobox. Can be binded-with with `v-model`. */
|
|
102
|
-
modelValue?: SelectModelValue<T, V, M>
|
|
103
|
-
/** Whether multiple options can be selected or not. */
|
|
104
|
-
multiple?: M
|
|
105
116
|
}
|
|
106
117
|
|
|
107
118
|
export type InputMenuEmits<T, V, M extends boolean> = Omit<ComboboxRootEmits<T>, 'update:modelValue'> & {
|
|
108
119
|
change: [payload: Event]
|
|
109
120
|
blur: [payload: FocusEvent]
|
|
110
121
|
focus: [payload: FocusEvent]
|
|
122
|
+
create: [item: string]
|
|
111
123
|
} & SelectModelValueEmits<T, V, M>
|
|
112
124
|
|
|
113
125
|
type SlotProps<T> = (props: { item: T, index: number }) => any
|
|
114
126
|
|
|
115
|
-
export interface InputMenuSlots<T> {
|
|
116
|
-
'leading'(props: { modelValue: T, open: boolean, ui: any }): any
|
|
117
|
-
'trailing'(props: { modelValue: T, open: boolean, ui: any }): any
|
|
127
|
+
export interface InputMenuSlots<T, M extends boolean> {
|
|
128
|
+
'leading'(props: { modelValue?: M extends true ? T[] : T, open: boolean, ui: any }): any
|
|
129
|
+
'trailing'(props: { modelValue?: M extends true ? T[] : T, open: boolean, ui: any }): any
|
|
118
130
|
'empty'(props: { searchTerm?: string }): any
|
|
119
131
|
'item': SlotProps<T>
|
|
120
132
|
'item-leading': SlotProps<T>
|
|
@@ -122,22 +134,22 @@ export interface InputMenuSlots<T> {
|
|
|
122
134
|
'item-trailing': SlotProps<T>
|
|
123
135
|
'tags-item-text': SlotProps<T>
|
|
124
136
|
'tags-item-delete': SlotProps<T>
|
|
137
|
+
'create-item-label'(props: { item: string }): any
|
|
125
138
|
}
|
|
126
|
-
|
|
127
|
-
extendDevtoolsMeta({ defaultProps: { items: ['Option 1', 'Option 2', 'Option 3'] } })
|
|
128
139
|
</script>
|
|
129
140
|
|
|
130
|
-
<script setup lang="ts" generic="T extends MaybeArrayOfArrayItem<I>, I extends MaybeArrayOfArray<InputMenuItem | AcceptableValue> = MaybeArrayOfArray<InputMenuItem | AcceptableValue>, V extends SelectItemKey<T> | undefined = undefined, M extends boolean = false">
|
|
131
|
-
import { computed, ref, toRef, onMounted } from 'vue'
|
|
132
|
-
import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, useForwardPropsEmits } from '
|
|
141
|
+
<script setup lang="ts" generic="T extends MaybeArrayOfArrayItem<I>, I extends MaybeArrayOfArray<InputMenuItem | AcceptableValue | boolean> = MaybeArrayOfArray<InputMenuItem | AcceptableValue | boolean>, V extends SelectItemKey<T> | undefined = undefined, M extends boolean = false">
|
|
142
|
+
import { computed, ref, toRef, onMounted, toRaw } from 'vue'
|
|
143
|
+
import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, useForwardPropsEmits, useFilter } from 'reka-ui'
|
|
133
144
|
import { defu } from 'defu'
|
|
134
|
-
import
|
|
135
|
-
import { reactivePick } from '@vueuse/core'
|
|
145
|
+
import { isEqual } from 'ohash'
|
|
146
|
+
import { reactivePick, createReusableTemplate } from '@vueuse/core'
|
|
136
147
|
import { useAppConfig } from '#imports'
|
|
137
148
|
import { useButtonGroup } from '../composables/useButtonGroup'
|
|
138
149
|
import { useComponentIcons } from '../composables/useComponentIcons'
|
|
139
150
|
import { useFormField } from '../composables/useFormField'
|
|
140
|
-
import {
|
|
151
|
+
import { useLocale } from '../composables/useLocale'
|
|
152
|
+
import { get, compare } from '../utils'
|
|
141
153
|
import UIcon from './Icon.vue'
|
|
142
154
|
import UAvatar from './Avatar.vue'
|
|
143
155
|
import UChip from './Chip.vue'
|
|
@@ -148,25 +160,29 @@ const props = withDefaults(defineProps<InputMenuProps<T, I, V, M>>(), {
|
|
|
148
160
|
type: 'text',
|
|
149
161
|
autofocusDelay: 0,
|
|
150
162
|
portal: true,
|
|
151
|
-
|
|
152
|
-
labelKey: 'label' as keyof T
|
|
163
|
+
labelKey: 'label' as never
|
|
153
164
|
})
|
|
154
165
|
const emits = defineEmits<InputMenuEmits<T, V, M>>()
|
|
155
|
-
const slots = defineSlots<InputMenuSlots<T>>()
|
|
166
|
+
const slots = defineSlots<InputMenuSlots<T, M>>()
|
|
156
167
|
|
|
157
168
|
const searchTerm = defineModel<string>('searchTerm', { default: '' })
|
|
158
169
|
|
|
170
|
+
const { t } = useLocale()
|
|
159
171
|
const appConfig = useAppConfig()
|
|
160
|
-
const
|
|
161
|
-
|
|
172
|
+
const { contains } = useFilter({ sensitivity: 'base' })
|
|
173
|
+
|
|
174
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'multiple', 'resetSearchTermOnBlur', 'highlightOnHover', 'ignoreFilter'), emits)
|
|
175
|
+
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
|
|
162
176
|
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
|
163
177
|
|
|
164
|
-
const { emitFormBlur, emitFormChange, emitFormInput, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
|
|
178
|
+
const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
|
|
165
179
|
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
|
166
180
|
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
|
|
167
181
|
|
|
168
182
|
const inputSize = computed(() => buttonGroupSize.value || formGroupSize.value)
|
|
169
183
|
|
|
184
|
+
const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate()
|
|
185
|
+
|
|
170
186
|
const ui = computed(() => inputMenu({
|
|
171
187
|
color: color.value,
|
|
172
188
|
variant: props.variant,
|
|
@@ -179,36 +195,54 @@ const ui = computed(() => inputMenu({
|
|
|
179
195
|
buttonGroup: orientation.value
|
|
180
196
|
}))
|
|
181
197
|
|
|
182
|
-
function displayValue(value:
|
|
183
|
-
|
|
198
|
+
function displayValue(value: T): string {
|
|
199
|
+
if (!props.valueKey) {
|
|
200
|
+
return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
|
|
201
|
+
}
|
|
184
202
|
|
|
203
|
+
const item = items.value.find(item => compare(typeof item === 'object' ? get(item as Record<string, any>, props.valueKey as string) : item, value))
|
|
185
204
|
return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
|
|
186
205
|
}
|
|
187
206
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
207
|
+
const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0]) ? props.items : [props.items]) as InputMenuItem[][] : [])
|
|
208
|
+
// eslint-disable-next-line vue/no-dupe-keys
|
|
209
|
+
const items = computed(() => groups.value.flatMap(group => group) as T[])
|
|
210
|
+
|
|
211
|
+
const filteredGroups = computed(() => {
|
|
212
|
+
if (props.ignoreFilter || !searchTerm.value) {
|
|
213
|
+
return groups.value
|
|
191
214
|
}
|
|
192
215
|
|
|
193
|
-
const fields = Array.isArray(props.
|
|
194
|
-
const escapedSearchTerm = escapeRegExp(searchTerm)
|
|
216
|
+
const fields = Array.isArray(props.filterFields) ? props.filterFields : [props.labelKey] as string[]
|
|
195
217
|
|
|
196
|
-
return items.filter((item) => {
|
|
218
|
+
return groups.value.map(items => items.filter((item) => {
|
|
197
219
|
if (typeof item !== 'object') {
|
|
198
|
-
return
|
|
220
|
+
return contains(item, searchTerm.value)
|
|
199
221
|
}
|
|
200
222
|
|
|
201
|
-
|
|
202
|
-
|
|
223
|
+
if (item.type && ['label', 'separator'].includes(item.type)) {
|
|
224
|
+
return true
|
|
225
|
+
}
|
|
203
226
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
227
|
+
return fields.some(field => contains(get(item, field), searchTerm.value))
|
|
228
|
+
})).filter(group => group.filter(item => !item.type || !['label', 'separator'].includes(item.type)).length > 0)
|
|
229
|
+
})
|
|
230
|
+
const filteredItems = computed(() => filteredGroups.value.flatMap(group => group) as T[])
|
|
208
231
|
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
232
|
+
const createItem = computed(() => {
|
|
233
|
+
if (!props.createItem || !searchTerm.value) {
|
|
234
|
+
return false
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const newItem = props.valueKey ? { [props.valueKey]: searchTerm.value } as T : searchTerm.value
|
|
238
|
+
|
|
239
|
+
if ((typeof props.createItem === 'object' && props.createItem.when === 'always') || props.createItem === 'always') {
|
|
240
|
+
return !filteredItems.value.find(item => compare(item, newItem, props.valueKey))
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return !filteredItems.value.length
|
|
244
|
+
})
|
|
245
|
+
const createItemPosition = computed(() => typeof props.createItem === 'object' ? props.createItem.position : 'bottom')
|
|
212
246
|
|
|
213
247
|
const inputRef = ref<InstanceType<typeof ComboboxInput> | null>(null)
|
|
214
248
|
|
|
@@ -225,6 +259,9 @@ onMounted(() => {
|
|
|
225
259
|
})
|
|
226
260
|
|
|
227
261
|
function onUpdate(value: any) {
|
|
262
|
+
if (toRaw(props.modelValue) === value) {
|
|
263
|
+
return
|
|
264
|
+
}
|
|
228
265
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
229
266
|
const event = new Event('change', { target: { value } })
|
|
230
267
|
emits('change', event)
|
|
@@ -239,6 +276,7 @@ function onBlur(event: FocusEvent) {
|
|
|
239
276
|
|
|
240
277
|
function onFocus(event: FocusEvent) {
|
|
241
278
|
emits('focus', event)
|
|
279
|
+
emitFormFocus()
|
|
242
280
|
}
|
|
243
281
|
|
|
244
282
|
function onUpdateOpen(value: boolean) {
|
|
@@ -252,23 +290,46 @@ function onUpdateOpen(value: boolean) {
|
|
|
252
290
|
}
|
|
253
291
|
}
|
|
254
292
|
|
|
293
|
+
function onRemoveTag(event: any) {
|
|
294
|
+
if (props.multiple) {
|
|
295
|
+
const modelValue = props.modelValue as SelectModelValue<T, V, true>
|
|
296
|
+
const filteredValue = modelValue.filter(value => !isEqual(value, event))
|
|
297
|
+
emits('update:modelValue', filteredValue as SelectModelValue<T, V, M>)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
255
301
|
defineExpose({
|
|
256
302
|
inputRef
|
|
257
303
|
})
|
|
258
304
|
</script>
|
|
259
305
|
|
|
306
|
+
<!-- eslint-disable vue/no-template-shadow -->
|
|
260
307
|
<template>
|
|
308
|
+
<DefineCreateItemTemplate>
|
|
309
|
+
<ComboboxGroup :class="ui.group({ class: props.ui?.group })">
|
|
310
|
+
<ComboboxItem
|
|
311
|
+
:class="ui.item({ class: props.ui?.item })"
|
|
312
|
+
:value="searchTerm"
|
|
313
|
+
@select.prevent="emits('create', searchTerm)"
|
|
314
|
+
>
|
|
315
|
+
<span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
|
|
316
|
+
<slot name="create-item-label" :item="searchTerm">
|
|
317
|
+
{{ t('inputMenu.create', { label: searchTerm }) }}
|
|
318
|
+
</slot>
|
|
319
|
+
</span>
|
|
320
|
+
</ComboboxItem>
|
|
321
|
+
</ComboboxGroup>
|
|
322
|
+
</DefineCreateItemTemplate>
|
|
323
|
+
|
|
261
324
|
<ComboboxRoot
|
|
262
325
|
:id="id"
|
|
263
326
|
v-slot="{ modelValue, open }"
|
|
264
327
|
v-bind="rootProps"
|
|
265
|
-
v-model:search-term="searchTerm"
|
|
266
328
|
:name="name"
|
|
267
329
|
:disabled="disabled"
|
|
268
|
-
:display-value="displayValue"
|
|
269
|
-
:filter-function="filterFunction"
|
|
270
330
|
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
|
271
331
|
:as-child="!!multiple"
|
|
332
|
+
ignore-filter
|
|
272
333
|
@update:model-value="onUpdate"
|
|
273
334
|
@update:open="onUpdateOpen"
|
|
274
335
|
@keydown.enter="$event.preventDefault()"
|
|
@@ -276,13 +337,14 @@ defineExpose({
|
|
|
276
337
|
<ComboboxAnchor :as-child="!multiple" :class="ui.base({ class: props.ui?.base })">
|
|
277
338
|
<TagsInputRoot
|
|
278
339
|
v-if="multiple"
|
|
279
|
-
v-slot="{ modelValue: tags }
|
|
340
|
+
v-slot="{ modelValue: tags }"
|
|
280
341
|
:model-value="(modelValue as string[])"
|
|
281
342
|
:disabled="disabled"
|
|
282
343
|
delimiter=""
|
|
283
344
|
as-child
|
|
284
345
|
@blur="onBlur"
|
|
285
346
|
@focus="onFocus"
|
|
347
|
+
@remove-tag="onRemoveTag"
|
|
286
348
|
>
|
|
287
349
|
<TagsInputItem v-for="(item, index) in tags" :key="index" :value="(item as string)" :class="ui.tagsItem({ class: props.ui?.tagsItem })">
|
|
288
350
|
<TagsInputItemText :class="ui.tagsItemText({ class: props.ui?.tagsItemText })">
|
|
@@ -298,10 +360,10 @@ defineExpose({
|
|
|
298
360
|
</TagsInputItemDelete>
|
|
299
361
|
</TagsInputItem>
|
|
300
362
|
|
|
301
|
-
<ComboboxInput as-child>
|
|
363
|
+
<ComboboxInput v-model="searchTerm" :display-value="displayValue" as-child>
|
|
302
364
|
<TagsInputInput
|
|
303
365
|
ref="inputRef"
|
|
304
|
-
v-bind="
|
|
366
|
+
v-bind="{ ...$attrs, ...ariaAttrs }"
|
|
305
367
|
:placeholder="placeholder"
|
|
306
368
|
:required="required"
|
|
307
369
|
:class="ui.tagsInput({ class: props.ui?.tagsInput })"
|
|
@@ -313,24 +375,25 @@ defineExpose({
|
|
|
313
375
|
<ComboboxInput
|
|
314
376
|
v-else
|
|
315
377
|
ref="inputRef"
|
|
316
|
-
v-
|
|
378
|
+
v-model="searchTerm"
|
|
379
|
+
:display-value="displayValue"
|
|
380
|
+
v-bind="{ ...$attrs, ...ariaAttrs }"
|
|
317
381
|
:type="type"
|
|
318
382
|
:placeholder="placeholder"
|
|
319
383
|
:required="required"
|
|
320
|
-
:class="ui.base({ class: props.ui?.base })"
|
|
321
384
|
@blur="onBlur"
|
|
322
385
|
@focus="onFocus"
|
|
323
386
|
/>
|
|
324
387
|
|
|
325
388
|
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
|
326
|
-
<slot name="leading" :model-value="(modelValue as T)" :open="open" :ui="ui">
|
|
389
|
+
<slot name="leading" :model-value="(modelValue as M extends true ? T[] : T)" :open="open" :ui="ui">
|
|
327
390
|
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
|
328
391
|
<UAvatar v-else-if="!!avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
|
|
329
392
|
</slot>
|
|
330
393
|
</span>
|
|
331
394
|
|
|
332
395
|
<ComboboxTrigger v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
|
|
333
|
-
<slot name="trailing" :model-value="(modelValue as T)" :open="open" :ui="ui">
|
|
396
|
+
<slot name="trailing" :model-value="(modelValue as M extends true ? T[] : T)" :open="open" :ui="ui">
|
|
334
397
|
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
|
335
398
|
</slot>
|
|
336
399
|
</ComboboxTrigger>
|
|
@@ -340,12 +403,14 @@ defineExpose({
|
|
|
340
403
|
<ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
|
|
341
404
|
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
|
|
342
405
|
<slot name="empty" :search-term="searchTerm">
|
|
343
|
-
{{ searchTerm ?
|
|
406
|
+
{{ searchTerm ? t('inputMenu.noMatch', { searchTerm }) : t('inputMenu.noData') }}
|
|
344
407
|
</slot>
|
|
345
408
|
</ComboboxEmpty>
|
|
346
409
|
|
|
347
410
|
<ComboboxViewport :class="ui.viewport({ class: props.ui?.viewport })">
|
|
348
|
-
<
|
|
411
|
+
<ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'top'" />
|
|
412
|
+
|
|
413
|
+
<ComboboxGroup v-for="(group, groupIndex) in filteredGroups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
|
|
349
414
|
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
|
350
415
|
<ComboboxLabel v-if="item?.type === 'label'" :class="ui.label({ class: props.ui?.label })">
|
|
351
416
|
{{ get(item, props.labelKey as string) }}
|
|
@@ -391,6 +456,8 @@ defineExpose({
|
|
|
391
456
|
</ComboboxItem>
|
|
392
457
|
</template>
|
|
393
458
|
</ComboboxGroup>
|
|
459
|
+
|
|
460
|
+
<ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'bottom'" />
|
|
394
461
|
</ComboboxViewport>
|
|
395
462
|
|
|
396
463
|
<ComboboxArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
|