@scalar/components 0.29.2 → 0.30.0
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/dist/components/ScalarCombobox/ScalarCombobox.vue.d.ts +4 -0
- package/dist/components/ScalarCombobox/ScalarCombobox.vue.d.ts.map +1 -1
- package/dist/components/ScalarCombobox/ScalarCombobox.vue.js.map +1 -1
- package/dist/components/ScalarCombobox/ScalarCombobox.vue.script.js +8 -0
- package/dist/components/ScalarCombobox/ScalarCombobox.vue.script.js.map +1 -1
- package/dist/components/ScalarCombobox/ScalarComboboxOptions.vue.d.ts +6 -0
- package/dist/components/ScalarCombobox/ScalarComboboxOptions.vue.d.ts.map +1 -1
- package/dist/components/ScalarCombobox/ScalarComboboxOptions.vue.js.map +1 -1
- package/dist/components/ScalarCombobox/ScalarComboboxOptions.vue.script.js +67 -49
- package/dist/components/ScalarCombobox/ScalarComboboxOptions.vue.script.js.map +1 -1
- package/dist/components/ScalarDropdown/ScalarDropdownButton.vue.js +1 -1
- package/dist/components/ScalarDropdown/ScalarDropdownButton.vue.js.map +1 -1
- package/dist/components/ScalarDropdown/ScalarDropdownButton.vue.script.js +1 -1
- package/dist/components/ScalarDropdown/ScalarDropdownButton.vue.script.js.map +1 -1
- package/dist/components/ScalarDropdown/ScalarDropdownMenu.vue.d.ts.map +1 -1
- package/dist/components/ScalarDropdown/ScalarDropdownMenu.vue.js.map +1 -1
- package/dist/components/ScalarDropdown/ScalarDropdownMenu.vue.script.js +1 -1
- package/dist/components/ScalarDropdown/ScalarDropdownMenu.vue.script.js.map +1 -1
- package/dist/style.css +2 -2
- package/dist/vue-styles.css +2 -2
- package/package.json +7 -7
|
@@ -19,6 +19,10 @@ declare const __VLS_export: <O extends Option = Option, G extends OptionGroup<O>
|
|
|
19
19
|
options: OptionsOrGroups<O, G>;
|
|
20
20
|
/** The placeholder text to display in the combobox */
|
|
21
21
|
placeholder?: string;
|
|
22
|
+
/** An accessible label for the search input */
|
|
23
|
+
inputLabel?: string;
|
|
24
|
+
/** The message to display when filtering returns no options */
|
|
25
|
+
noResults?: string;
|
|
22
26
|
/** A function to filter the options based on a query,
|
|
23
27
|
* if not provided, the options will be filtered by option label
|
|
24
28
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarCombobox.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarCombobox/ScalarCombobox.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ScalarCombobox.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarCombobox/ScalarCombobox.vue"],"names":[],"mappings":"AA6GA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AAG9D,OAAO,KAAK,EAEV,aAAa,EACb,cAAc,EACd,MAAM,EACN,WAAW,EACX,eAAe,EAChB,MAAM,SAAS,CAAA;AAGhB;;;;;;;;;;GAUG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY,GAAK,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,EAC1F,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WA4KO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB,CAAC;QA1KpD,6CAA6C;iBACpC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9B,sDAAsD;sBACxC,MAAM;QACpB,+CAA+C;qBAClC,MAAM;QACnB,+DAA+D;oBACnD,MAAM;QAClB;;;;WAIG;mBACQ,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;;qBAgBtB,CAAC;;;;KA6I6E,CAAC,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC5J,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;UAEJ,qFAAoC;EAEvC,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;CAAI,CAAC;AACzF,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarCombobox.vue.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarCombobox.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox component\n *\n * A searchable select input with support for filtering, option groups,\n * and custom option rendering.\n *\n * @example\n * <ScalarCombobox v-model=\"selected\" :options=\"options\">\n * <ScalarButton>{{ selected?.label ?? 'Select' }}</ScalarButton>\n * </ScalarCombobox>\n */\nexport default {}\n</script>\n\n<!-- prettier-ignore-attribute generic -->\n<script\n setup\n lang=\"ts\"\n generic=\"O extends Option = Option, G extends OptionGroup<O> = OptionGroup<O>\">\nimport type { ScalarFloatingOptions } from '../ScalarFloating'\nimport ComboboxOptions from './ScalarComboboxOptions.vue'\nimport ComboboxPopover from './ScalarComboboxPopover.vue'\nimport type {\n ComboboxEmits,\n ComboboxSlots,\n FilterFunction,\n Option,\n OptionGroup,\n OptionsOrGroups,\n} from './types'\n\ndefineProps<\n {\n /** The options to display in the combobox */\n options: OptionsOrGroups<O, G>\n /** The placeholder text to display in the combobox */\n placeholder?: string\n /** A function to filter the options based on a query,\n * if not provided, the options will be filtered by option label\n *\n * @see {@link FilterFunction} for more information\n */\n filterFn?: FilterFunction<O, G>\n } & ScalarFloatingOptions\n>()\n\nconst emit = defineEmits<ComboboxEmits>()\n\nconst model = defineModel<O>()\n\ndefineSlots<ComboboxSlots<O, G>>()\n</script>\n<template>\n <ComboboxPopover\n :middleware\n :offset\n :placement=\"placement ?? 'bottom-start'\"\n :resize\n :target\n :teleport>\n <template #default=\"{ open }\">\n <slot :open />\n </template>\n <template #popover=\"{ open, close }\">\n <ComboboxOptions\n :filterFn\n :modelValue=\"model ? [model] : []\"\n :open\n :options\n :placeholder\n @add=\"() => (close(), emit('add'))\"\n @update:modelValue=\"(v) => (close(), (model = v[0]))\">\n <!-- Pass through the combobox slots -->\n <template\n v-if=\"$slots.option\"\n #option=\"props\">\n <slot\n name=\"option\"\n v-bind=\"props\" />\n </template>\n <template\n v-if=\"$slots.group\"\n #group=\"props\">\n <slot\n name=\"group\"\n v-bind=\"props\" />\n </template>\n <template\n v-if=\"$slots.add\"\n #add=\"props\">\n <slot\n name=\"add\"\n v-bind=\"props\" />\n </template>\n </ComboboxOptions>\n </template>\n </ComboboxPopover>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarCombobox.vue.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarCombobox.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox component\n *\n * A searchable select input with support for filtering, option groups,\n * and custom option rendering.\n *\n * @example\n * <ScalarCombobox v-model=\"selected\" :options=\"options\">\n * <ScalarButton>{{ selected?.label ?? 'Select' }}</ScalarButton>\n * </ScalarCombobox>\n */\nexport default {}\n</script>\n\n<!-- prettier-ignore-attribute generic -->\n<script\n setup\n lang=\"ts\"\n generic=\"O extends Option = Option, G extends OptionGroup<O> = OptionGroup<O>\">\nimport type { ScalarFloatingOptions } from '../ScalarFloating'\nimport ComboboxOptions from './ScalarComboboxOptions.vue'\nimport ComboboxPopover from './ScalarComboboxPopover.vue'\nimport type {\n ComboboxEmits,\n ComboboxSlots,\n FilterFunction,\n Option,\n OptionGroup,\n OptionsOrGroups,\n} from './types'\n\ndefineProps<\n {\n /** The options to display in the combobox */\n options: OptionsOrGroups<O, G>\n /** The placeholder text to display in the combobox */\n placeholder?: string\n /** An accessible label for the search input */\n inputLabel?: string\n /** The message to display when filtering returns no options */\n noResults?: string\n /** A function to filter the options based on a query,\n * if not provided, the options will be filtered by option label\n *\n * @see {@link FilterFunction} for more information\n */\n filterFn?: FilterFunction<O, G>\n } & ScalarFloatingOptions\n>()\n\nconst emit = defineEmits<ComboboxEmits>()\n\nconst model = defineModel<O>()\n\ndefineSlots<ComboboxSlots<O, G>>()\n</script>\n<template>\n <ComboboxPopover\n :middleware\n :offset\n :placement=\"placement ?? 'bottom-start'\"\n :resize\n :target\n :teleport>\n <template #default=\"{ open }\">\n <slot :open />\n </template>\n <template #popover=\"{ open, close }\">\n <ComboboxOptions\n :close\n :filterFn\n :inputLabel\n :modelValue=\"model ? [model] : []\"\n :noResults\n :open\n :options\n :placeholder\n @add=\"() => (close(), emit('add'))\"\n @update:modelValue=\"(v) => (close(), (model = v[0]))\">\n <!-- Pass through the combobox slots -->\n <template\n v-if=\"$slots.option\"\n #option=\"props\">\n <slot\n name=\"option\"\n v-bind=\"props\" />\n </template>\n <template\n v-if=\"$slots.group\"\n #group=\"props\">\n <slot\n name=\"group\"\n v-bind=\"props\" />\n </template>\n <template\n v-if=\"$slots.add\"\n #add=\"props\">\n <slot\n name=\"add\"\n v-bind=\"props\" />\n </template>\n </ComboboxOptions>\n </template>\n </ComboboxPopover>\n</template>\n"],"mappings":""}
|
|
@@ -6,6 +6,8 @@ var ScalarCombobox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
6
6
|
props: /*@__PURE__*/ mergeModels({
|
|
7
7
|
options: {},
|
|
8
8
|
placeholder: {},
|
|
9
|
+
inputLabel: {},
|
|
10
|
+
noResults: {},
|
|
9
11
|
filterFn: { type: Function },
|
|
10
12
|
placement: {},
|
|
11
13
|
offset: { type: [
|
|
@@ -36,8 +38,11 @@ var ScalarCombobox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
36
38
|
}, {
|
|
37
39
|
default: withCtx(({ open }) => [renderSlot(_ctx.$slots, "default", { open })]),
|
|
38
40
|
popover: withCtx(({ open, close }) => [createVNode(ScalarComboboxOptions_default, {
|
|
41
|
+
close,
|
|
39
42
|
filterFn: __props.filterFn,
|
|
43
|
+
inputLabel: __props.inputLabel,
|
|
40
44
|
modelValue: model.value ? [model.value] : [],
|
|
45
|
+
noResults: __props.noResults,
|
|
41
46
|
open,
|
|
42
47
|
options: __props.options,
|
|
43
48
|
placeholder: __props.placeholder,
|
|
@@ -60,8 +65,11 @@ var ScalarCombobox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
|
|
|
60
65
|
key: "2"
|
|
61
66
|
} : void 0
|
|
62
67
|
]), 1032, [
|
|
68
|
+
"close",
|
|
63
69
|
"filterFn",
|
|
70
|
+
"inputLabel",
|
|
64
71
|
"modelValue",
|
|
72
|
+
"noResults",
|
|
65
73
|
"open",
|
|
66
74
|
"options",
|
|
67
75
|
"placeholder",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarCombobox.vue.script.js","names":["$slots"],"sources":["../../../src/components/ScalarCombobox/ScalarCombobox.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox component\n *\n * A searchable select input with support for filtering, option groups,\n * and custom option rendering.\n *\n * @example\n * <ScalarCombobox v-model=\"selected\" :options=\"options\">\n * <ScalarButton>{{ selected?.label ?? 'Select' }}</ScalarButton>\n * </ScalarCombobox>\n */\nexport default {}\n</script>\n\n<!-- prettier-ignore-attribute generic -->\n<script\n setup\n lang=\"ts\"\n generic=\"O extends Option = Option, G extends OptionGroup<O> = OptionGroup<O>\">\nimport type { ScalarFloatingOptions } from '../ScalarFloating'\nimport ComboboxOptions from './ScalarComboboxOptions.vue'\nimport ComboboxPopover from './ScalarComboboxPopover.vue'\nimport type {\n ComboboxEmits,\n ComboboxSlots,\n FilterFunction,\n Option,\n OptionGroup,\n OptionsOrGroups,\n} from './types'\n\ndefineProps<\n {\n /** The options to display in the combobox */\n options: OptionsOrGroups<O, G>\n /** The placeholder text to display in the combobox */\n placeholder?: string\n /** A function to filter the options based on a query,\n * if not provided, the options will be filtered by option label\n *\n * @see {@link FilterFunction} for more information\n */\n filterFn?: FilterFunction<O, G>\n } & ScalarFloatingOptions\n>()\n\nconst emit = defineEmits<ComboboxEmits>()\n\nconst model = defineModel<O>()\n\ndefineSlots<ComboboxSlots<O, G>>()\n</script>\n<template>\n <ComboboxPopover\n :middleware\n :offset\n :placement=\"placement ?? 'bottom-start'\"\n :resize\n :target\n :teleport>\n <template #default=\"{ open }\">\n <slot :open />\n </template>\n <template #popover=\"{ open, close }\">\n <ComboboxOptions\n :filterFn\n :modelValue=\"model ? [model] : []\"\n :open\n :options\n :placeholder\n @add=\"() => (close(), emit('add'))\"\n @update:modelValue=\"(v) => (close(), (model = v[0]))\">\n <!-- Pass through the combobox slots -->\n <template\n v-if=\"$slots.option\"\n #option=\"props\">\n <slot\n name=\"option\"\n v-bind=\"props\" />\n </template>\n <template\n v-if=\"$slots.group\"\n #group=\"props\">\n <slot\n name=\"group\"\n v-bind=\"props\" />\n </template>\n <template\n v-if=\"$slots.add\"\n #add=\"props\">\n <slot\n name=\"add\"\n v-bind=\"props\" />\n </template>\n </ComboboxOptions>\n </template>\n </ComboboxPopover>\n</template>\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ScalarCombobox.vue.script.js","names":["$slots"],"sources":["../../../src/components/ScalarCombobox/ScalarCombobox.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox component\n *\n * A searchable select input with support for filtering, option groups,\n * and custom option rendering.\n *\n * @example\n * <ScalarCombobox v-model=\"selected\" :options=\"options\">\n * <ScalarButton>{{ selected?.label ?? 'Select' }}</ScalarButton>\n * </ScalarCombobox>\n */\nexport default {}\n</script>\n\n<!-- prettier-ignore-attribute generic -->\n<script\n setup\n lang=\"ts\"\n generic=\"O extends Option = Option, G extends OptionGroup<O> = OptionGroup<O>\">\nimport type { ScalarFloatingOptions } from '../ScalarFloating'\nimport ComboboxOptions from './ScalarComboboxOptions.vue'\nimport ComboboxPopover from './ScalarComboboxPopover.vue'\nimport type {\n ComboboxEmits,\n ComboboxSlots,\n FilterFunction,\n Option,\n OptionGroup,\n OptionsOrGroups,\n} from './types'\n\ndefineProps<\n {\n /** The options to display in the combobox */\n options: OptionsOrGroups<O, G>\n /** The placeholder text to display in the combobox */\n placeholder?: string\n /** An accessible label for the search input */\n inputLabel?: string\n /** The message to display when filtering returns no options */\n noResults?: string\n /** A function to filter the options based on a query,\n * if not provided, the options will be filtered by option label\n *\n * @see {@link FilterFunction} for more information\n */\n filterFn?: FilterFunction<O, G>\n } & ScalarFloatingOptions\n>()\n\nconst emit = defineEmits<ComboboxEmits>()\n\nconst model = defineModel<O>()\n\ndefineSlots<ComboboxSlots<O, G>>()\n</script>\n<template>\n <ComboboxPopover\n :middleware\n :offset\n :placement=\"placement ?? 'bottom-start'\"\n :resize\n :target\n :teleport>\n <template #default=\"{ open }\">\n <slot :open />\n </template>\n <template #popover=\"{ open, close }\">\n <ComboboxOptions\n :close\n :filterFn\n :inputLabel\n :modelValue=\"model ? [model] : []\"\n :noResults\n :open\n :options\n :placeholder\n @add=\"() => (close(), emit('add'))\"\n @update:modelValue=\"(v) => (close(), (model = v[0]))\">\n <!-- Pass through the combobox slots -->\n <template\n v-if=\"$slots.option\"\n #option=\"props\">\n <slot\n name=\"option\"\n v-bind=\"props\" />\n </template>\n <template\n v-if=\"$slots.group\"\n #group=\"props\">\n <slot\n name=\"group\"\n v-bind=\"props\" />\n </template>\n <template\n v-if=\"$slots.add\"\n #add=\"props\">\n <slot\n name=\"add\"\n v-bind=\"props\" />\n </template>\n </ComboboxOptions>\n </template>\n </ComboboxPopover>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;EAmDA,MAAM,OAAO;EAEb,MAAM,QAAQ,SAAc,SAAA,YAAC;;uBAK3B,YA8CkB,+BAAA;IA7Cf,YAAA,QAAA;IACA,QAAA,QAAA;IACA,WAAW,QAAA,aAAS;IACpB,QAAA,QAAA;IACA,QAAA,QAAA;IACA,UAAA,QAAA;;IACU,SAAO,SACF,EADM,WAAI,CACxB,WAAc,KAAA,QAAA,WAAA,EAAP,KAAI,CAAA,CAAA,CAAA;IAEF,SAAO,SAkCE,EAlCE,MAAM,YAAK,CAC/B,YAiCkB,+BAAA;KAhCf;KACA,UAAA,QAAA;KACA,YAAA,QAAA;KACA,YAAY,MAAA,QAAK,CAAI,MAAA,KAAK,IAAA,CAAA;KAC1B,WAAA,QAAA;KACA;KACA,SAAA,QAAA;KACA,aAAA,QAAA;KACA,cAAY,MAAK,GAAI,KAAI,KAAA;KACzB,wBAAoB,OAAO,MAAK,GAAK,MAAA,QAAQ,EAAC;;KAGvCA,KAAAA,OAAO,SAAA;YACZ;mBAAQ,UAAK,CACd,WAEmB,KAAA,QAAA,UAAA,eAAA,mBAAT,KAAK,CAAA,CAAA,CAAA,CAAA;;;KAGTA,KAAAA,OAAO,QAAA;YACZ;mBAAO,UAAK,CACb,WAEmB,KAAA,QAAA,SAAA,eAAA,mBAAT,KAAK,CAAA,CAAA,CAAA,CAAA;;;KAGTA,KAAAA,OAAO,MAAA;YACZ;mBAAK,UAAK,CACX,WAEmB,KAAA,QAAA,OAAA,eAAA,mBAAT,KAAK,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -16,6 +16,12 @@ declare const __VLS_export: <O extends Option = Option, G extends OptionGroup<O>
|
|
|
16
16
|
options: OptionsOrGroups<O, G>;
|
|
17
17
|
/** The placeholder text to display in the combobox */
|
|
18
18
|
placeholder?: string;
|
|
19
|
+
/** An accessible label for the search input */
|
|
20
|
+
inputLabel?: string;
|
|
21
|
+
/** The message to display when filtering returns no options */
|
|
22
|
+
noResults?: string;
|
|
23
|
+
/** Close the popover without changing the current selection */
|
|
24
|
+
close?: () => void;
|
|
19
25
|
/**
|
|
20
26
|
* A function to filter the options based on a query,
|
|
21
27
|
* if not provided, the options will be filtered by option label
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarComboboxOptions.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarCombobox/ScalarComboboxOptions.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ScalarComboboxOptions.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarCombobox/ScalarComboboxOptions.vue"],"names":[],"mappings":"AAiUA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,eAAe,EAErB,MAAM,SAAS,CAAA;AAGhB;;;;;;;;GAQG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY,GAAK,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,EAC1F,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WAggBO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB,CAAC;QA9ftD,6CAA6C;iBACpC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9B,sDAAsD;sBACxC,MAAM;QACpB,+CAA+C;qBAClC,MAAM;QACnB,+DAA+D;oBACnD,MAAM;QAClB,+DAA+D;gBACvD,MAAM,IAAI;QAClB;;;;;WAKG;mBACQ,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/B,qEAAqE;sBACvD,OAAO;;qBAwKV,CAAC,EAAE;;;;KAoU2E,CAAC,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC5J,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;UAEJ,2EAAoC;EAEvC,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;CAAI,CAAC;AACzF,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarComboboxOptions.vue.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxOptions.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Options component\n *\n * Renders the searchable option list for a combobox, including\n * filtering, keyboard navigation, and an optional \"add new\" action.\n *\n * @example\n * <ScalarComboboxOptions v-model=\"selected\" :options=\"options\" />\n */\nexport default {}\n</script>\n\n<!-- prettier-ignore-attribute generic -->\n<script\n setup\n lang=\"ts\"\n generic=\"O extends Option = Option, G extends OptionGroup<O> = OptionGroup<O>\">\nimport { filterByOptionLabel } from '@/components/ScalarCombobox/filter-by-option-label'\nimport { ScalarIconMagnifyingGlass, ScalarIconPlus } from '@scalar/icons'\nimport { computed, onMounted, ref, useId, watch } from 'vue'\n\nimport { ScalarListboxCheckbox } from '../ScalarListbox'\nimport ComboboxOption from './ScalarComboboxOption.vue'\nimport ComboboxOptionGroup from './ScalarComboboxOptionGroup.vue'\nimport {\n type ComboboxEmits,\n type ComboboxSlots,\n type FilterFunction,\n type Option,\n type OptionGroup,\n type OptionsOrGroups,\n isGroups,\n} from './types'\n\nconst {\n options: optionsOrGroups,\n placeholder,\n filterFn = filterByOptionLabel,\n multiselect,\n} = defineProps<{\n /** The options to display in the combobox */\n options: OptionsOrGroups<O, G>\n /** The placeholder text to display in the combobox */\n placeholder?: string\n /**\n * A function to filter the options based on a query,\n * if not provided, the options will be filtered by option label\n *\n * @see {@link FilterFunction} for more information\n */\n filterFn?: FilterFunction<O, G>\n /** Whether the combobox is in multiselect mode, defaults to false */\n multiselect?: boolean\n}>()\n\nconst emit = defineEmits<ComboboxEmits>()\n\nconst model = defineModel<O[]>({ default: () => [] })\n\nconst slots = defineSlots<Omit<ComboboxSlots<O, G>, 'default'>>()\n\ndefineOptions({ inheritAttrs: false })\n\n/** A unique ID for the combobox */\nconst id = `scalar-combobox-items-${useId()}`\n\n/** A static option entry for the \"Add a new option\" option */\nconst addOption: Option = { id: `${useId()}-add`, label: 'Add a new option' }\n\n/** Generate a unique ID for an option */\nfunction getOptionId(option: Option) {\n return `${id}-${option.id}`\n}\n\n/** A flat list of all options */\nconst options = computed<O[]>(() =>\n isGroups(optionsOrGroups)\n ? optionsOrGroups.flatMap((group) => group.options)\n : optionsOrGroups,\n)\n\n/** An list of all groups */\nconst groups = computed<G[]>(\n () =>\n isGroups(optionsOrGroups)\n ? optionsOrGroups // G extends OptionGroup<O>\n : /*\n We know G is an unextended OptionGroup<O> here because of the\n structure of the component props so we can cast it to G\n */\n [{ label: '', options: optionsOrGroups } as G], // G is OptionGroup<O>\n)\n\nconst query = ref<string>('')\nconst activeRef = ref<Option | undefined>(model.value?.[0] ?? options.value[0])\n\n// Clear the query on open and close\nonMounted(() => {\n // Clear the query\n query.value = ''\n\n // Set the active option to the selected option or the first option\n activeRef.value = model.value?.[0] ?? options.value[0]\n\n // Scroll to the selected option\n const selected = model.value[0]\n if (selected) {\n setTimeout(() => {\n const value = model.value[0]\n if (!value) {\n return\n }\n\n document\n ?.getElementById(getOptionId(value))\n ?.scrollIntoView({ block: 'nearest' })\n }, 10)\n }\n})\n\n// Set the top option as active when searching\nwatch(\n () => query.value,\n () => (activeRef.value = withAdd.value[0]),\n)\n\n/** The filtered list of options */\nconst filtered = computed<O[]>(() =>\n filterFn(query.value, options.value, groups.value),\n)\n\n/** The list of filtered options with the \"Add a new option\" option */\nconst withAdd = computed<Option[]>(() =>\n slots.add ? [...filtered.value, addOption] : filtered.value,\n)\n\nfunction toggleSelected(option: Option | undefined) {\n if (!option) {\n return\n }\n\n if (option.id === addOption.id) {\n addNew()\n return\n }\n\n if (multiselect) {\n // Remove from selection list\n if (model.value.some((o) => o.id === option.id)) {\n model.value = model.value.filter((o) => o.id !== option.id)\n }\n // Add to selection list\n else {\n model.value = [\n ...model.value,\n options.value.find((o) => o.id === option.id)!,\n ]\n }\n } else {\n // Set selection for single select mode\n model.value = [options.value.find((o) => o.id === option.id)!]\n }\n}\n\nfunction moveActive(dir: 1 | -1) {\n const list = withAdd.value\n\n // Find active index\n const activeIdx = list.findIndex(\n (option) => option.id === activeRef.value?.id,\n )\n\n // Calculate next index and exit if it's out of bounds\n const nextIdx = activeIdx + dir\n\n if (nextIdx < 0 || nextIdx > list.length - 1) {\n return\n }\n\n activeRef.value = list[nextIdx]! // We know it's in bounds from the check above\n\n if (!activeRef.value) {\n return\n }\n\n // Scroll to the active option\n document?.getElementById(getOptionId(activeRef.value))?.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n })\n}\n\nfunction addNew() {\n emit('add')\n query.value = ''\n}\n\n// Manual autofocus for the input\nconst input = ref<HTMLInputElement | null>(null)\n\n// This must be a setTimeout to ensure there is no scroll jump. nextTick does not work here.\nonMounted(() => setTimeout(() => input.value?.focus(), 0))\n</script>\n<template>\n <div class=\"relative flex\">\n <ScalarIconMagnifyingGlass\n class=\"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-c-3 size-4\" />\n <input\n ref=\"input\"\n v-model=\"query\"\n :aria-activedescendant=\"activeRef ? getOptionId(activeRef) : undefined\"\n aria-autocomplete=\"list\"\n :aria-controls=\"id\"\n class=\"min-w-0 flex-1 rounded border-0 py-2.5 pl-8 pr-3 leading-none text-c-1 -outline-offset-1\"\n data-1p-ignore\n :placeholder\n role=\"combobox\"\n tabindex=\"0\"\n type=\"text\"\n @keydown.down.prevent=\"moveActive(1)\"\n @keydown.enter.prevent=\"activeRef && toggleSelected(activeRef)\"\n @keydown.up.prevent=\"moveActive(-1)\" />\n </div>\n <ul\n v-show=\"filtered.length || slots.add\"\n :id=\"id\"\n :aria-multiselectable=\"multiselect\"\n class=\"border-t p-0.75 custom-scroll overscroll-contain flex-1 min-h-0\"\n role=\"listbox\"\n tabindex=\"-1\">\n <ComboboxOptionGroup\n v-for=\"(group, i) in groups\"\n :id=\"`${id}-group-${i}`\"\n :key=\"i\"\n :hidden=\"\n // Only show the group label if there are some results\n !group.options.some((o) => filtered.some((f) => f.id === o.id)) ||\n // And it has a label\n !group.label\n \">\n <template #label>\n <slot\n v-if=\"$slots.group\"\n :group\n name=\"group\" />\n <template v-else>\n {{ group.label }}\n </template>\n </template>\n <template\n v-for=\"option in filtered\"\n :key=\"option.id\">\n <ComboboxOption\n v-if=\"group.options.some((o) => o.id === option.id)\"\n :id=\"getOptionId(option)\"\n v-slot=\"{ active, selected }\"\n :active=\"activeRef?.id === option.id\"\n :selected=\"model.some((o) => o.id === option.id)\"\n @click=\"toggleSelected(option)\"\n @mousedown.prevent\n @mouseenter=\"activeRef = option\">\n <slot\n v-if=\"$slots.option\"\n :active\n name=\"option\"\n :option\n :selected />\n <template v-else>\n <ScalarListboxCheckbox\n :multiselect\n :selected=\"model.some((o) => o.id === option.id)\" />\n <span class=\"inline-block min-w-0 flex-1 truncate text-c-1\">\n {{ option.label }}\n </span>\n </template>\n </ComboboxOption>\n </template>\n </ComboboxOptionGroup>\n <ComboboxOption\n v-if=\"slots.add\"\n :id=\"getOptionId(addOption)\"\n v-slot=\"{ active }\"\n :active=\"activeRef?.id === addOption.id\"\n @click=\"addNew\"\n @mousedown.prevent\n @mouseenter=\"activeRef = addOption\">\n <ScalarIconPlus class=\"size-4 p-px\" />\n <slot\n :active\n name=\"add\" />\n </ComboboxOption>\n </ul>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarComboboxOptions.vue.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxOptions.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Options component\n *\n * Renders the searchable option list for a combobox, including\n * filtering, keyboard navigation, and an optional \"add new\" action.\n *\n * @example\n * <ScalarComboboxOptions v-model=\"selected\" :options=\"options\" />\n */\nexport default {}\n</script>\n\n<!-- prettier-ignore-attribute generic -->\n<script\n setup\n lang=\"ts\"\n generic=\"O extends Option = Option, G extends OptionGroup<O> = OptionGroup<O>\">\nimport { filterByOptionLabel } from '@/components/ScalarCombobox/filter-by-option-label'\nimport { ScalarIconMagnifyingGlass, ScalarIconPlus } from '@scalar/icons'\nimport { computed, onMounted, ref, useId, watch } from 'vue'\n\nimport { ScalarListboxCheckbox } from '../ScalarListbox'\nimport ComboboxOption from './ScalarComboboxOption.vue'\nimport ComboboxOptionGroup from './ScalarComboboxOptionGroup.vue'\nimport {\n type ComboboxEmits,\n type ComboboxSlots,\n type FilterFunction,\n type Option,\n type OptionGroup,\n type OptionsOrGroups,\n isGroups,\n} from './types'\n\nconst {\n options: optionsOrGroups,\n placeholder,\n inputLabel,\n noResults,\n close,\n filterFn = filterByOptionLabel,\n multiselect,\n} = defineProps<{\n /** The options to display in the combobox */\n options: OptionsOrGroups<O, G>\n /** The placeholder text to display in the combobox */\n placeholder?: string\n /** An accessible label for the search input */\n inputLabel?: string\n /** The message to display when filtering returns no options */\n noResults?: string\n /** Close the popover without changing the current selection */\n close?: () => void\n /**\n * A function to filter the options based on a query,\n * if not provided, the options will be filtered by option label\n *\n * @see {@link FilterFunction} for more information\n */\n filterFn?: FilterFunction<O, G>\n /** Whether the combobox is in multiselect mode, defaults to false */\n multiselect?: boolean\n}>()\n\nconst emit = defineEmits<ComboboxEmits>()\n\nconst model = defineModel<O[]>({ default: () => [] })\n\nconst slots = defineSlots<Omit<ComboboxSlots<O, G>, 'default'>>()\n\ndefineOptions({ inheritAttrs: false })\n\n/** A unique ID for the combobox */\nconst id = `scalar-combobox-items-${useId()}`\n\n/** A static option entry for the \"Add a new option\" option */\nconst addOption: Option = { id: `${useId()}-add`, label: 'Add a new option' }\n\n/** Generate a unique ID for an option */\nfunction getOptionId(option: Option) {\n return `${id}-${option.id}`\n}\n\n/** A flat list of all options */\nconst options = computed<O[]>(() =>\n isGroups(optionsOrGroups)\n ? optionsOrGroups.flatMap((group) => group.options)\n : optionsOrGroups,\n)\n\n/** An list of all groups */\nconst groups = computed<G[]>(\n () =>\n isGroups(optionsOrGroups)\n ? optionsOrGroups // G extends OptionGroup<O>\n : /*\n We know G is an unextended OptionGroup<O> here because of the\n structure of the component props so we can cast it to G\n */\n [{ label: '', options: optionsOrGroups } as G], // G is OptionGroup<O>\n)\n\nconst query = ref<string>('')\nconst activeRef = ref<Option | undefined>(model.value?.[0] ?? options.value[0])\n\n// Clear the query on open and close\nonMounted(() => {\n // Clear the query\n query.value = ''\n\n // Set the active option to the selected option or the first option\n activeRef.value = model.value?.[0] ?? options.value[0]\n\n // Scroll to the selected option\n const selected = model.value[0]\n if (selected) {\n setTimeout(() => {\n const value = model.value[0]\n if (!value) {\n return\n }\n\n document\n ?.getElementById(getOptionId(value))\n ?.scrollIntoView({ block: 'nearest' })\n }, 10)\n }\n})\n\n// Set the top option as active when searching\nwatch(\n () => query.value,\n () => (activeRef.value = withAdd.value[0]),\n)\n\n/** The filtered list of options */\nconst filtered = computed<O[]>(() =>\n filterFn(query.value, options.value, groups.value),\n)\n\n/** The list of filtered options with the \"Add a new option\" option */\nconst withAdd = computed<Option[]>(() =>\n slots.add ? [...filtered.value, addOption] : filtered.value,\n)\n\nfunction toggleSelected(option: Option | undefined) {\n if (!option) {\n return\n }\n\n if (option.id === addOption.id) {\n addNew()\n return\n }\n\n if (multiselect) {\n // Remove from selection list\n if (model.value.some((o) => o.id === option.id)) {\n model.value = model.value.filter((o) => o.id !== option.id)\n }\n // Add to selection list\n else {\n model.value = [\n ...model.value,\n options.value.find((o) => o.id === option.id)!,\n ]\n }\n } else {\n // Set selection for single select mode\n model.value = [options.value.find((o) => o.id === option.id)!]\n }\n}\n\nfunction moveActive(dir: 1 | -1) {\n const list = withAdd.value\n\n // Find active index\n const activeIdx = list.findIndex(\n (option) => option.id === activeRef.value?.id,\n )\n\n // Calculate next index and exit if it's out of bounds\n const nextIdx = activeIdx + dir\n\n if (nextIdx < 0 || nextIdx > list.length - 1) {\n return\n }\n\n activeRef.value = list[nextIdx]! // We know it's in bounds from the check above\n\n if (!activeRef.value) {\n return\n }\n\n // Scroll to the active option\n document?.getElementById(getOptionId(activeRef.value))?.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n })\n}\n\nfunction addNew() {\n emit('add')\n query.value = ''\n}\n\n// Manual autofocus for the input\nconst input = ref<HTMLInputElement | null>(null)\n\n// This must be a setTimeout to ensure there is no scroll jump. nextTick does not work here.\nonMounted(() => setTimeout(() => input.value?.focus(), 0))\n</script>\n<template>\n <div class=\"relative flex\">\n <ScalarIconMagnifyingGlass\n class=\"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-c-3 size-4\" />\n <input\n ref=\"input\"\n v-model=\"query\"\n :aria-activedescendant=\"activeRef ? getOptionId(activeRef) : undefined\"\n aria-autocomplete=\"list\"\n :aria-controls=\"id\"\n :aria-label=\"inputLabel\"\n class=\"min-w-0 flex-1 rounded border-0 py-2.5 pl-8 pr-3 leading-none text-c-1 -outline-offset-1\"\n data-1p-ignore\n :placeholder\n role=\"combobox\"\n tabindex=\"0\"\n type=\"text\"\n @keydown.down.prevent=\"moveActive(1)\"\n @keydown.enter.prevent=\"activeRef && toggleSelected(activeRef)\"\n @keydown.esc.prevent=\"close?.()\"\n @keydown.up.prevent=\"moveActive(-1)\" />\n </div>\n <ul\n v-show=\"filtered.length || slots.add || noResults\"\n :id=\"id\"\n :aria-multiselectable=\"multiselect\"\n class=\"border-t p-0.75 custom-scroll overscroll-contain flex-1 min-h-0\"\n role=\"listbox\"\n tabindex=\"-1\">\n <li\n v-if=\"!filtered.length && !slots.add && noResults\"\n class=\"text-c-3 px-2.5 py-2\"\n role=\"status\">\n {{ noResults }}\n </li>\n <ComboboxOptionGroup\n v-for=\"(group, i) in groups\"\n :id=\"`${id}-group-${i}`\"\n :key=\"i\"\n :hidden=\"\n // Only show the group label if there are some results\n !group.options.some((o) => filtered.some((f) => f.id === o.id)) ||\n // And it has a label\n !group.label\n \">\n <template #label>\n <slot\n v-if=\"$slots.group\"\n :group\n name=\"group\" />\n <template v-else>\n {{ group.label }}\n </template>\n </template>\n <template\n v-for=\"option in filtered\"\n :key=\"option.id\">\n <ComboboxOption\n v-if=\"group.options.some((o) => o.id === option.id)\"\n :id=\"getOptionId(option)\"\n v-slot=\"{ active, selected }\"\n :active=\"activeRef?.id === option.id\"\n :selected=\"model.some((o) => o.id === option.id)\"\n @click=\"toggleSelected(option)\"\n @mousedown.prevent\n @mouseenter=\"activeRef = option\">\n <slot\n v-if=\"$slots.option\"\n :active\n name=\"option\"\n :option\n :selected />\n <template v-else>\n <ScalarListboxCheckbox\n :multiselect\n :selected=\"model.some((o) => o.id === option.id)\" />\n <span class=\"inline-block min-w-0 flex-1 truncate text-c-1\">\n {{ option.label }}\n </span>\n </template>\n </ComboboxOption>\n </template>\n </ComboboxOptionGroup>\n <ComboboxOption\n v-if=\"slots.add\"\n :id=\"getOptionId(addOption)\"\n v-slot=\"{ active }\"\n :active=\"activeRef?.id === addOption.id\"\n @click=\"addNew\"\n @mousedown.prevent\n @mouseenter=\"activeRef = addOption\">\n <ScalarIconPlus class=\"size-4 p-px\" />\n <slot\n :active\n name=\"add\" />\n </ComboboxOption>\n </ul>\n</template>\n"],"mappings":""}
|
|
@@ -7,15 +7,27 @@ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock
|
|
|
7
7
|
import { ScalarIconMagnifyingGlass, ScalarIconPlus } from "@scalar/icons";
|
|
8
8
|
//#region src/components/ScalarCombobox/ScalarComboboxOptions.vue?vue&type=script&setup=true&lang.ts
|
|
9
9
|
var _hoisted_1 = { class: "relative flex" };
|
|
10
|
-
var _hoisted_2 = [
|
|
10
|
+
var _hoisted_2 = [
|
|
11
|
+
"aria-activedescendant",
|
|
12
|
+
"aria-label",
|
|
13
|
+
"placeholder"
|
|
14
|
+
];
|
|
11
15
|
var _hoisted_3 = ["aria-multiselectable"];
|
|
12
|
-
var _hoisted_4 = {
|
|
16
|
+
var _hoisted_4 = {
|
|
17
|
+
key: 0,
|
|
18
|
+
class: "text-c-3 px-2.5 py-2",
|
|
19
|
+
role: "status"
|
|
20
|
+
};
|
|
21
|
+
var _hoisted_5 = { class: "inline-block min-w-0 flex-1 truncate text-c-1" };
|
|
13
22
|
var ScalarComboboxOptions_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
14
23
|
inheritAttrs: false,
|
|
15
24
|
__name: "ScalarComboboxOptions",
|
|
16
25
|
props: /*@__PURE__*/ mergeModels({
|
|
17
26
|
options: {},
|
|
18
27
|
placeholder: {},
|
|
28
|
+
inputLabel: {},
|
|
29
|
+
noResults: {},
|
|
30
|
+
close: { type: Function },
|
|
19
31
|
filterFn: {
|
|
20
32
|
type: Function,
|
|
21
33
|
default: filterByOptionLabel
|
|
@@ -99,6 +111,7 @@ var ScalarComboboxOptions_vue_vue_type_script_setup_true_lang_default = /*@__PUR
|
|
|
99
111
|
"aria-activedescendant": activeRef.value ? getOptionId(activeRef.value) : void 0,
|
|
100
112
|
"aria-autocomplete": "list",
|
|
101
113
|
"aria-controls": id,
|
|
114
|
+
"aria-label": __props.inputLabel,
|
|
102
115
|
class: "min-w-0 flex-1 rounded border-0 py-2.5 pl-8 pr-3 leading-none text-c-1 -outline-offset-1",
|
|
103
116
|
"data-1p-ignore": "",
|
|
104
117
|
placeholder: __props.placeholder,
|
|
@@ -108,7 +121,8 @@ var ScalarComboboxOptions_vue_vue_type_script_setup_true_lang_default = /*@__PUR
|
|
|
108
121
|
onKeydown: [
|
|
109
122
|
_cache[1] || (_cache[1] = withKeys(withModifiers(($event) => moveActive(1), ["prevent"]), ["down"])),
|
|
110
123
|
_cache[2] || (_cache[2] = withKeys(withModifiers(($event) => activeRef.value && toggleSelected(activeRef.value), ["prevent"]), ["enter"])),
|
|
111
|
-
_cache[3] || (_cache[3] = withKeys(withModifiers(($event) =>
|
|
124
|
+
_cache[3] || (_cache[3] = withKeys(withModifiers(($event) => __props.close?.(), ["prevent"]), ["esc"])),
|
|
125
|
+
_cache[4] || (_cache[4] = withKeys(withModifiers(($event) => moveActive(-1), ["prevent"]), ["up"]))
|
|
112
126
|
]
|
|
113
127
|
}, null, 40, _hoisted_2), [[vModelText, query.value]])]), withDirectives(createElementVNode("ul", {
|
|
114
128
|
id,
|
|
@@ -116,53 +130,57 @@ var ScalarComboboxOptions_vue_vue_type_script_setup_true_lang_default = /*@__PUR
|
|
|
116
130
|
class: "border-t p-0.75 custom-scroll overscroll-contain flex-1 min-h-0",
|
|
117
131
|
role: "listbox",
|
|
118
132
|
tabindex: "-1"
|
|
119
|
-
}, [
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
133
|
+
}, [
|
|
134
|
+
!filtered.value.length && !slots.add && __props.noResults ? (openBlock(), createElementBlock("li", _hoisted_4, toDisplayString(__props.noResults), 1)) : createCommentVNode("", true),
|
|
135
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(groups.value, (group, i) => {
|
|
136
|
+
return openBlock(), createBlock(ScalarComboboxOptionGroup_default, {
|
|
137
|
+
id: `${id}-group-${i}`,
|
|
138
|
+
key: i,
|
|
139
|
+
hidden: !group.options.some((o) => filtered.value.some((f) => f.id === o.id)) || !group.label
|
|
140
|
+
}, {
|
|
141
|
+
label: withCtx(() => [_ctx.$slots.group ? renderSlot(_ctx.$slots, "group", { group }, void 0, void 0, 0) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(group.label), 1)], 64))]),
|
|
142
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(filtered.value, (option) => {
|
|
143
|
+
return openBlock(), createElementBlock(Fragment, { key: option.id }, [group.options.some((o) => o.id === option.id) ? (openBlock(), createBlock(ScalarComboboxOption_default, {
|
|
144
|
+
key: 0,
|
|
145
|
+
id: getOptionId(option),
|
|
146
|
+
active: activeRef.value?.id === option.id,
|
|
147
|
+
selected: model.value.some((o) => o.id === option.id),
|
|
148
|
+
onClick: ($event) => toggleSelected(option),
|
|
149
|
+
onMousedown: _cache[5] || (_cache[5] = withModifiers(() => {}, ["prevent"])),
|
|
150
|
+
onMouseenter: ($event) => activeRef.value = option
|
|
151
|
+
}, {
|
|
152
|
+
default: withCtx(({ active, selected }) => [_ctx.$slots.option ? renderSlot(_ctx.$slots, "option", {
|
|
153
|
+
active,
|
|
154
|
+
option,
|
|
155
|
+
selected
|
|
156
|
+
}, void 0, void 0, 0) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createVNode(unref(ScalarListboxCheckbox_default), {
|
|
157
|
+
multiselect: __props.multiselect,
|
|
158
|
+
selected: model.value.some((o) => o.id === option.id)
|
|
159
|
+
}, null, 8, ["multiselect", "selected"]), createElementVNode("span", _hoisted_5, toDisplayString(option.label), 1)], 64))]),
|
|
160
|
+
_: 2
|
|
161
|
+
}, 1032, [
|
|
162
|
+
"id",
|
|
163
|
+
"active",
|
|
164
|
+
"selected",
|
|
165
|
+
"onClick",
|
|
166
|
+
"onMouseenter"
|
|
167
|
+
])) : createCommentVNode("", true)], 64);
|
|
168
|
+
}), 128))]),
|
|
169
|
+
_: 2
|
|
170
|
+
}, 1032, ["id", "hidden"]);
|
|
171
|
+
}), 128)),
|
|
172
|
+
slots.add ? (openBlock(), createBlock(ScalarComboboxOption_default, {
|
|
173
|
+
key: 1,
|
|
174
|
+
id: getOptionId(addOption),
|
|
175
|
+
active: activeRef.value?.id === addOption.id,
|
|
176
|
+
onClick: addNew,
|
|
177
|
+
onMousedown: _cache[6] || (_cache[6] = withModifiers(() => {}, ["prevent"])),
|
|
178
|
+
onMouseenter: _cache[7] || (_cache[7] = ($event) => activeRef.value = addOption)
|
|
124
179
|
}, {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
id: getOptionId(option),
|
|
130
|
-
active: activeRef.value?.id === option.id,
|
|
131
|
-
selected: model.value.some((o) => o.id === option.id),
|
|
132
|
-
onClick: ($event) => toggleSelected(option),
|
|
133
|
-
onMousedown: _cache[4] || (_cache[4] = withModifiers(() => {}, ["prevent"])),
|
|
134
|
-
onMouseenter: ($event) => activeRef.value = option
|
|
135
|
-
}, {
|
|
136
|
-
default: withCtx(({ active, selected }) => [_ctx.$slots.option ? renderSlot(_ctx.$slots, "option", {
|
|
137
|
-
active,
|
|
138
|
-
option,
|
|
139
|
-
selected
|
|
140
|
-
}, void 0, void 0, 0) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createVNode(unref(ScalarListboxCheckbox_default), {
|
|
141
|
-
multiselect: __props.multiselect,
|
|
142
|
-
selected: model.value.some((o) => o.id === option.id)
|
|
143
|
-
}, null, 8, ["multiselect", "selected"]), createElementVNode("span", _hoisted_4, toDisplayString(option.label), 1)], 64))]),
|
|
144
|
-
_: 2
|
|
145
|
-
}, 1032, [
|
|
146
|
-
"id",
|
|
147
|
-
"active",
|
|
148
|
-
"selected",
|
|
149
|
-
"onClick",
|
|
150
|
-
"onMouseenter"
|
|
151
|
-
])) : createCommentVNode("", true)], 64);
|
|
152
|
-
}), 128))]),
|
|
153
|
-
_: 2
|
|
154
|
-
}, 1032, ["id", "hidden"]);
|
|
155
|
-
}), 128)), slots.add ? (openBlock(), createBlock(ScalarComboboxOption_default, {
|
|
156
|
-
key: 0,
|
|
157
|
-
id: getOptionId(addOption),
|
|
158
|
-
active: activeRef.value?.id === addOption.id,
|
|
159
|
-
onClick: addNew,
|
|
160
|
-
onMousedown: _cache[5] || (_cache[5] = withModifiers(() => {}, ["prevent"])),
|
|
161
|
-
onMouseenter: _cache[6] || (_cache[6] = ($event) => activeRef.value = addOption)
|
|
162
|
-
}, {
|
|
163
|
-
default: withCtx(({ active }) => [createVNode(unref(ScalarIconPlus), { class: "size-4 p-px" }), renderSlot(_ctx.$slots, "add", { active })]),
|
|
164
|
-
_: 3
|
|
165
|
-
}, 8, ["id", "active"])) : createCommentVNode("", true)], 8, _hoisted_3), [[vShow, filtered.value.length || slots.add]])], 64);
|
|
180
|
+
default: withCtx(({ active }) => [createVNode(unref(ScalarIconPlus), { class: "size-4 p-px" }), renderSlot(_ctx.$slots, "add", { active })]),
|
|
181
|
+
_: 3
|
|
182
|
+
}, 8, ["id", "active"])) : createCommentVNode("", true)
|
|
183
|
+
], 8, _hoisted_3), [[vShow, filtered.value.length || slots.add || __props.noResults]])], 64);
|
|
166
184
|
};
|
|
167
185
|
}
|
|
168
186
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarComboboxOptions.vue.script.js","names":["$slots"],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxOptions.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Options component\n *\n * Renders the searchable option list for a combobox, including\n * filtering, keyboard navigation, and an optional \"add new\" action.\n *\n * @example\n * <ScalarComboboxOptions v-model=\"selected\" :options=\"options\" />\n */\nexport default {}\n</script>\n\n<!-- prettier-ignore-attribute generic -->\n<script\n setup\n lang=\"ts\"\n generic=\"O extends Option = Option, G extends OptionGroup<O> = OptionGroup<O>\">\nimport { filterByOptionLabel } from '@/components/ScalarCombobox/filter-by-option-label'\nimport { ScalarIconMagnifyingGlass, ScalarIconPlus } from '@scalar/icons'\nimport { computed, onMounted, ref, useId, watch } from 'vue'\n\nimport { ScalarListboxCheckbox } from '../ScalarListbox'\nimport ComboboxOption from './ScalarComboboxOption.vue'\nimport ComboboxOptionGroup from './ScalarComboboxOptionGroup.vue'\nimport {\n type ComboboxEmits,\n type ComboboxSlots,\n type FilterFunction,\n type Option,\n type OptionGroup,\n type OptionsOrGroups,\n isGroups,\n} from './types'\n\nconst {\n options: optionsOrGroups,\n placeholder,\n filterFn = filterByOptionLabel,\n multiselect,\n} = defineProps<{\n /** The options to display in the combobox */\n options: OptionsOrGroups<O, G>\n /** The placeholder text to display in the combobox */\n placeholder?: string\n /**\n * A function to filter the options based on a query,\n * if not provided, the options will be filtered by option label\n *\n * @see {@link FilterFunction} for more information\n */\n filterFn?: FilterFunction<O, G>\n /** Whether the combobox is in multiselect mode, defaults to false */\n multiselect?: boolean\n}>()\n\nconst emit = defineEmits<ComboboxEmits>()\n\nconst model = defineModel<O[]>({ default: () => [] })\n\nconst slots = defineSlots<Omit<ComboboxSlots<O, G>, 'default'>>()\n\ndefineOptions({ inheritAttrs: false })\n\n/** A unique ID for the combobox */\nconst id = `scalar-combobox-items-${useId()}`\n\n/** A static option entry for the \"Add a new option\" option */\nconst addOption: Option = { id: `${useId()}-add`, label: 'Add a new option' }\n\n/** Generate a unique ID for an option */\nfunction getOptionId(option: Option) {\n return `${id}-${option.id}`\n}\n\n/** A flat list of all options */\nconst options = computed<O[]>(() =>\n isGroups(optionsOrGroups)\n ? optionsOrGroups.flatMap((group) => group.options)\n : optionsOrGroups,\n)\n\n/** An list of all groups */\nconst groups = computed<G[]>(\n () =>\n isGroups(optionsOrGroups)\n ? optionsOrGroups // G extends OptionGroup<O>\n : /*\n We know G is an unextended OptionGroup<O> here because of the\n structure of the component props so we can cast it to G\n */\n [{ label: '', options: optionsOrGroups } as G], // G is OptionGroup<O>\n)\n\nconst query = ref<string>('')\nconst activeRef = ref<Option | undefined>(model.value?.[0] ?? options.value[0])\n\n// Clear the query on open and close\nonMounted(() => {\n // Clear the query\n query.value = ''\n\n // Set the active option to the selected option or the first option\n activeRef.value = model.value?.[0] ?? options.value[0]\n\n // Scroll to the selected option\n const selected = model.value[0]\n if (selected) {\n setTimeout(() => {\n const value = model.value[0]\n if (!value) {\n return\n }\n\n document\n ?.getElementById(getOptionId(value))\n ?.scrollIntoView({ block: 'nearest' })\n }, 10)\n }\n})\n\n// Set the top option as active when searching\nwatch(\n () => query.value,\n () => (activeRef.value = withAdd.value[0]),\n)\n\n/** The filtered list of options */\nconst filtered = computed<O[]>(() =>\n filterFn(query.value, options.value, groups.value),\n)\n\n/** The list of filtered options with the \"Add a new option\" option */\nconst withAdd = computed<Option[]>(() =>\n slots.add ? [...filtered.value, addOption] : filtered.value,\n)\n\nfunction toggleSelected(option: Option | undefined) {\n if (!option) {\n return\n }\n\n if (option.id === addOption.id) {\n addNew()\n return\n }\n\n if (multiselect) {\n // Remove from selection list\n if (model.value.some((o) => o.id === option.id)) {\n model.value = model.value.filter((o) => o.id !== option.id)\n }\n // Add to selection list\n else {\n model.value = [\n ...model.value,\n options.value.find((o) => o.id === option.id)!,\n ]\n }\n } else {\n // Set selection for single select mode\n model.value = [options.value.find((o) => o.id === option.id)!]\n }\n}\n\nfunction moveActive(dir: 1 | -1) {\n const list = withAdd.value\n\n // Find active index\n const activeIdx = list.findIndex(\n (option) => option.id === activeRef.value?.id,\n )\n\n // Calculate next index and exit if it's out of bounds\n const nextIdx = activeIdx + dir\n\n if (nextIdx < 0 || nextIdx > list.length - 1) {\n return\n }\n\n activeRef.value = list[nextIdx]! // We know it's in bounds from the check above\n\n if (!activeRef.value) {\n return\n }\n\n // Scroll to the active option\n document?.getElementById(getOptionId(activeRef.value))?.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n })\n}\n\nfunction addNew() {\n emit('add')\n query.value = ''\n}\n\n// Manual autofocus for the input\nconst input = ref<HTMLInputElement | null>(null)\n\n// This must be a setTimeout to ensure there is no scroll jump. nextTick does not work here.\nonMounted(() => setTimeout(() => input.value?.focus(), 0))\n</script>\n<template>\n <div class=\"relative flex\">\n <ScalarIconMagnifyingGlass\n class=\"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-c-3 size-4\" />\n <input\n ref=\"input\"\n v-model=\"query\"\n :aria-activedescendant=\"activeRef ? getOptionId(activeRef) : undefined\"\n aria-autocomplete=\"list\"\n :aria-controls=\"id\"\n class=\"min-w-0 flex-1 rounded border-0 py-2.5 pl-8 pr-3 leading-none text-c-1 -outline-offset-1\"\n data-1p-ignore\n :placeholder\n role=\"combobox\"\n tabindex=\"0\"\n type=\"text\"\n @keydown.down.prevent=\"moveActive(1)\"\n @keydown.enter.prevent=\"activeRef && toggleSelected(activeRef)\"\n @keydown.up.prevent=\"moveActive(-1)\" />\n </div>\n <ul\n v-show=\"filtered.length || slots.add\"\n :id=\"id\"\n :aria-multiselectable=\"multiselect\"\n class=\"border-t p-0.75 custom-scroll overscroll-contain flex-1 min-h-0\"\n role=\"listbox\"\n tabindex=\"-1\">\n <ComboboxOptionGroup\n v-for=\"(group, i) in groups\"\n :id=\"`${id}-group-${i}`\"\n :key=\"i\"\n :hidden=\"\n // Only show the group label if there are some results\n !group.options.some((o) => filtered.some((f) => f.id === o.id)) ||\n // And it has a label\n !group.label\n \">\n <template #label>\n <slot\n v-if=\"$slots.group\"\n :group\n name=\"group\" />\n <template v-else>\n {{ group.label }}\n </template>\n </template>\n <template\n v-for=\"option in filtered\"\n :key=\"option.id\">\n <ComboboxOption\n v-if=\"group.options.some((o) => o.id === option.id)\"\n :id=\"getOptionId(option)\"\n v-slot=\"{ active, selected }\"\n :active=\"activeRef?.id === option.id\"\n :selected=\"model.some((o) => o.id === option.id)\"\n @click=\"toggleSelected(option)\"\n @mousedown.prevent\n @mouseenter=\"activeRef = option\">\n <slot\n v-if=\"$slots.option\"\n :active\n name=\"option\"\n :option\n :selected />\n <template v-else>\n <ScalarListboxCheckbox\n :multiselect\n :selected=\"model.some((o) => o.id === option.id)\" />\n <span class=\"inline-block min-w-0 flex-1 truncate text-c-1\">\n {{ option.label }}\n </span>\n </template>\n </ComboboxOption>\n </template>\n </ComboboxOptionGroup>\n <ComboboxOption\n v-if=\"slots.add\"\n :id=\"getOptionId(addOption)\"\n v-slot=\"{ active }\"\n :active=\"activeRef?.id === addOption.id\"\n @click=\"addNew\"\n @mousedown.prevent\n @mouseenter=\"activeRef = addOption\">\n <ScalarIconPlus class=\"size-4 p-px\" />\n <slot\n :active\n name=\"add\" />\n </ComboboxOption>\n </ul>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ScalarComboboxOptions.vue.script.js","names":["$slots"],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxOptions.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Options component\n *\n * Renders the searchable option list for a combobox, including\n * filtering, keyboard navigation, and an optional \"add new\" action.\n *\n * @example\n * <ScalarComboboxOptions v-model=\"selected\" :options=\"options\" />\n */\nexport default {}\n</script>\n\n<!-- prettier-ignore-attribute generic -->\n<script\n setup\n lang=\"ts\"\n generic=\"O extends Option = Option, G extends OptionGroup<O> = OptionGroup<O>\">\nimport { filterByOptionLabel } from '@/components/ScalarCombobox/filter-by-option-label'\nimport { ScalarIconMagnifyingGlass, ScalarIconPlus } from '@scalar/icons'\nimport { computed, onMounted, ref, useId, watch } from 'vue'\n\nimport { ScalarListboxCheckbox } from '../ScalarListbox'\nimport ComboboxOption from './ScalarComboboxOption.vue'\nimport ComboboxOptionGroup from './ScalarComboboxOptionGroup.vue'\nimport {\n type ComboboxEmits,\n type ComboboxSlots,\n type FilterFunction,\n type Option,\n type OptionGroup,\n type OptionsOrGroups,\n isGroups,\n} from './types'\n\nconst {\n options: optionsOrGroups,\n placeholder,\n inputLabel,\n noResults,\n close,\n filterFn = filterByOptionLabel,\n multiselect,\n} = defineProps<{\n /** The options to display in the combobox */\n options: OptionsOrGroups<O, G>\n /** The placeholder text to display in the combobox */\n placeholder?: string\n /** An accessible label for the search input */\n inputLabel?: string\n /** The message to display when filtering returns no options */\n noResults?: string\n /** Close the popover without changing the current selection */\n close?: () => void\n /**\n * A function to filter the options based on a query,\n * if not provided, the options will be filtered by option label\n *\n * @see {@link FilterFunction} for more information\n */\n filterFn?: FilterFunction<O, G>\n /** Whether the combobox is in multiselect mode, defaults to false */\n multiselect?: boolean\n}>()\n\nconst emit = defineEmits<ComboboxEmits>()\n\nconst model = defineModel<O[]>({ default: () => [] })\n\nconst slots = defineSlots<Omit<ComboboxSlots<O, G>, 'default'>>()\n\ndefineOptions({ inheritAttrs: false })\n\n/** A unique ID for the combobox */\nconst id = `scalar-combobox-items-${useId()}`\n\n/** A static option entry for the \"Add a new option\" option */\nconst addOption: Option = { id: `${useId()}-add`, label: 'Add a new option' }\n\n/** Generate a unique ID for an option */\nfunction getOptionId(option: Option) {\n return `${id}-${option.id}`\n}\n\n/** A flat list of all options */\nconst options = computed<O[]>(() =>\n isGroups(optionsOrGroups)\n ? optionsOrGroups.flatMap((group) => group.options)\n : optionsOrGroups,\n)\n\n/** An list of all groups */\nconst groups = computed<G[]>(\n () =>\n isGroups(optionsOrGroups)\n ? optionsOrGroups // G extends OptionGroup<O>\n : /*\n We know G is an unextended OptionGroup<O> here because of the\n structure of the component props so we can cast it to G\n */\n [{ label: '', options: optionsOrGroups } as G], // G is OptionGroup<O>\n)\n\nconst query = ref<string>('')\nconst activeRef = ref<Option | undefined>(model.value?.[0] ?? options.value[0])\n\n// Clear the query on open and close\nonMounted(() => {\n // Clear the query\n query.value = ''\n\n // Set the active option to the selected option or the first option\n activeRef.value = model.value?.[0] ?? options.value[0]\n\n // Scroll to the selected option\n const selected = model.value[0]\n if (selected) {\n setTimeout(() => {\n const value = model.value[0]\n if (!value) {\n return\n }\n\n document\n ?.getElementById(getOptionId(value))\n ?.scrollIntoView({ block: 'nearest' })\n }, 10)\n }\n})\n\n// Set the top option as active when searching\nwatch(\n () => query.value,\n () => (activeRef.value = withAdd.value[0]),\n)\n\n/** The filtered list of options */\nconst filtered = computed<O[]>(() =>\n filterFn(query.value, options.value, groups.value),\n)\n\n/** The list of filtered options with the \"Add a new option\" option */\nconst withAdd = computed<Option[]>(() =>\n slots.add ? [...filtered.value, addOption] : filtered.value,\n)\n\nfunction toggleSelected(option: Option | undefined) {\n if (!option) {\n return\n }\n\n if (option.id === addOption.id) {\n addNew()\n return\n }\n\n if (multiselect) {\n // Remove from selection list\n if (model.value.some((o) => o.id === option.id)) {\n model.value = model.value.filter((o) => o.id !== option.id)\n }\n // Add to selection list\n else {\n model.value = [\n ...model.value,\n options.value.find((o) => o.id === option.id)!,\n ]\n }\n } else {\n // Set selection for single select mode\n model.value = [options.value.find((o) => o.id === option.id)!]\n }\n}\n\nfunction moveActive(dir: 1 | -1) {\n const list = withAdd.value\n\n // Find active index\n const activeIdx = list.findIndex(\n (option) => option.id === activeRef.value?.id,\n )\n\n // Calculate next index and exit if it's out of bounds\n const nextIdx = activeIdx + dir\n\n if (nextIdx < 0 || nextIdx > list.length - 1) {\n return\n }\n\n activeRef.value = list[nextIdx]! // We know it's in bounds from the check above\n\n if (!activeRef.value) {\n return\n }\n\n // Scroll to the active option\n document?.getElementById(getOptionId(activeRef.value))?.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n })\n}\n\nfunction addNew() {\n emit('add')\n query.value = ''\n}\n\n// Manual autofocus for the input\nconst input = ref<HTMLInputElement | null>(null)\n\n// This must be a setTimeout to ensure there is no scroll jump. nextTick does not work here.\nonMounted(() => setTimeout(() => input.value?.focus(), 0))\n</script>\n<template>\n <div class=\"relative flex\">\n <ScalarIconMagnifyingGlass\n class=\"pointer-events-none absolute left-2.5 top-1/2 -translate-y-1/2 text-c-3 size-4\" />\n <input\n ref=\"input\"\n v-model=\"query\"\n :aria-activedescendant=\"activeRef ? getOptionId(activeRef) : undefined\"\n aria-autocomplete=\"list\"\n :aria-controls=\"id\"\n :aria-label=\"inputLabel\"\n class=\"min-w-0 flex-1 rounded border-0 py-2.5 pl-8 pr-3 leading-none text-c-1 -outline-offset-1\"\n data-1p-ignore\n :placeholder\n role=\"combobox\"\n tabindex=\"0\"\n type=\"text\"\n @keydown.down.prevent=\"moveActive(1)\"\n @keydown.enter.prevent=\"activeRef && toggleSelected(activeRef)\"\n @keydown.esc.prevent=\"close?.()\"\n @keydown.up.prevent=\"moveActive(-1)\" />\n </div>\n <ul\n v-show=\"filtered.length || slots.add || noResults\"\n :id=\"id\"\n :aria-multiselectable=\"multiselect\"\n class=\"border-t p-0.75 custom-scroll overscroll-contain flex-1 min-h-0\"\n role=\"listbox\"\n tabindex=\"-1\">\n <li\n v-if=\"!filtered.length && !slots.add && noResults\"\n class=\"text-c-3 px-2.5 py-2\"\n role=\"status\">\n {{ noResults }}\n </li>\n <ComboboxOptionGroup\n v-for=\"(group, i) in groups\"\n :id=\"`${id}-group-${i}`\"\n :key=\"i\"\n :hidden=\"\n // Only show the group label if there are some results\n !group.options.some((o) => filtered.some((f) => f.id === o.id)) ||\n // And it has a label\n !group.label\n \">\n <template #label>\n <slot\n v-if=\"$slots.group\"\n :group\n name=\"group\" />\n <template v-else>\n {{ group.label }}\n </template>\n </template>\n <template\n v-for=\"option in filtered\"\n :key=\"option.id\">\n <ComboboxOption\n v-if=\"group.options.some((o) => o.id === option.id)\"\n :id=\"getOptionId(option)\"\n v-slot=\"{ active, selected }\"\n :active=\"activeRef?.id === option.id\"\n :selected=\"model.some((o) => o.id === option.id)\"\n @click=\"toggleSelected(option)\"\n @mousedown.prevent\n @mouseenter=\"activeRef = option\">\n <slot\n v-if=\"$slots.option\"\n :active\n name=\"option\"\n :option\n :selected />\n <template v-else>\n <ScalarListboxCheckbox\n :multiselect\n :selected=\"model.some((o) => o.id === option.id)\" />\n <span class=\"inline-block min-w-0 flex-1 truncate text-c-1\">\n {{ option.label }}\n </span>\n </template>\n </ComboboxOption>\n </template>\n </ComboboxOptionGroup>\n <ComboboxOption\n v-if=\"slots.add\"\n :id=\"getOptionId(addOption)\"\n v-slot=\"{ active }\"\n :active=\"activeRef?.id === addOption.id\"\n @click=\"addNew\"\n @mousedown.prevent\n @mouseenter=\"activeRef = addOption\">\n <ScalarIconPlus class=\"size-4 p-px\" />\n <slot\n :active\n name=\"add\" />\n </ComboboxOption>\n </ul>\n</template>\n"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
|
|
|
2
2
|
import ScalarDropdownButton_vue_vue_type_script_setup_true_lang_default from "./ScalarDropdownButton.vue.script.js";
|
|
3
3
|
/* empty css */
|
|
4
4
|
//#region src/components/ScalarDropdown/ScalarDropdownButton.vue
|
|
5
|
-
var ScalarDropdownButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(ScalarDropdownButton_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
5
|
+
var ScalarDropdownButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(ScalarDropdownButton_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-128eed00"]]);
|
|
6
6
|
//#endregion
|
|
7
7
|
export { ScalarDropdownButton_default as default };
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarDropdownButton.vue.js","names":[],"sources":["../../../src/components/ScalarDropdown/ScalarDropdownButton.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar dropdown button base component\n *\n * Provide a styled button for the ScalarDropdown or similar\n *\n * This is used internally by the ScalarDropdownItem component\n *\n * If you're looking to add items to a dropdown menu you\n * probably want the ScalarDropdownItem component\n *\n * @example\n * <ScalarDropdownButton @click=\"handleClick\">\n * Label\n * </ScalarDropdownButton>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\nimport type { Component } from 'vue'\n\nconst { is = 'button' } = defineProps<{\n is?: string | Component\n active?: boolean\n disabled?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Layout\n 'block h-8 min-w-0 gap-1.5 rounded px-2.5 py-1.5 text-left',\n // Text / background style\n 'truncate no-underline text-sm text-c-1',\n // Interaction — hover:bg-b-2 handles mouse, highlighted:bg-b-2 handles\n // Radix keyboard navigation and mouse-hover within Radix menu items\n 'cursor-pointer hover:bg-b-2 highlighted:bg-b-2',\n ],\n variants: {\n disabled: { true: 'pointer-events-none text-c-3' },\n active: { true: '' },\n },\n compoundVariants: [{ disabled: false, active: true, class: 'bg-b-2' }],\n})\n</script>\n<template>\n <component\n :is=\"is\"\n :aria-disabled=\"disabled\"\n class=\"item\"\n :class=\"cx('scalar-dropdown-item', variants({ active, disabled }))\"\n :type=\"is === 'button' ? 'button' : undefined\">\n <slot />\n </component>\n</template>\n<style scoped>\n.dark-mode .scalar-dropdown-item:hover,\n.dark-mode .scalar-dropdown-item[data-highlighted] {\n filter: brightness(1.1);\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarDropdownButton.vue.js","names":[],"sources":["../../../src/components/ScalarDropdown/ScalarDropdownButton.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar dropdown button base component\n *\n * Provide a styled button for the ScalarDropdown or similar\n *\n * This is used internally by the ScalarDropdownItem component\n *\n * If you're looking to add items to a dropdown menu you\n * probably want the ScalarDropdownItem component\n *\n * @example\n * <ScalarDropdownButton @click=\"handleClick\">\n * Label\n * </ScalarDropdownButton>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\nimport type { Component } from 'vue'\n\nconst { is = 'button' } = defineProps<{\n is?: string | Component\n active?: boolean\n disabled?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Layout\n 'block h-8 min-w-0 gap-1.5 rounded-md px-2.5 py-1.5 text-left',\n // Text / background style\n 'truncate no-underline text-sm text-c-1',\n // Interaction — hover:bg-b-2 handles mouse, highlighted:bg-b-2 handles\n // Radix keyboard navigation and mouse-hover within Radix menu items\n 'cursor-pointer hover:bg-b-2 highlighted:bg-b-2',\n ],\n variants: {\n disabled: { true: 'pointer-events-none text-c-3' },\n active: { true: '' },\n },\n compoundVariants: [{ disabled: false, active: true, class: 'bg-b-2' }],\n})\n</script>\n<template>\n <component\n :is=\"is\"\n :aria-disabled=\"disabled\"\n class=\"item\"\n :class=\"cx('scalar-dropdown-item', variants({ active, disabled }))\"\n :type=\"is === 'button' ? 'button' : undefined\">\n <slot />\n </component>\n</template>\n<style scoped>\n.dark-mode .scalar-dropdown-item:hover,\n.dark-mode .scalar-dropdown-item[data-highlighted] {\n filter: brightness(1.1);\n}\n</style>\n"],"mappings":""}
|
|
@@ -10,7 +10,7 @@ var ScalarDropdownButton_vue_vue_type_script_setup_true_lang_default = /*@__PURE
|
|
|
10
10
|
setup(__props) {
|
|
11
11
|
const variants = cva({
|
|
12
12
|
base: [
|
|
13
|
-
"block h-8 min-w-0 gap-1.5 rounded px-2.5 py-1.5 text-left",
|
|
13
|
+
"block h-8 min-w-0 gap-1.5 rounded-md px-2.5 py-1.5 text-left",
|
|
14
14
|
"truncate no-underline text-sm text-c-1",
|
|
15
15
|
"cursor-pointer hover:bg-b-2 highlighted:bg-b-2"
|
|
16
16
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarDropdownButton.vue.script.js","names":[],"sources":["../../../src/components/ScalarDropdown/ScalarDropdownButton.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar dropdown button base component\n *\n * Provide a styled button for the ScalarDropdown or similar\n *\n * This is used internally by the ScalarDropdownItem component\n *\n * If you're looking to add items to a dropdown menu you\n * probably want the ScalarDropdownItem component\n *\n * @example\n * <ScalarDropdownButton @click=\"handleClick\">\n * Label\n * </ScalarDropdownButton>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\nimport type { Component } from 'vue'\n\nconst { is = 'button' } = defineProps<{\n is?: string | Component\n active?: boolean\n disabled?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Layout\n 'block h-8 min-w-0 gap-1.5 rounded px-2.5 py-1.5 text-left',\n // Text / background style\n 'truncate no-underline text-sm text-c-1',\n // Interaction — hover:bg-b-2 handles mouse, highlighted:bg-b-2 handles\n // Radix keyboard navigation and mouse-hover within Radix menu items\n 'cursor-pointer hover:bg-b-2 highlighted:bg-b-2',\n ],\n variants: {\n disabled: { true: 'pointer-events-none text-c-3' },\n active: { true: '' },\n },\n compoundVariants: [{ disabled: false, active: true, class: 'bg-b-2' }],\n})\n</script>\n<template>\n <component\n :is=\"is\"\n :aria-disabled=\"disabled\"\n class=\"item\"\n :class=\"cx('scalar-dropdown-item', variants({ active, disabled }))\"\n :type=\"is === 'button' ? 'button' : undefined\">\n <slot />\n </component>\n</template>\n<style scoped>\n.dark-mode .scalar-dropdown-item:hover,\n.dark-mode .scalar-dropdown-item[data-highlighted] {\n filter: brightness(1.1);\n}\n</style>\n"],"mappings":";;;;;;;;;;EA4BA,MAAM,WAAW,IAAI;GACnB,MAAM;IAEJ;IAEA;IAGA;GACF;GACA,UAAU;IACR,UAAU,EAAE,MAAM,+BAA+B;IACjD,QAAQ,EAAE,MAAM,GAAG;GACrB;GACA,kBAAkB,CAAC;IAAE,UAAU;IAAO,QAAQ;IAAM,OAAO;GAAS,CAAC;EACvE,CAAC;;uBAGC,YAOY,wBANL,QAAA,EAAE,GAAA;IACN,iBAAe,QAAA;IAChB,OAAK,eAAA,CAAC,QACE,MAAA,EAAA,CAAE,CAAA,wBAAyB,MAAA,QAAA,CAAQ,CAAA;KAAA,QAAG,QAAA;KAAM,UAAE,QAAA;IAAQ,CAAA,CAAA,CAAA,CAAA;IAC7D,MAAM,QAAA,OAAE,WAAA,WAA2B,KAAA;;2BAC5B,CAAR,WAAQ,KAAA,QAAA,WAAA,CAAA,GAAA,KAAA,GAAA,IAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"ScalarDropdownButton.vue.script.js","names":[],"sources":["../../../src/components/ScalarDropdown/ScalarDropdownButton.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar dropdown button base component\n *\n * Provide a styled button for the ScalarDropdown or similar\n *\n * This is used internally by the ScalarDropdownItem component\n *\n * If you're looking to add items to a dropdown menu you\n * probably want the ScalarDropdownItem component\n *\n * @example\n * <ScalarDropdownButton @click=\"handleClick\">\n * Label\n * </ScalarDropdownButton>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\nimport type { Component } from 'vue'\n\nconst { is = 'button' } = defineProps<{\n is?: string | Component\n active?: boolean\n disabled?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Layout\n 'block h-8 min-w-0 gap-1.5 rounded-md px-2.5 py-1.5 text-left',\n // Text / background style\n 'truncate no-underline text-sm text-c-1',\n // Interaction — hover:bg-b-2 handles mouse, highlighted:bg-b-2 handles\n // Radix keyboard navigation and mouse-hover within Radix menu items\n 'cursor-pointer hover:bg-b-2 highlighted:bg-b-2',\n ],\n variants: {\n disabled: { true: 'pointer-events-none text-c-3' },\n active: { true: '' },\n },\n compoundVariants: [{ disabled: false, active: true, class: 'bg-b-2' }],\n})\n</script>\n<template>\n <component\n :is=\"is\"\n :aria-disabled=\"disabled\"\n class=\"item\"\n :class=\"cx('scalar-dropdown-item', variants({ active, disabled }))\"\n :type=\"is === 'button' ? 'button' : undefined\">\n <slot />\n </component>\n</template>\n<style scoped>\n.dark-mode .scalar-dropdown-item:hover,\n.dark-mode .scalar-dropdown-item[data-highlighted] {\n filter: brightness(1.1);\n}\n</style>\n"],"mappings":";;;;;;;;;;EA4BA,MAAM,WAAW,IAAI;GACnB,MAAM;IAEJ;IAEA;IAGA;GACF;GACA,UAAU;IACR,UAAU,EAAE,MAAM,+BAA+B;IACjD,QAAQ,EAAE,MAAM,GAAG;GACrB;GACA,kBAAkB,CAAC;IAAE,UAAU;IAAO,QAAQ;IAAM,OAAO;GAAS,CAAC;EACvE,CAAC;;uBAGC,YAOY,wBANL,QAAA,EAAE,GAAA;IACN,iBAAe,QAAA;IAChB,OAAK,eAAA,CAAC,QACE,MAAA,EAAA,CAAE,CAAA,wBAAyB,MAAA,QAAA,CAAQ,CAAA;KAAA,QAAG,QAAA;KAAM,UAAE,QAAA;IAAQ,CAAA,CAAA,CAAA,CAAA;IAC7D,MAAM,QAAA,OAAE,WAAA,WAA2B,KAAA;;2BAC5B,CAAR,WAAQ,KAAA,QAAA,WAAA,CAAA,GAAA,KAAA,GAAA,IAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarDropdownMenu.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarDropdown/ScalarDropdownMenu.vue"],"names":[],"mappings":"AAgEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,CAAA;AAKpC;;;;;;;;;;;;;;GAcG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IAEhB,8BAA8B;SACzB,MAAM,GAAG,SAAS;;IADvB,8BAA8B;SACzB,MAAM,GAAG,SAAS;;IAKvB,wBAAwB;gBACZ,OAAO;IACnB,6CAA6C;aACpC,OAAO;IAChB,8CAA8C;iBACjC,OAAO;
|
|
1
|
+
{"version":3,"file":"ScalarDropdownMenu.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarDropdown/ScalarDropdownMenu.vue"],"names":[],"mappings":"AAgEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,KAAK,CAAA;AAKpC;;;;;;;;;;;;;;GAcG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;IAEhB,8BAA8B;SACzB,MAAM,GAAG,SAAS;;IADvB,8BAA8B;SACzB,MAAM,GAAG,SAAS;;IAKvB,wBAAwB;gBACZ,OAAO;IACnB,6CAA6C;aACpC,OAAO;IAChB,8CAA8C;iBACjC,OAAO;EA6ElB,CAAC;AACL,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarDropdownMenu.vue.js","names":[],"sources":["../../../src/components/ScalarDropdown/ScalarDropdownMenu.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar dropdown menu component\n *\n * Provides a scrollable container for dropdown items\n * This is used internally by the ScalarDropdown component\n *\n * If you're looking to create a dropdown menu with a trigger\n * button you probably want the ScalarDropdown component\n *\n * @example\n * <ScalarDropdownMenu>\n * <ScalarDropdownItem>Item 1</ScalarDropdownItem>\n * <ScalarDropdownItem>Item 2</ScalarDropdownItem>\n * </ScalarDropdownMenu>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { type Component } from 'vue'\n\nimport { ScalarFloatingBackdrop } from '../ScalarFloating'\n\ndefineProps<{\n /** The component to render */\n is?: string | Component\n}>()\n\ndefineSlots<{\n /** The menu contents */\n default?(): unknown\n /** Overrides the normal menu list element */\n menu?(): unknown\n /** Overrides the backdrop for the dropdown */\n backdrop?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <!-- Background container -->\n <component\n :is=\"is ?? 'div'\"\n v-bind=\"cx('relative flex w-56')\">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1\">\n <!-- Menu items -->\n <slot name=\"menu\">\n <div class=\"flex flex-col p-0.75\">\n <slot />\n </div>\n </slot>\n <slot name=\"backdrop\">\n <ScalarFloatingBackdrop />\n </slot>\n </div>\n </component>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarDropdownMenu.vue.js","names":[],"sources":["../../../src/components/ScalarDropdown/ScalarDropdownMenu.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar dropdown menu component\n *\n * Provides a scrollable container for dropdown items\n * This is used internally by the ScalarDropdown component\n *\n * If you're looking to create a dropdown menu with a trigger\n * button you probably want the ScalarDropdown component\n *\n * @example\n * <ScalarDropdownMenu>\n * <ScalarDropdownItem>Item 1</ScalarDropdownItem>\n * <ScalarDropdownItem>Item 2</ScalarDropdownItem>\n * </ScalarDropdownMenu>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { type Component } from 'vue'\n\nimport { ScalarFloatingBackdrop } from '../ScalarFloating'\n\ndefineProps<{\n /** The component to render */\n is?: string | Component\n}>()\n\ndefineSlots<{\n /** The menu contents */\n default?(): unknown\n /** Overrides the normal menu list element */\n menu?(): unknown\n /** Overrides the backdrop for the dropdown */\n backdrop?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <!-- Background container -->\n <component\n :is=\"is ?? 'div'\"\n v-bind=\"cx('relative flex w-56')\">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1\">\n <!-- Menu items -->\n <slot name=\"menu\">\n <div class=\"flex flex-col p-0.75\">\n <slot />\n </div>\n </slot>\n <slot name=\"backdrop\">\n <ScalarFloatingBackdrop class=\"rounded-xl border shadow-md\" />\n </slot>\n </div>\n </component>\n</template>\n"],"mappings":""}
|
|
@@ -12,7 +12,7 @@ var ScalarDropdownMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
|
|
|
12
12
|
const { cx } = useBindCx();
|
|
13
13
|
return (_ctx, _cache) => {
|
|
14
14
|
return openBlock(), createBlock(resolveDynamicComponent(__props.is ?? "div"), normalizeProps(guardReactiveProps(unref(cx)("relative flex w-56"))), {
|
|
15
|
-
default: withCtx(() => [createElementVNode("div", _hoisted_1, [renderSlot(_ctx.$slots, "menu", {}, () => [createElementVNode("div", _hoisted_2, [renderSlot(_ctx.$slots, "default")])]), renderSlot(_ctx.$slots, "backdrop", {}, () => [createVNode(unref(ScalarFloatingBackdrop_default))])])]),
|
|
15
|
+
default: withCtx(() => [createElementVNode("div", _hoisted_1, [renderSlot(_ctx.$slots, "menu", {}, () => [createElementVNode("div", _hoisted_2, [renderSlot(_ctx.$slots, "default")])]), renderSlot(_ctx.$slots, "backdrop", {}, () => [createVNode(unref(ScalarFloatingBackdrop_default), { class: "rounded-xl border shadow-md" })])])]),
|
|
16
16
|
_: 3
|
|
17
17
|
}, 16);
|
|
18
18
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarDropdownMenu.vue.script.js","names":[],"sources":["../../../src/components/ScalarDropdown/ScalarDropdownMenu.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar dropdown menu component\n *\n * Provides a scrollable container for dropdown items\n * This is used internally by the ScalarDropdown component\n *\n * If you're looking to create a dropdown menu with a trigger\n * button you probably want the ScalarDropdown component\n *\n * @example\n * <ScalarDropdownMenu>\n * <ScalarDropdownItem>Item 1</ScalarDropdownItem>\n * <ScalarDropdownItem>Item 2</ScalarDropdownItem>\n * </ScalarDropdownMenu>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { type Component } from 'vue'\n\nimport { ScalarFloatingBackdrop } from '../ScalarFloating'\n\ndefineProps<{\n /** The component to render */\n is?: string | Component\n}>()\n\ndefineSlots<{\n /** The menu contents */\n default?(): unknown\n /** Overrides the normal menu list element */\n menu?(): unknown\n /** Overrides the backdrop for the dropdown */\n backdrop?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <!-- Background container -->\n <component\n :is=\"is ?? 'div'\"\n v-bind=\"cx('relative flex w-56')\">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1\">\n <!-- Menu items -->\n <slot name=\"menu\">\n <div class=\"flex flex-col p-0.75\">\n <slot />\n </div>\n </slot>\n <slot name=\"backdrop\">\n <ScalarFloatingBackdrop />\n </slot>\n </div>\n </component>\n</template>\n"],"mappings":";;;;;;;;;;;EAuCA,MAAM,EAAE,OAAO,UAAU;;uBAIvB,YAeY,wBAdL,QAAA,MAAE,KAAA,GAAA,eAAA,mBACC,MAAA,EAAA,CAAE,CAAA,oBAAA,CAAA,CAAA,GAAA;2BAYJ,CAVN,mBAUM,OAVN,YAUM,CARJ,WAIO,KAAA,QAAA,QAAA,CAAA,SAAA,CAHL,mBAEM,OAFN,YAEM,CADJ,WAAQ,KAAA,QAAA,SAAA,CAAA,CAAA,CAAA,CAAA,GAGZ,WAEO,KAAA,QAAA,YAAA,CAAA,SAAA,CADL,
|
|
1
|
+
{"version":3,"file":"ScalarDropdownMenu.vue.script.js","names":[],"sources":["../../../src/components/ScalarDropdown/ScalarDropdownMenu.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar dropdown menu component\n *\n * Provides a scrollable container for dropdown items\n * This is used internally by the ScalarDropdown component\n *\n * If you're looking to create a dropdown menu with a trigger\n * button you probably want the ScalarDropdown component\n *\n * @example\n * <ScalarDropdownMenu>\n * <ScalarDropdownItem>Item 1</ScalarDropdownItem>\n * <ScalarDropdownItem>Item 2</ScalarDropdownItem>\n * </ScalarDropdownMenu>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { type Component } from 'vue'\n\nimport { ScalarFloatingBackdrop } from '../ScalarFloating'\n\ndefineProps<{\n /** The component to render */\n is?: string | Component\n}>()\n\ndefineSlots<{\n /** The menu contents */\n default?(): unknown\n /** Overrides the normal menu list element */\n menu?(): unknown\n /** Overrides the backdrop for the dropdown */\n backdrop?(): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <!-- Background container -->\n <component\n :is=\"is ?? 'div'\"\n v-bind=\"cx('relative flex w-56')\">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1\">\n <!-- Menu items -->\n <slot name=\"menu\">\n <div class=\"flex flex-col p-0.75\">\n <slot />\n </div>\n </slot>\n <slot name=\"backdrop\">\n <ScalarFloatingBackdrop class=\"rounded-xl border shadow-md\" />\n </slot>\n </div>\n </component>\n</template>\n"],"mappings":";;;;;;;;;;;EAuCA,MAAM,EAAE,OAAO,UAAU;;uBAIvB,YAeY,wBAdL,QAAA,MAAE,KAAA,GAAA,eAAA,mBACC,MAAA,EAAA,CAAE,CAAA,oBAAA,CAAA,CAAA,GAAA;2BAYJ,CAVN,mBAUM,OAVN,YAUM,CARJ,WAIO,KAAA,QAAA,QAAA,CAAA,SAAA,CAHL,mBAEM,OAFN,YAEM,CADJ,WAAQ,KAAA,QAAA,SAAA,CAAA,CAAA,CAAA,CAAA,GAGZ,WAEO,KAAA,QAAA,YAAA,CAAA,SAAA,CADL,YAA8D,MAAA,8BAAA,GAAA,EAAtC,OAAM,8BAA6B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA"}
|
package/dist/style.css
CHANGED
|
@@ -3764,8 +3764,8 @@ to {
|
|
|
3764
3764
|
transform: translate3d(0, 0, 0);
|
|
3765
3765
|
}
|
|
3766
3766
|
|
|
3767
|
-
.dark-mode .scalar-dropdown-item[data-v-
|
|
3768
|
-
.dark-mode .scalar-dropdown-item[data-highlighted][data-v-
|
|
3767
|
+
.dark-mode .scalar-dropdown-item[data-v-128eed00]:hover,
|
|
3768
|
+
.dark-mode .scalar-dropdown-item[data-highlighted][data-v-128eed00] {
|
|
3769
3769
|
filter: brightness(1.1);
|
|
3770
3770
|
}
|
|
3771
3771
|
|
package/dist/vue-styles.css
CHANGED
|
@@ -270,8 +270,8 @@ to {
|
|
|
270
270
|
transform: translate3d(0, 0, 0);
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
.dark-mode .scalar-dropdown-item[data-v-
|
|
274
|
-
.dark-mode .scalar-dropdown-item[data-highlighted][data-v-
|
|
273
|
+
.dark-mode .scalar-dropdown-item[data-v-128eed00]:hover,
|
|
274
|
+
.dark-mode .scalar-dropdown-item[data-highlighted][data-v-128eed00] {
|
|
275
275
|
filter: brightness(1.1);
|
|
276
276
|
}
|
|
277
277
|
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"url": "git+https://github.com/scalar/scalar.git",
|
|
11
11
|
"directory": "packages/components"
|
|
12
12
|
},
|
|
13
|
-
"version": "0.
|
|
13
|
+
"version": "0.30.0",
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=22"
|
|
16
16
|
},
|
|
@@ -216,16 +216,16 @@
|
|
|
216
216
|
"@floating-ui/vue": "1.1.9",
|
|
217
217
|
"@headlessui/tailwindcss": "^0.2.2",
|
|
218
218
|
"@headlessui/vue": "1.7.23",
|
|
219
|
+
"@scalar/code-highlight": "0.4.6",
|
|
220
|
+
"@scalar/helpers": "0.12.0",
|
|
221
|
+
"@scalar/icons": "0.7.6",
|
|
222
|
+
"@scalar/themes": "0.18.0",
|
|
223
|
+
"@scalar/use-hooks": "0.4.12",
|
|
219
224
|
"@vueuse/core": "13.9.0",
|
|
220
225
|
"cva": "1.0.0-beta.4",
|
|
221
226
|
"radix-vue": "^1.9.17",
|
|
222
227
|
"vue": "^3.5.40",
|
|
223
|
-
"vue-component-type-helpers": "^3.2.6"
|
|
224
|
-
"@scalar/code-highlight": "0.4.6",
|
|
225
|
-
"@scalar/icons": "0.7.6",
|
|
226
|
-
"@scalar/helpers": "0.12.0",
|
|
227
|
-
"@scalar/themes": "0.18.0",
|
|
228
|
-
"@scalar/use-hooks": "0.4.12"
|
|
228
|
+
"vue-component-type-helpers": "^3.2.6"
|
|
229
229
|
},
|
|
230
230
|
"devDependencies": {
|
|
231
231
|
"@playwright/test": "1.62.1",
|