@nuxt/ui 3.0.0-alpha.0 → 3.0.0-alpha.10
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 +20 -0
- package/.nuxt/ui/alert.ts +242 -0
- package/.nuxt/ui/avatar-group.ts +40 -0
- package/.nuxt/ui/avatar.ts +42 -0
- package/.nuxt/ui/badge.ts +194 -0
- package/.nuxt/ui/breadcrumb.ts +45 -0
- package/.nuxt/ui/button-group.ts +16 -0
- package/.nuxt/ui/button.ts +344 -0
- package/.nuxt/ui/calendar.ts +85 -0
- package/.nuxt/ui/card.ts +8 -0
- package/.nuxt/ui/carousel.ts +41 -0
- package/.nuxt/ui/checkbox.ts +105 -0
- package/.nuxt/ui/chip.ts +67 -0
- package/.nuxt/ui/collapsible.ts +6 -0
- package/.nuxt/ui/color-picker.ts +39 -0
- package/.nuxt/ui/command-palette.ts +50 -0
- package/.nuxt/ui/container.ts +3 -0
- package/.nuxt/ui/context-menu.ts +198 -0
- package/.nuxt/ui/drawer.ts +55 -0
- package/.nuxt/ui/dropdown-menu.ts +199 -0
- package/.nuxt/ui/form-field.ts +40 -0
- package/.nuxt/ui/form.ts +3 -0
- package/.nuxt/ui/index.ts +48 -0
- package/.nuxt/ui/input-menu.ts +410 -0
- package/.nuxt/ui/input-number.ts +204 -0
- package/.nuxt/ui/input.ts +263 -0
- package/.nuxt/ui/kbd.ts +19 -0
- package/.nuxt/ui/link.ts +15 -0
- package/.nuxt/ui/modal.ts +28 -0
- package/.nuxt/ui/navigation-menu.ts +390 -0
- package/.nuxt/ui/pagination.ts +8 -0
- package/.nuxt/ui/pin-input.ts +145 -0
- package/.nuxt/ui/popover.ts +6 -0
- package/.nuxt/ui/progress.ts +258 -0
- package/.nuxt/ui/radio-group.ts +112 -0
- package/.nuxt/ui/select-menu.ts +316 -0
- package/.nuxt/ui/select.ts +315 -0
- package/.nuxt/ui/separator.ts +143 -0
- package/.nuxt/ui/skeleton.ts +3 -0
- package/.nuxt/ui/slideover.ts +63 -0
- package/.nuxt/ui/slider.ts +148 -0
- package/.nuxt/ui/stepper.ts +180 -0
- package/.nuxt/ui/switch.ts +113 -0
- package/.nuxt/ui/table.ts +129 -0
- package/.nuxt/ui/tabs.ts +227 -0
- package/.nuxt/ui/textarea.ts +263 -0
- package/.nuxt/ui/toast.ts +66 -0
- package/.nuxt/ui/toaster.ts +75 -0
- package/.nuxt/ui/tooltip.ts +9 -0
- package/README.md +75 -54
- package/cli/commands/{init.mjs → make/component.mjs} +5 -5
- package/cli/commands/make/index.mjs +14 -0
- package/cli/commands/make/locale.mjs +64 -0
- package/cli/index.mjs +2 -2
- package/cli/templates.mjs +52 -7
- package/cli/utils.mjs +14 -0
- package/dist/chunks/component-meta.cjs +82802 -0
- package/dist/chunks/component-meta.mjs +82800 -0
- package/dist/client/devtools/200.html +1 -0
- package/dist/client/devtools/404.html +1 -0
- 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/B1fTd_Rf.js +1 -0
- package/dist/client/devtools/_nuxt/CSUxkedg.js +1 -0
- package/dist/client/devtools/_nuxt/CbRTGpb7.js +1 -0
- package/dist/client/devtools/_nuxt/YQTlxbcT.js +53 -0
- package/dist/client/devtools/_nuxt/builds/latest.json +1 -0
- package/dist/client/devtools/_nuxt/builds/meta/b3465abc-0a92-4ee7-ba6b-e5174891fcc0.json +1 -0
- package/dist/client/devtools/_nuxt/entry.DXXceQev.css +1 -0
- package/dist/client/devtools/_nuxt/error-404.BJpkZFyY.css +1 -0
- package/dist/client/devtools/_nuxt/error-500.D3i9VDlt.css +1 -0
- package/dist/client/devtools/favicon.svg +1 -0
- package/dist/client/devtools/index.html +1 -0
- package/dist/devtools/runtime/DevtoolsRenderer.vue +54 -0
- package/dist/devtools/runtime/examples/AvatarGroupExample.vue +7 -0
- package/dist/devtools/runtime/examples/ButtonGroupExample.vue +8 -0
- package/dist/devtools/runtime/examples/CardExample.vue +13 -0
- package/dist/devtools/runtime/examples/CarouselExample.vue +13 -0
- package/dist/devtools/runtime/examples/ChipExample.vue +5 -0
- package/dist/devtools/runtime/examples/CollapsibleExample.vue +8 -0
- package/dist/devtools/runtime/examples/CommandPaletteExample.vue +29 -0
- package/dist/devtools/runtime/examples/ContainerExample.vue +5 -0
- package/dist/devtools/runtime/examples/ContextMenuExample.vue +5 -0
- package/dist/devtools/runtime/examples/DrawerExample.vue +8 -0
- package/dist/devtools/runtime/examples/DropdownMenuExample.vue +5 -0
- package/dist/devtools/runtime/examples/FormExample.vue +30 -0
- package/dist/devtools/runtime/examples/FormFieldExample.vue +5 -0
- package/dist/devtools/runtime/examples/LinkExample.vue +5 -0
- package/dist/devtools/runtime/examples/ModalExample.vue +8 -0
- package/dist/devtools/runtime/examples/PopoverExample.vue +8 -0
- package/dist/devtools/runtime/examples/SkeletonExample.vue +3 -0
- package/dist/devtools/runtime/examples/SlideoverExample.vue +8 -0
- package/dist/devtools/runtime/examples/StepperExample.vue +44 -0
- package/dist/devtools/runtime/examples/ToasterExample.vue +11 -0
- package/dist/devtools/runtime/examples/TooltipExample.vue +5 -0
- package/dist/module.cjs +223 -4
- package/dist/module.d.cts +54 -0
- package/dist/module.d.mts +38 -7
- package/dist/module.d.ts +38 -7
- package/dist/module.json +4 -3
- package/dist/module.mjs +180 -2617
- package/dist/runtime/components/Accordion.vue +95 -11
- package/dist/runtime/components/Alert.vue +69 -10
- package/dist/runtime/components/App.vue +28 -5
- package/dist/runtime/components/Avatar.vue +57 -12
- package/dist/runtime/components/AvatarGroup.vue +34 -7
- package/dist/runtime/components/Badge.vue +61 -9
- package/dist/runtime/components/Breadcrumb.vue +93 -16
- package/dist/runtime/components/Button.vue +78 -12
- package/dist/runtime/components/ButtonGroup.vue +35 -8
- package/dist/runtime/components/Calendar.vue +190 -0
- package/dist/runtime/components/Card.vue +29 -7
- package/dist/runtime/components/Carousel.vue +322 -0
- package/dist/runtime/components/Checkbox.vue +64 -30
- package/dist/runtime/components/Chip.vue +48 -8
- package/dist/runtime/components/Collapsible.vue +32 -8
- package/dist/runtime/components/ColorPicker.vue +265 -0
- package/dist/runtime/components/CommandPalette.vue +207 -88
- package/dist/runtime/components/Container.vue +26 -7
- package/dist/runtime/components/ContextMenu.vue +150 -11
- package/dist/runtime/components/ContextMenuContent.vue +63 -19
- package/dist/runtime/components/Drawer.vue +68 -15
- package/dist/runtime/components/DropdownMenu.vue +147 -12
- package/dist/runtime/components/DropdownMenuContent.vue +69 -19
- package/dist/runtime/components/Form.vue +80 -42
- package/dist/runtime/components/FormField.vue +58 -21
- package/dist/runtime/components/Icon.vue +13 -3
- package/dist/runtime/components/Input.vue +61 -12
- package/dist/runtime/components/InputMenu.vue +247 -53
- package/dist/runtime/components/InputNumber.vue +192 -0
- package/dist/runtime/components/Kbd.vue +31 -7
- package/dist/runtime/components/Link.vue +148 -21
- package/dist/runtime/components/LinkBase.vue +21 -8
- package/dist/runtime/components/Modal.vue +90 -15
- package/dist/runtime/components/NavigationMenu.vue +234 -69
- package/dist/runtime/components/Pagination.vue +124 -15
- package/dist/runtime/components/PinInput.vue +96 -0
- package/dist/runtime/components/Popover.vue +66 -11
- package/dist/runtime/components/Progress.vue +67 -12
- package/dist/runtime/components/RadioGroup.vue +78 -9
- package/dist/runtime/components/Select.vue +155 -26
- package/dist/runtime/components/SelectMenu.vue +245 -63
- package/dist/runtime/components/Separator.vue +42 -7
- package/dist/runtime/components/Skeleton.vue +22 -7
- package/dist/runtime/components/Slideover.vue +88 -15
- package/dist/runtime/components/Slider.vue +37 -7
- package/dist/runtime/components/Stepper.vue +171 -0
- package/dist/runtime/components/Switch.vue +58 -14
- package/dist/runtime/components/Table.vue +262 -0
- package/dist/runtime/components/Tabs.vue +97 -17
- package/dist/runtime/components/Textarea.vue +55 -9
- package/dist/runtime/components/Toast.vue +66 -9
- package/dist/runtime/components/Toaster.vue +57 -21
- package/dist/runtime/components/Tooltip.vue +49 -10
- 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 -8
- package/dist/runtime/composables/extendDevtoolsMeta.d.ts +7 -0
- package/dist/runtime/composables/extendDevtoolsMeta.js +2 -0
- package/dist/runtime/composables/useAvatarGroup.d.ts +2 -2
- package/dist/runtime/composables/useButtonGroup.d.ts +5 -5
- package/dist/runtime/composables/useComponentIcons.d.ts +3 -0
- package/dist/runtime/composables/useFormField.d.ts +13 -6
- package/dist/runtime/composables/useFormField.js +12 -7
- package/dist/runtime/composables/useKbd.d.ts +10 -3
- package/dist/runtime/composables/useKbd.js +14 -8
- package/dist/runtime/composables/useLocale.d.ts +4 -0
- package/dist/runtime/composables/useLocale.js +10 -0
- package/dist/runtime/composables/useModal.d.ts +2 -2
- package/dist/runtime/composables/useSlideover.d.ts +2 -2
- package/dist/runtime/composables/useToast.d.ts +2 -2
- package/dist/runtime/index.css +1 -0
- package/dist/runtime/keyframes.css +1 -0
- package/dist/runtime/locale/ar.d.ts +2 -0
- package/dist/runtime/locale/ar.js +53 -0
- package/dist/runtime/locale/cs.d.ts +2 -0
- package/dist/runtime/locale/cs.js +52 -0
- package/dist/runtime/locale/de.d.ts +2 -0
- package/dist/runtime/locale/de.js +52 -0
- package/dist/runtime/locale/en.d.ts +2 -0
- package/dist/runtime/locale/en.js +52 -0
- package/dist/runtime/locale/es.d.ts +2 -0
- package/dist/runtime/locale/es.js +52 -0
- package/dist/runtime/locale/fa_ir.d.ts +2 -0
- package/dist/runtime/locale/fa_ir.js +53 -0
- package/dist/runtime/locale/fr.d.ts +2 -0
- package/dist/runtime/locale/fr.js +52 -0
- package/dist/runtime/locale/index.d.ts +19 -0
- package/dist/runtime/locale/index.js +19 -0
- package/dist/runtime/locale/it.d.ts +2 -0
- package/dist/runtime/locale/it.js +52 -0
- package/dist/runtime/locale/ja.d.ts +2 -0
- package/dist/runtime/locale/ja.js +52 -0
- package/dist/runtime/locale/ko.d.ts +2 -0
- package/dist/runtime/locale/ko.js +52 -0
- package/dist/runtime/locale/nl.d.ts +2 -0
- package/dist/runtime/locale/nl.js +52 -0
- package/dist/runtime/locale/pl.d.ts +2 -0
- package/dist/runtime/locale/pl.js +52 -0
- package/dist/runtime/locale/pt.d.ts +2 -0
- package/dist/runtime/locale/pt.js +52 -0
- package/dist/runtime/locale/pt_br.d.ts +2 -0
- package/dist/runtime/locale/pt_br.js +52 -0
- package/dist/runtime/locale/ru.d.ts +2 -0
- package/dist/runtime/locale/ru.js +52 -0
- package/dist/runtime/locale/sk.d.ts +2 -0
- package/dist/runtime/locale/sk.js +52 -0
- package/dist/runtime/locale/tr.d.ts +2 -0
- package/dist/runtime/locale/tr.js +52 -0
- package/dist/runtime/locale/zh_hans.d.ts +2 -0
- package/dist/runtime/locale/zh_hans.js +52 -0
- package/dist/runtime/locale/zh_hant.d.ts +2 -0
- package/dist/runtime/locale/zh_hant.js +52 -0
- package/dist/runtime/plugins/colors.d.ts +2 -0
- package/dist/runtime/plugins/colors.js +12 -8
- package/dist/runtime/plugins/modal.d.ts +2 -0
- package/dist/runtime/plugins/slideover.d.ts +2 -0
- package/dist/runtime/types/form.d.ts +10 -4
- package/dist/runtime/types/index.d.ts +50 -42
- package/dist/runtime/types/index.js +8 -0
- package/dist/runtime/types/locale.d.ts +54 -0
- package/dist/runtime/types/utils.d.ts +8 -3
- package/dist/runtime/utils/form.d.ts +7 -5
- package/dist/runtime/utils/form.js +117 -28
- package/dist/runtime/utils/index.d.ts +2 -1
- package/dist/runtime/utils/index.js +16 -0
- package/dist/runtime/utils/link.d.ts +25 -55
- package/dist/runtime/utils/link.js +1 -1
- package/dist/runtime/utils/locale.d.ts +15 -0
- package/dist/runtime/utils/locale.js +25 -0
- package/dist/runtime/vue/components/Icon.vue +15 -0
- package/dist/runtime/vue/components/Link.vue +208 -0
- package/dist/runtime/vue/plugins/color-mode.d.ts +4 -0
- package/dist/runtime/vue/plugins/color-mode.js +6 -0
- package/dist/runtime/vue/plugins/head.d.ts +4 -0
- package/dist/runtime/vue/plugins/head.js +6 -0
- package/dist/runtime/vue/stubs.d.ts +15 -0
- package/dist/runtime/vue/stubs.js +27 -0
- package/dist/shared/ui.CwmIkD_Y.cjs +3269 -0
- package/dist/shared/ui.D_93iuwH.mjs +3262 -0
- package/dist/unplugin.cjs +192 -0
- package/dist/unplugin.d.cts +49 -0
- package/dist/unplugin.d.mts +49 -0
- package/dist/unplugin.d.ts +49 -0
- package/dist/unplugin.mjs +181 -0
- package/dist/vite.cjs +22 -0
- package/dist/vite.d.cts +13 -0
- package/dist/vite.d.mts +13 -0
- package/dist/vite.d.ts +13 -0
- package/dist/vite.mjs +20 -0
- package/package.json +103 -37
- package/vue-plugin.d.ts +5 -0
- package/dist/runtime/assets/css/animations.css +0 -1
- package/dist/runtime/components/Accordion.vue.d.ts +0 -492
- package/dist/runtime/components/Alert.vue.d.ts +0 -548
- package/dist/runtime/components/App.vue.d.ts +0 -25
- package/dist/runtime/components/Avatar.vue.d.ts +0 -384
- package/dist/runtime/components/AvatarGroup.vue.d.ts +0 -381
- package/dist/runtime/components/Badge.vue.d.ts +0 -422
- package/dist/runtime/components/Breadcrumb.vue.d.ts +0 -307
- package/dist/runtime/components/Button.vue.d.ts +0 -949
- package/dist/runtime/components/ButtonGroup.vue.d.ts +0 -182
- package/dist/runtime/components/Card.vue.d.ts +0 -191
- package/dist/runtime/components/Checkbox.vue.d.ts +0 -819
- package/dist/runtime/components/Chip.vue.d.ts +0 -590
- package/dist/runtime/components/Collapsible.vue.d.ts +0 -159
- package/dist/runtime/components/CommandPalette.vue.d.ts +0 -684
- package/dist/runtime/components/Container.vue.d.ts +0 -27
- package/dist/runtime/components/ContextMenu.vue.d.ts +0 -796
- package/dist/runtime/components/Drawer.vue.d.ts +0 -343
- package/dist/runtime/components/DropdownMenu.vue.d.ts +0 -815
- package/dist/runtime/components/DropdownMenuContent.vue.d.ts +0 -0
- package/dist/runtime/components/Form.vue.d.ts +0 -39
- package/dist/runtime/components/FormField.vue.d.ts +0 -356
- package/dist/runtime/components/Icon.vue.d.ts +0 -17
- package/dist/runtime/components/Input.vue.d.ts +0 -1137
- package/dist/runtime/components/InputMenu.vue.d.ts +0 -2121
- package/dist/runtime/components/Kbd.vue.d.ts +0 -169
- package/dist/runtime/components/Link.vue.d.ts +0 -76
- package/dist/runtime/components/LinkBase.vue.d.ts +0 -49
- package/dist/runtime/components/Modal.vue.d.ts +0 -319
- package/dist/runtime/components/NavigationMenu.vue.d.ts +0 -1789
- package/dist/runtime/components/Pagination.vue.d.ts +0 -295
- package/dist/runtime/components/Popover.vue.d.ts +0 -197
- package/dist/runtime/components/Progress.vue.d.ts +0 -1781
- package/dist/runtime/components/RadioGroup.vue.d.ts +0 -1715
- package/dist/runtime/components/Select.vue.d.ts +0 -1569
- package/dist/runtime/components/SelectMenu.vue.d.ts +0 -1661
- package/dist/runtime/components/Separator.vue.d.ts +0 -0
- package/dist/runtime/components/Skeleton.vue.d.ts +0 -26
- package/dist/runtime/components/Slideover.vue.d.ts +0 -375
- package/dist/runtime/components/Slider.vue.d.ts +0 -0
- package/dist/runtime/components/Switch.vue.d.ts +0 -1676
- package/dist/runtime/components/Tabs.vue.d.ts +0 -934
- package/dist/runtime/components/Textarea.vue.d.ts +0 -1133
- package/dist/runtime/components/Toast.vue.d.ts +0 -0
- package/dist/runtime/components/Toaster.vue.d.ts +0 -362
- package/dist/runtime/components/Tooltip.vue.d.ts +0 -248
- package/dist/runtime/types/component.d.ts +0 -17
- package/dist/runtime/types/component.js +0 -0
- /package/dist/runtime/{components/ContextMenuContent.vue.d.ts → types/locale.js} +0 -0
|
@@ -1,88 +1,249 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { InputHTMLAttributes } from 'vue'
|
|
3
|
+
import { tv, type VariantProps } from 'tailwind-variants'
|
|
4
|
+
import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, ComboboxArrowProps, AcceptableValue } from 'reka-ui'
|
|
5
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
6
|
+
import _appConfig from '#build/app.config'
|
|
7
|
+
import theme from '#build/ui/input-menu'
|
|
8
|
+
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
|
|
9
|
+
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
|
10
|
+
import type { AvatarProps, ChipProps, InputProps } from '../types'
|
|
11
|
+
import type { PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
|
|
12
|
+
|
|
13
|
+
const appConfig = _appConfig as AppConfig & { ui: { inputMenu: Partial<typeof theme> } }
|
|
14
|
+
|
|
15
|
+
const inputMenu = tv({ extend: tv(theme), ...(appConfig.ui?.inputMenu || {}) })
|
|
16
|
+
|
|
17
|
+
export interface InputMenuItem {
|
|
18
|
+
label?: string
|
|
19
|
+
icon?: string
|
|
20
|
+
avatar?: AvatarProps
|
|
21
|
+
chip?: ChipProps
|
|
22
|
+
/**
|
|
23
|
+
* The item type.
|
|
24
|
+
* @defaultValue 'item'
|
|
25
|
+
*/
|
|
26
|
+
type?: 'label' | 'separator' | 'item'
|
|
27
|
+
disabled?: boolean
|
|
28
|
+
onSelect?(e?: Event): void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type InputMenuVariants = VariantProps<typeof inputMenu>
|
|
32
|
+
|
|
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
|
+
/**
|
|
35
|
+
* The element or component this component should render as.
|
|
36
|
+
* @defaultValue 'div'
|
|
37
|
+
*/
|
|
38
|
+
as?: any
|
|
39
|
+
id?: string
|
|
40
|
+
type?: InputHTMLAttributes['type']
|
|
41
|
+
/** The placeholder text when the input is empty. */
|
|
42
|
+
placeholder?: string
|
|
43
|
+
color?: InputMenuVariants['color']
|
|
44
|
+
variant?: InputMenuVariants['variant']
|
|
45
|
+
size?: InputMenuVariants['size']
|
|
46
|
+
required?: boolean
|
|
47
|
+
autofocus?: boolean
|
|
48
|
+
autofocusDelay?: number
|
|
49
|
+
/**
|
|
50
|
+
* The icon displayed to open the menu.
|
|
51
|
+
* @defaultValue appConfig.ui.icons.chevronDown
|
|
52
|
+
*/
|
|
53
|
+
trailingIcon?: string
|
|
54
|
+
/**
|
|
55
|
+
* The icon displayed when an item is selected.
|
|
56
|
+
* @defaultValue appConfig.ui.icons.check
|
|
57
|
+
*/
|
|
58
|
+
selectedIcon?: string
|
|
59
|
+
/**
|
|
60
|
+
* The icon displayed to delete a tag.
|
|
61
|
+
* Works only when `multiple` is `true`.
|
|
62
|
+
* @defaultValue appConfig.ui.icons.close
|
|
63
|
+
*/
|
|
64
|
+
deleteIcon?: string
|
|
65
|
+
/**
|
|
66
|
+
* The content of the menu.
|
|
67
|
+
* @defaultValue { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }
|
|
68
|
+
*/
|
|
69
|
+
content?: Omit<ComboboxContentProps, 'as' | 'asChild' | 'forceMount'>
|
|
70
|
+
/**
|
|
71
|
+
* Display an arrow alongside the menu.
|
|
72
|
+
* @defaultValue false
|
|
73
|
+
*/
|
|
74
|
+
arrow?: boolean | Omit<ComboboxArrowProps, 'as' | 'asChild'>
|
|
75
|
+
/**
|
|
76
|
+
* Render the menu in a portal.
|
|
77
|
+
* @defaultValue true
|
|
78
|
+
*/
|
|
79
|
+
portal?: boolean
|
|
80
|
+
/**
|
|
81
|
+
* When `items` is an array of objects, select the field to use as the value instead of the object itself.
|
|
82
|
+
* @defaultValue undefined
|
|
83
|
+
*/
|
|
84
|
+
valueKey?: V
|
|
85
|
+
/**
|
|
86
|
+
* When `items` is an array of objects, select the field to use as the label.
|
|
87
|
+
* @defaultValue 'label'
|
|
88
|
+
*/
|
|
89
|
+
labelKey?: V
|
|
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
|
+
/** Highlight the ring color like a focus state. */
|
|
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
|
|
114
|
+
class?: any
|
|
115
|
+
ui?: PartialString<typeof inputMenu.slots>
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type InputMenuEmits<T, V, M extends boolean> = Omit<ComboboxRootEmits<T>, 'update:modelValue'> & {
|
|
119
|
+
change: [payload: Event]
|
|
120
|
+
blur: [payload: FocusEvent]
|
|
121
|
+
focus: [payload: FocusEvent]
|
|
122
|
+
create: [item: string]
|
|
123
|
+
} & SelectModelValueEmits<T, V, M>
|
|
124
|
+
|
|
125
|
+
type SlotProps<T> = (props: { item: T, index: number }) => any
|
|
126
|
+
|
|
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
|
|
130
|
+
'empty'(props: { searchTerm?: string }): any
|
|
131
|
+
'item': SlotProps<T>
|
|
132
|
+
'item-leading': SlotProps<T>
|
|
133
|
+
'item-label': SlotProps<T>
|
|
134
|
+
'item-trailing': SlotProps<T>
|
|
135
|
+
'tags-item-text': SlotProps<T>
|
|
136
|
+
'tags-item-delete': SlotProps<T>
|
|
137
|
+
'create-item-label'(props: { item: string }): any
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
extendDevtoolsMeta({ defaultProps: { items: ['Option 1', 'Option 2', 'Option 3'] } })
|
|
7
141
|
</script>
|
|
8
142
|
|
|
9
|
-
<script setup lang="ts" generic="T extends InputMenuItem | AcceptableValue">
|
|
10
|
-
import { computed, ref, toRef, onMounted } from 'vue'
|
|
11
|
-
import { ComboboxRoot, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, useForwardPropsEmits } from '
|
|
143
|
+
<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">
|
|
144
|
+
import { computed, ref, toRef, onMounted, toRaw } from 'vue'
|
|
145
|
+
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'
|
|
12
146
|
import { defu } from 'defu'
|
|
13
|
-
import { reactivePick } from '@vueuse/core'
|
|
147
|
+
import { reactivePick, createReusableTemplate } from '@vueuse/core'
|
|
14
148
|
import { useAppConfig } from '#imports'
|
|
15
149
|
import { useButtonGroup } from '../composables/useButtonGroup'
|
|
16
150
|
import { useComponentIcons } from '../composables/useComponentIcons'
|
|
17
151
|
import { useFormField } from '../composables/useFormField'
|
|
152
|
+
import { useLocale } from '../composables/useLocale'
|
|
153
|
+
import { get, compare } from '../utils'
|
|
18
154
|
import UIcon from './Icon.vue'
|
|
19
155
|
import UAvatar from './Avatar.vue'
|
|
20
156
|
import UChip from './Chip.vue'
|
|
21
|
-
import { get } from '../utils'
|
|
22
157
|
|
|
23
158
|
defineOptions({ inheritAttrs: false })
|
|
24
159
|
|
|
25
|
-
const props = withDefaults(defineProps<InputMenuProps<T>>(), {
|
|
160
|
+
const props = withDefaults(defineProps<InputMenuProps<T, I, V, M>>(), {
|
|
26
161
|
type: 'text',
|
|
27
162
|
autofocusDelay: 0,
|
|
28
163
|
portal: true,
|
|
29
|
-
|
|
164
|
+
labelKey: 'label' as never
|
|
30
165
|
})
|
|
31
|
-
const emits = defineEmits<InputMenuEmits<T>>()
|
|
32
|
-
const slots = defineSlots<InputMenuSlots<T>>()
|
|
166
|
+
const emits = defineEmits<InputMenuEmits<T, V, M>>()
|
|
167
|
+
const slots = defineSlots<InputMenuSlots<T, M>>()
|
|
33
168
|
|
|
34
169
|
const searchTerm = defineModel<string>('searchTerm', { default: '' })
|
|
35
170
|
|
|
171
|
+
const { t } = useLocale()
|
|
36
172
|
const appConfig = useAppConfig()
|
|
37
|
-
const
|
|
38
|
-
|
|
173
|
+
const { contains } = useFilter({ sensitivity: 'base' })
|
|
174
|
+
|
|
175
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'multiple', 'resetSearchTermOnBlur', 'highlightOnHover', 'ignoreFilter'), emits)
|
|
176
|
+
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
|
|
177
|
+
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
|
178
|
+
|
|
39
179
|
const { emitFormBlur, emitFormChange, emitFormInput, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
|
|
40
180
|
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
|
41
181
|
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
|
|
42
182
|
|
|
43
183
|
const inputSize = computed(() => buttonGroupSize.value || formGroupSize.value)
|
|
44
184
|
|
|
185
|
+
const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate()
|
|
186
|
+
|
|
45
187
|
const ui = computed(() => inputMenu({
|
|
46
188
|
color: color.value,
|
|
47
189
|
variant: props.variant,
|
|
48
190
|
size: inputSize?.value,
|
|
49
191
|
loading: props.loading,
|
|
50
192
|
highlight: highlight.value,
|
|
51
|
-
leading: isLeading.value || !!slots.leading,
|
|
193
|
+
leading: isLeading.value || !!props.avatar || !!slots.leading,
|
|
52
194
|
trailing: isTrailing.value || !!slots.trailing,
|
|
53
195
|
multiple: props.multiple,
|
|
54
196
|
buttonGroup: orientation.value
|
|
55
197
|
}))
|
|
56
198
|
|
|
57
|
-
function displayValue(
|
|
58
|
-
if (
|
|
59
|
-
return
|
|
199
|
+
function displayValue(value: T): string {
|
|
200
|
+
if (!props.valueKey) {
|
|
201
|
+
return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
|
|
60
202
|
}
|
|
61
203
|
|
|
62
|
-
|
|
204
|
+
const item = items.value.find(item => compare(typeof item === 'object' ? get(item, props.valueKey as string) : item, value))
|
|
205
|
+
return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
|
|
63
206
|
}
|
|
64
207
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
208
|
+
const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0]) ? props.items : [props.items]) as InputMenuItem[][] : [])
|
|
209
|
+
// eslint-disable-next-line vue/no-dupe-keys
|
|
210
|
+
const items = computed(() => groups.value.flatMap(group => group) as T[])
|
|
211
|
+
|
|
212
|
+
const filteredGroups = computed(() => {
|
|
213
|
+
if (props.ignoreFilter || !searchTerm.value) {
|
|
214
|
+
return groups.value
|
|
68
215
|
}
|
|
69
216
|
|
|
70
|
-
const fields = Array.isArray(props.
|
|
217
|
+
const fields = Array.isArray(props.filterFields) ? props.filterFields : [props.labelKey] as string[]
|
|
71
218
|
|
|
72
|
-
return items.filter((item) => {
|
|
219
|
+
return groups.value.map(items => items.filter((item) => {
|
|
73
220
|
if (typeof item !== 'object') {
|
|
74
|
-
return
|
|
221
|
+
return contains(item, searchTerm.value)
|
|
75
222
|
}
|
|
76
223
|
|
|
77
|
-
|
|
78
|
-
|
|
224
|
+
if (item.type && ['label', 'separator'].includes(item.type)) {
|
|
225
|
+
return true
|
|
226
|
+
}
|
|
79
227
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
228
|
+
return fields.some(field => contains(get(item, field), searchTerm.value))
|
|
229
|
+
})).filter(group => group.filter(item => !item.type || !['label', 'separator'].includes(item.type)).length > 0)
|
|
230
|
+
})
|
|
231
|
+
const filteredItems = computed(() => filteredGroups.value.flatMap(group => group) as T[])
|
|
84
232
|
|
|
85
|
-
const
|
|
233
|
+
const createItem = computed(() => {
|
|
234
|
+
if (!props.createItem || !searchTerm.value) {
|
|
235
|
+
return false
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const newItem = props.valueKey ? { [props.valueKey]: searchTerm.value } as T : searchTerm.value
|
|
239
|
+
|
|
240
|
+
if ((typeof props.createItem === 'object' && props.createItem.when === 'always') || props.createItem === 'always') {
|
|
241
|
+
return !filteredItems.value.find(item => compare(item, newItem, props.valueKey))
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return !filteredItems.value.length
|
|
245
|
+
})
|
|
246
|
+
const createItemPosition = computed(() => typeof props.createItem === 'object' ? props.createItem.position : 'bottom')
|
|
86
247
|
|
|
87
248
|
const inputRef = ref<InstanceType<typeof ComboboxInput> | null>(null)
|
|
88
249
|
|
|
@@ -99,6 +260,9 @@ onMounted(() => {
|
|
|
99
260
|
})
|
|
100
261
|
|
|
101
262
|
function onUpdate(value: any) {
|
|
263
|
+
if (toRaw(props.modelValue) === value) {
|
|
264
|
+
return
|
|
265
|
+
}
|
|
102
266
|
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
103
267
|
const event = new Event('change', { target: { value } })
|
|
104
268
|
emits('change', event)
|
|
@@ -111,6 +275,10 @@ function onBlur(event: FocusEvent) {
|
|
|
111
275
|
emitFormBlur()
|
|
112
276
|
}
|
|
113
277
|
|
|
278
|
+
function onFocus(event: FocusEvent) {
|
|
279
|
+
emits('focus', event)
|
|
280
|
+
}
|
|
281
|
+
|
|
114
282
|
function onUpdateOpen(value: boolean) {
|
|
115
283
|
if (!value) {
|
|
116
284
|
const event = new FocusEvent('blur')
|
|
@@ -127,18 +295,33 @@ defineExpose({
|
|
|
127
295
|
})
|
|
128
296
|
</script>
|
|
129
297
|
|
|
298
|
+
<!-- eslint-disable vue/no-template-shadow -->
|
|
130
299
|
<template>
|
|
300
|
+
<DefineCreateItemTemplate>
|
|
301
|
+
<ComboboxGroup :class="ui.group({ class: props.ui?.group })">
|
|
302
|
+
<ComboboxItem
|
|
303
|
+
:class="ui.item({ class: props.ui?.item })"
|
|
304
|
+
:value="searchTerm"
|
|
305
|
+
@select.prevent="emits('create', searchTerm)"
|
|
306
|
+
>
|
|
307
|
+
<span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
|
|
308
|
+
<slot name="create-item-label" :item="searchTerm">
|
|
309
|
+
{{ t('inputMenu.create', { label: searchTerm }) }}
|
|
310
|
+
</slot>
|
|
311
|
+
</span>
|
|
312
|
+
</ComboboxItem>
|
|
313
|
+
</ComboboxGroup>
|
|
314
|
+
</DefineCreateItemTemplate>
|
|
315
|
+
|
|
131
316
|
<ComboboxRoot
|
|
132
317
|
:id="id"
|
|
133
318
|
v-slot="{ modelValue, open }"
|
|
134
319
|
v-bind="rootProps"
|
|
135
|
-
v-model:search-term="searchTerm"
|
|
136
320
|
:name="name"
|
|
137
321
|
:disabled="disabled"
|
|
138
|
-
:display-value="displayValue"
|
|
139
|
-
:filter-function="filterFunction"
|
|
140
322
|
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
|
141
323
|
:as-child="!!multiple"
|
|
324
|
+
ignore-filter
|
|
142
325
|
@update:model-value="onUpdate"
|
|
143
326
|
@update:open="onUpdateOpen"
|
|
144
327
|
@keydown.enter="$event.preventDefault()"
|
|
@@ -146,17 +329,18 @@ defineExpose({
|
|
|
146
329
|
<ComboboxAnchor :as-child="!multiple" :class="ui.base({ class: props.ui?.base })">
|
|
147
330
|
<TagsInputRoot
|
|
148
331
|
v-if="multiple"
|
|
149
|
-
v-slot="{ modelValue: tags }
|
|
332
|
+
v-slot="{ modelValue: tags }"
|
|
150
333
|
:model-value="(modelValue as string[])"
|
|
151
334
|
:disabled="disabled"
|
|
152
335
|
delimiter=""
|
|
153
336
|
as-child
|
|
154
337
|
@blur="onBlur"
|
|
338
|
+
@focus="onFocus"
|
|
155
339
|
>
|
|
156
340
|
<TagsInputItem v-for="(item, index) in tags" :key="index" :value="(item as string)" :class="ui.tagsItem({ class: props.ui?.tagsItem })">
|
|
157
341
|
<TagsInputItemText :class="ui.tagsItemText({ class: props.ui?.tagsItemText })">
|
|
158
342
|
<slot name="tags-item-text" :item="(item as T)" :index="index">
|
|
159
|
-
{{
|
|
343
|
+
{{ displayValue(item as T) }}
|
|
160
344
|
</slot>
|
|
161
345
|
</TagsInputItemText>
|
|
162
346
|
|
|
@@ -167,7 +351,7 @@ defineExpose({
|
|
|
167
351
|
</TagsInputItemDelete>
|
|
168
352
|
</TagsInputItem>
|
|
169
353
|
|
|
170
|
-
<ComboboxInput as-child>
|
|
354
|
+
<ComboboxInput v-model="searchTerm" :display-value="displayValue" as-child>
|
|
171
355
|
<TagsInputInput
|
|
172
356
|
ref="inputRef"
|
|
173
357
|
v-bind="$attrs"
|
|
@@ -182,22 +366,25 @@ defineExpose({
|
|
|
182
366
|
<ComboboxInput
|
|
183
367
|
v-else
|
|
184
368
|
ref="inputRef"
|
|
369
|
+
v-model="searchTerm"
|
|
370
|
+
:display-value="displayValue"
|
|
185
371
|
v-bind="$attrs"
|
|
186
372
|
:type="type"
|
|
187
373
|
:placeholder="placeholder"
|
|
188
374
|
:required="required"
|
|
189
|
-
:class="ui.base({ class: props.ui?.base })"
|
|
190
375
|
@blur="onBlur"
|
|
376
|
+
@focus="onFocus"
|
|
191
377
|
/>
|
|
192
378
|
|
|
193
|
-
<span v-if="isLeading || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
|
194
|
-
<slot name="leading" :model-value="(modelValue as T)" :open="open" :ui="ui">
|
|
195
|
-
<UIcon v-if="leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
|
379
|
+
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
|
380
|
+
<slot name="leading" :model-value="(modelValue as M extends true ? T[] : T)" :open="open" :ui="ui">
|
|
381
|
+
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
|
382
|
+
<UAvatar v-else-if="!!avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
|
|
196
383
|
</slot>
|
|
197
384
|
</span>
|
|
198
385
|
|
|
199
386
|
<ComboboxTrigger v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
|
|
200
|
-
<slot name="trailing" :model-value="(modelValue as T)" :open="open" :ui="ui">
|
|
387
|
+
<slot name="trailing" :model-value="(modelValue as M extends true ? T[] : T)" :open="open" :ui="ui">
|
|
201
388
|
<UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
|
|
202
389
|
</slot>
|
|
203
390
|
</ComboboxTrigger>
|
|
@@ -207,15 +394,17 @@ defineExpose({
|
|
|
207
394
|
<ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
|
|
208
395
|
<ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
|
|
209
396
|
<slot name="empty" :search-term="searchTerm">
|
|
210
|
-
{{ searchTerm ?
|
|
397
|
+
{{ searchTerm ? t('inputMenu.noMatch', { searchTerm }) : t('inputMenu.noData') }}
|
|
211
398
|
</slot>
|
|
212
399
|
</ComboboxEmpty>
|
|
213
400
|
|
|
214
401
|
<ComboboxViewport :class="ui.viewport({ class: props.ui?.viewport })">
|
|
215
|
-
<
|
|
402
|
+
<ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'top'" />
|
|
403
|
+
|
|
404
|
+
<ComboboxGroup v-for="(group, groupIndex) in filteredGroups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
|
|
216
405
|
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
|
217
406
|
<ComboboxLabel v-if="item?.type === 'label'" :class="ui.label({ class: props.ui?.label })">
|
|
218
|
-
{{ item.
|
|
407
|
+
{{ get(item, props.labelKey as string) }}
|
|
219
408
|
</ComboboxLabel>
|
|
220
409
|
|
|
221
410
|
<ComboboxSeparator v-else-if="item?.type === 'separator'" :class="ui.separator({ class: props.ui?.separator })" />
|
|
@@ -224,12 +413,13 @@ defineExpose({
|
|
|
224
413
|
v-else
|
|
225
414
|
:class="ui.item({ class: props.ui?.item })"
|
|
226
415
|
:disabled="item.disabled"
|
|
227
|
-
:value="valueKey && typeof item === 'object' ? (item
|
|
416
|
+
:value="valueKey && typeof item === 'object' ? get(item, props.valueKey as string) : item"
|
|
417
|
+
@select="item.onSelect"
|
|
228
418
|
>
|
|
229
419
|
<slot name="item" :item="(item as T)" :index="index">
|
|
230
420
|
<slot name="item-leading" :item="(item as T)" :index="index">
|
|
231
|
-
<
|
|
232
|
-
<
|
|
421
|
+
<UIcon v-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
|
|
422
|
+
<UAvatar v-else-if="item.avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
|
|
233
423
|
<UChip
|
|
234
424
|
v-else-if="item.chip"
|
|
235
425
|
:size="((props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()) as ChipProps['size'])"
|
|
@@ -242,7 +432,7 @@ defineExpose({
|
|
|
242
432
|
|
|
243
433
|
<span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
|
|
244
434
|
<slot name="item-label" :item="(item as T)" :index="index">
|
|
245
|
-
{{
|
|
435
|
+
{{ typeof item === 'object' ? get(item, props.labelKey as string) : item }}
|
|
246
436
|
</slot>
|
|
247
437
|
</span>
|
|
248
438
|
|
|
@@ -257,7 +447,11 @@ defineExpose({
|
|
|
257
447
|
</ComboboxItem>
|
|
258
448
|
</template>
|
|
259
449
|
</ComboboxGroup>
|
|
450
|
+
|
|
451
|
+
<ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'bottom'" />
|
|
260
452
|
</ComboboxViewport>
|
|
453
|
+
|
|
454
|
+
<ComboboxArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
|
|
261
455
|
</ComboboxContent>
|
|
262
456
|
</ComboboxPortal>
|
|
263
457
|
</ComboboxRoot>
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tv, type VariantProps } from 'tailwind-variants'
|
|
3
|
+
import type { NumberFieldRootProps } from 'reka-ui'
|
|
4
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
5
|
+
import _appConfig from '#build/app.config'
|
|
6
|
+
import theme from '#build/ui/input-number'
|
|
7
|
+
import type { ButtonProps } from '../types'
|
|
8
|
+
|
|
9
|
+
const appConfig = _appConfig as AppConfig & { ui: { inputNumber: Partial<typeof theme> } }
|
|
10
|
+
|
|
11
|
+
const inputNumber = tv({ extend: tv(theme), ...(appConfig.ui?.inputNumber || {}) })
|
|
12
|
+
|
|
13
|
+
type InputNumberVariants = VariantProps<typeof inputNumber>
|
|
14
|
+
|
|
15
|
+
export interface InputNumberProps extends Pick<NumberFieldRootProps, 'modelValue' | 'defaultValue' | 'min' | 'max' | 'step' | 'disabled' | 'required' | 'id' | 'name' | 'formatOptions'> {
|
|
16
|
+
/**
|
|
17
|
+
* The element or component this component should render as.
|
|
18
|
+
* @defaultValue 'div'
|
|
19
|
+
*/
|
|
20
|
+
as?: any
|
|
21
|
+
class?: any
|
|
22
|
+
/** The placeholder text when the input is empty. */
|
|
23
|
+
placeholder?: string
|
|
24
|
+
ui?: Partial<typeof inputNumber.slots>
|
|
25
|
+
color?: InputNumberVariants['color']
|
|
26
|
+
variant?: InputNumberVariants['variant']
|
|
27
|
+
size?: InputNumberVariants['size']
|
|
28
|
+
/** Highlight the ring color like a focus state. */
|
|
29
|
+
highlight?: boolean
|
|
30
|
+
/**
|
|
31
|
+
* The orientation of the input menu.
|
|
32
|
+
* @defaultValue 'horizontal'
|
|
33
|
+
*/
|
|
34
|
+
orientation?: 'vertical' | 'horizontal'
|
|
35
|
+
/**
|
|
36
|
+
* Configure the increment button. The `color` and `size` are inherited.
|
|
37
|
+
* @defaultValue { variant: 'link' }
|
|
38
|
+
*/
|
|
39
|
+
increment?: ButtonProps
|
|
40
|
+
/**
|
|
41
|
+
* The icon displayed to increment the value.
|
|
42
|
+
* @defaultValue appConfig.ui.icons.plus
|
|
43
|
+
*/
|
|
44
|
+
incrementIcon?: string
|
|
45
|
+
/**
|
|
46
|
+
* Configure the decrement button. The `color` and `size` are inherited.
|
|
47
|
+
* @defaultValue { variant: 'link' }
|
|
48
|
+
*/
|
|
49
|
+
decrement?: ButtonProps
|
|
50
|
+
/**
|
|
51
|
+
* The icon displayed to decrement the value.
|
|
52
|
+
* @defaultValue appConfig.ui.icons.minus
|
|
53
|
+
*/
|
|
54
|
+
decrementIcon?: string
|
|
55
|
+
autofocus?: boolean
|
|
56
|
+
autofocusDelay?: number
|
|
57
|
+
/**
|
|
58
|
+
* The locale to use for formatting and parsing numbers.
|
|
59
|
+
* @defaultValue UApp.locale.code
|
|
60
|
+
*/
|
|
61
|
+
locale?: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface InputNumberEmits {
|
|
65
|
+
(e: 'update:modelValue', payload: number): void
|
|
66
|
+
(e: 'blur', event: FocusEvent): void
|
|
67
|
+
(e: 'change', payload: Event): void
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface InputNumberSlots {
|
|
71
|
+
increment(props?: {}): any
|
|
72
|
+
decrement(props?: {}): any
|
|
73
|
+
}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<script setup lang="ts">
|
|
77
|
+
import { onMounted, ref, computed } from 'vue'
|
|
78
|
+
import { NumberFieldRoot, NumberFieldInput, NumberFieldDecrement, NumberFieldIncrement, useForwardPropsEmits } from 'reka-ui'
|
|
79
|
+
import { reactivePick } from '@vueuse/core'
|
|
80
|
+
import { useFormField } from '../composables/useFormField'
|
|
81
|
+
import { useLocale } from '../composables/useLocale'
|
|
82
|
+
import UButton from './Button.vue'
|
|
83
|
+
|
|
84
|
+
defineOptions({ inheritAttrs: false })
|
|
85
|
+
|
|
86
|
+
const props = withDefaults(defineProps<InputNumberProps>(), {
|
|
87
|
+
orientation: 'horizontal'
|
|
88
|
+
})
|
|
89
|
+
const emits = defineEmits<InputNumberEmits>()
|
|
90
|
+
defineSlots<InputNumberSlots>()
|
|
91
|
+
|
|
92
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'min', 'max', 'step', 'formatOptions'), emits)
|
|
93
|
+
|
|
94
|
+
const { emitFormBlur, emitFormChange, emitFormInput, id, color, size, name, highlight, disabled } = useFormField<InputNumberProps>(props)
|
|
95
|
+
|
|
96
|
+
const { t, code: codeLocale } = useLocale()
|
|
97
|
+
const locale = computed(() => props.locale || codeLocale.value)
|
|
98
|
+
|
|
99
|
+
const ui = computed(() => inputNumber({
|
|
100
|
+
color: color.value,
|
|
101
|
+
variant: props.variant,
|
|
102
|
+
size: size.value,
|
|
103
|
+
highlight: highlight.value,
|
|
104
|
+
orientation: props.orientation
|
|
105
|
+
}))
|
|
106
|
+
|
|
107
|
+
const incrementIcon = computed(() => props.incrementIcon || (props.orientation === 'horizontal' ? appConfig.ui.icons.plus : appConfig.ui.icons.chevronUp))
|
|
108
|
+
const decrementIcon = computed(() => props.decrementIcon || (props.orientation === 'horizontal' ? appConfig.ui.icons.minus : appConfig.ui.icons.chevronDown))
|
|
109
|
+
|
|
110
|
+
const inputRef = ref<InstanceType<typeof NumberFieldInput> | null>(null)
|
|
111
|
+
|
|
112
|
+
function autoFocus() {
|
|
113
|
+
if (props.autofocus) {
|
|
114
|
+
inputRef.value?.$el?.focus()
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
onMounted(() => {
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
autoFocus()
|
|
121
|
+
}, props.autofocusDelay)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
function onUpdate(value: number) {
|
|
125
|
+
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
|
126
|
+
const event = new Event('change', { target: { value } })
|
|
127
|
+
emits('change', event)
|
|
128
|
+
|
|
129
|
+
emitFormChange()
|
|
130
|
+
emitFormInput()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function onBlur(event: FocusEvent) {
|
|
134
|
+
emitFormBlur()
|
|
135
|
+
emits('blur', event)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
defineExpose({
|
|
139
|
+
inputRef
|
|
140
|
+
})
|
|
141
|
+
</script>
|
|
142
|
+
|
|
143
|
+
<template>
|
|
144
|
+
<NumberFieldRoot
|
|
145
|
+
v-bind="rootProps"
|
|
146
|
+
:id="id"
|
|
147
|
+
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
|
148
|
+
:name="name"
|
|
149
|
+
:disabled="disabled"
|
|
150
|
+
:locale="locale"
|
|
151
|
+
@update:model-value="onUpdate"
|
|
152
|
+
>
|
|
153
|
+
<NumberFieldInput
|
|
154
|
+
v-bind="$attrs"
|
|
155
|
+
ref="inputRef"
|
|
156
|
+
:placeholder="placeholder"
|
|
157
|
+
:required="required"
|
|
158
|
+
:class="ui.base({ class: props.ui?.base })"
|
|
159
|
+
@blur="onBlur"
|
|
160
|
+
/>
|
|
161
|
+
|
|
162
|
+
<div :class="ui.increment({ class: props.ui?.increment })">
|
|
163
|
+
<NumberFieldIncrement as-child :disabled="disabled">
|
|
164
|
+
<slot name="increment">
|
|
165
|
+
<UButton
|
|
166
|
+
:icon="incrementIcon"
|
|
167
|
+
:color="color"
|
|
168
|
+
:size="size"
|
|
169
|
+
variant="link"
|
|
170
|
+
:aria-label="t('inputNumber.increment')"
|
|
171
|
+
v-bind="typeof increment === 'object' ? increment : undefined"
|
|
172
|
+
/>
|
|
173
|
+
</slot>
|
|
174
|
+
</NumberFieldIncrement>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<div :class="ui.decrement({ class: props.ui?.decrement })">
|
|
178
|
+
<NumberFieldDecrement as-child :disabled="disabled">
|
|
179
|
+
<slot name="decrement">
|
|
180
|
+
<UButton
|
|
181
|
+
:icon="decrementIcon"
|
|
182
|
+
:color="color"
|
|
183
|
+
:size="size"
|
|
184
|
+
variant="link"
|
|
185
|
+
:aria-label="t('inputNumber.decrement')"
|
|
186
|
+
v-bind="typeof decrement === 'object' ? decrement : undefined"
|
|
187
|
+
/>
|
|
188
|
+
</slot>
|
|
189
|
+
</NumberFieldDecrement>
|
|
190
|
+
</div>
|
|
191
|
+
</NumberFieldRoot>
|
|
192
|
+
</template>
|