@scalar/components 0.30.6 → 0.30.7
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/ScalarComboboxOption.vue.js.map +1 -1
- package/dist/components/ScalarCombobox/ScalarComboboxOption.vue.script.js +1 -1
- package/dist/components/ScalarCombobox/ScalarComboboxOption.vue.script.js.map +1 -1
- 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 +3 -3
- package/dist/components/ScalarCombobox/ScalarComboboxOptions.vue.script.js.map +1 -1
- package/dist/components/ScalarCombobox/ScalarComboboxPopover.vue.js.map +1 -1
- package/dist/components/ScalarCombobox/ScalarComboboxPopover.vue.script.js +1 -1
- package/dist/components/ScalarCombobox/ScalarComboboxPopover.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 +3 -3
- package/dist/components/ScalarDropdown/ScalarDropdownMenu.vue.script.js.map +1 -1
- package/dist/components/ScalarFloating/ScalarFloatingBackdrop.vue.d.ts +3 -0
- package/dist/components/ScalarFloating/ScalarFloatingBackdrop.vue.d.ts.map +1 -1
- package/dist/components/ScalarFloating/ScalarFloatingBackdrop.vue.js.map +1 -1
- package/dist/components/ScalarFloating/ScalarFloatingBackdrop.vue.script.js +4 -2
- package/dist/components/ScalarFloating/ScalarFloatingBackdrop.vue.script.js.map +1 -1
- package/dist/components/ScalarListbox/ScalarListbox.vue.js.map +1 -1
- package/dist/components/ScalarListbox/ScalarListbox.vue.script.js +1 -1
- package/dist/components/ScalarListbox/ScalarListbox.vue.script.js.map +1 -1
- package/dist/components/ScalarListbox/ScalarListboxItem.vue.js.map +1 -1
- package/dist/components/ScalarListbox/ScalarListboxItem.vue.script.js +1 -1
- package/dist/components/ScalarListbox/ScalarListboxItem.vue.script.js.map +1 -1
- package/dist/components/ScalarPopover/ScalarPopover.vue.js.map +1 -1
- package/dist/components/ScalarPopover/ScalarPopover.vue.script.js +1 -1
- package/dist/components/ScalarPopover/ScalarPopover.vue.script.js.map +1 -1
- package/dist/style.css +45 -12
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarComboboxOption.vue.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxOption.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Option component\n *\n * A single selectable option within a combobox list.\n * Handles active and selected states.\n *\n * @example\n * <ScalarComboboxOption :active=\"true\" :selected=\"false\">\n * Option Label\n * </ScalarComboboxOption>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\n\nconst { active, selected } = defineProps<{\n active?: boolean\n selected?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Group\n 'group/item',\n // Layout\n 'flex min-w-0 items-center gap-1.5 rounded px-2 py-1.5 text-left',\n // Text / background style\n 'truncate bg-transparent text-c-1',\n // Interaction\n 'cursor-pointer hover:bg-b-2',\n ],\n variants: {\n selected: { true: 'text-c-1' },\n active: { true: 'bg-b-2' },\n },\n})\n</script>\n<template>\n <li\n :aria-selected=\"selected\"\n :class=\"cx(variants({ active, selected }))\"\n role=\"option\"\n tabindex=\"-1\">\n <slot\n :active\n :selected />\n </li>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarComboboxOption.vue.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxOption.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Option component\n *\n * A single selectable option within a combobox list.\n * Handles active and selected states.\n *\n * @example\n * <ScalarComboboxOption :active=\"true\" :selected=\"false\">\n * Option Label\n * </ScalarComboboxOption>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\n\nconst { active, selected } = defineProps<{\n active?: boolean\n selected?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Group\n 'group/item',\n // Layout\n 'flex min-w-0 items-center gap-1.5 rounded-md px-2 py-1.5 text-left',\n // Text / background style\n 'truncate bg-transparent text-c-1',\n // Interaction\n 'cursor-pointer hover:bg-b-2',\n ],\n variants: {\n selected: { true: 'text-c-1' },\n active: { true: 'bg-b-2' },\n },\n})\n</script>\n<template>\n <li\n :aria-selected=\"selected\"\n :class=\"cx(variants({ active, selected }))\"\n role=\"option\"\n tabindex=\"-1\">\n <slot\n :active\n :selected />\n </li>\n</template>\n"],"mappings":""}
|
|
@@ -12,7 +12,7 @@ var ScalarComboboxOption_vue_vue_type_script_setup_true_lang_default = /*@__PURE
|
|
|
12
12
|
const variants = cva({
|
|
13
13
|
base: [
|
|
14
14
|
"group/item",
|
|
15
|
-
"flex min-w-0 items-center gap-1.5 rounded px-2 py-1.5 text-left",
|
|
15
|
+
"flex min-w-0 items-center gap-1.5 rounded-md px-2 py-1.5 text-left",
|
|
16
16
|
"truncate bg-transparent text-c-1",
|
|
17
17
|
"cursor-pointer hover:bg-b-2"
|
|
18
18
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarComboboxOption.vue.script.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxOption.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Option component\n *\n * A single selectable option within a combobox list.\n * Handles active and selected states.\n *\n * @example\n * <ScalarComboboxOption :active=\"true\" :selected=\"false\">\n * Option Label\n * </ScalarComboboxOption>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\n\nconst { active, selected } = defineProps<{\n active?: boolean\n selected?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Group\n 'group/item',\n // Layout\n 'flex min-w-0 items-center gap-1.5 rounded px-2 py-1.5 text-left',\n // Text / background style\n 'truncate bg-transparent text-c-1',\n // Interaction\n 'cursor-pointer hover:bg-b-2',\n ],\n variants: {\n selected: { true: 'text-c-1' },\n active: { true: 'bg-b-2' },\n },\n})\n</script>\n<template>\n <li\n :aria-selected=\"selected\"\n :class=\"cx(variants({ active, selected }))\"\n role=\"option\"\n tabindex=\"-1\">\n <slot\n :active\n :selected />\n </li>\n</template>\n"],"mappings":";;;;;;;;;;;EAuBA,MAAM,WAAW,IAAI;GACnB,MAAM;IAEJ;IAEA;IAEA;IAEA;GACF;GACA,UAAU;IACR,UAAU,EAAE,MAAM,WAAW;IAC7B,QAAQ,EAAE,MAAM,SAAS;GAC3B;EACF,CAAC;;uBAGC,mBAQK,MAAA;IAPF,iBAAe,QAAA;IACf,OAAK,eAAE,MAAA,EAAA,CAAE,CAAC,MAAA,QAAA,CAAQ,CAAA;KAAA,QAAG,QAAA;KAAM,UAAE,QAAA;IAAQ,CAAA,CAAA,CAAA;IACtC,MAAK;IACL,UAAS;OACT,WAEc,KAAA,QAAA,WAAA;IADX,QAAA,QAAA;IACA,UAAA,QAAA"}
|
|
1
|
+
{"version":3,"file":"ScalarComboboxOption.vue.script.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxOption.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Option component\n *\n * A single selectable option within a combobox list.\n * Handles active and selected states.\n *\n * @example\n * <ScalarComboboxOption :active=\"true\" :selected=\"false\">\n * Option Label\n * </ScalarComboboxOption>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\n\nconst { active, selected } = defineProps<{\n active?: boolean\n selected?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Group\n 'group/item',\n // Layout\n 'flex min-w-0 items-center gap-1.5 rounded-md px-2 py-1.5 text-left',\n // Text / background style\n 'truncate bg-transparent text-c-1',\n // Interaction\n 'cursor-pointer hover:bg-b-2',\n ],\n variants: {\n selected: { true: 'text-c-1' },\n active: { true: 'bg-b-2' },\n },\n})\n</script>\n<template>\n <li\n :aria-selected=\"selected\"\n :class=\"cx(variants({ active, selected }))\"\n role=\"option\"\n tabindex=\"-1\">\n <slot\n :active\n :selected />\n </li>\n</template>\n"],"mappings":";;;;;;;;;;;EAuBA,MAAM,WAAW,IAAI;GACnB,MAAM;IAEJ;IAEA;IAEA;IAEA;GACF;GACA,UAAU;IACR,UAAU,EAAE,MAAM,WAAW;IAC7B,QAAQ,EAAE,MAAM,SAAS;GAC3B;EACF,CAAC;;uBAGC,mBAQK,MAAA;IAPF,iBAAe,QAAA;IACf,OAAK,eAAE,MAAA,EAAA,CAAE,CAAC,MAAA,QAAA,CAAQ,CAAA;KAAA,QAAG,QAAA;KAAM,UAAE,QAAA;IAAQ,CAAA,CAAA,CAAA;IACtC,MAAK;IACL,UAAS;OACT,WAEc,KAAA,QAAA,WAAA;IADX,QAAA,QAAA;IACA,UAAA,QAAA"}
|
|
@@ -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":"AAyVA,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;WAyhBO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB,CAAC;QAvhBtD,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;;qBA6LV,CAAC,EAAE;;;;KAwU2E,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 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/**\n * Space toggles the active option in multiselect mode while the search box is empty.\n *\n * The options look like checkboxes, so keyboard users press Space to toggle them. Without this\n * handler Space types a leading space into the query, which filters out every option whose label\n * has no space and hides the whole list without any feedback (found by an accessibility audit).\n * Once a query has been typed, Space keeps inserting a character so multi-word labels stay\n * searchable. Key auto-repeat is ignored so holding Space after opening the popover with it does\n * not toggle the option repeatedly, and IME composition is left alone.\n */\nconst handleSpace = (event: KeyboardEvent): void => {\n if (!multiselect || query.value !== '' || event.isComposing) {\n return\n }\n // Suppress repeated spaces too, so holding the key does not start filtering.\n event.preventDefault()\n if (!event.repeat) {\n toggleSelected(activeRef.value)\n }\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-expanded=\"Boolean(filtered.length || slots.add || noResults)\"\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.space=\"handleSpace\"\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":""}
|
|
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/**\n * Space toggles the active option in multiselect mode while the search box is empty.\n *\n * The options look like checkboxes, so keyboard users press Space to toggle them. Without this\n * handler Space types a leading space into the query, which filters out every option whose label\n * has no space and hides the whole list without any feedback (found by an accessibility audit).\n * Once a query has been typed, Space keeps inserting a character so multi-word labels stay\n * searchable. Key auto-repeat is ignored so holding Space after opening the popover with it does\n * not toggle the option repeatedly, and IME composition is left alone.\n */\nconst handleSpace = (event: KeyboardEvent): void => {\n if (!multiselect || query.value !== '' || event.isComposing) {\n return\n }\n // Suppress repeated spaces too, so holding the key does not start filtering.\n event.preventDefault()\n if (!event.repeat) {\n toggleSelected(activeRef.value)\n }\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 <!-- Inset to line up with the options below -->\n <div class=\"relative flex m-1 mb-0.75\">\n <ScalarIconMagnifyingGlass\n class=\"pointer-events-none absolute left-1.75 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-expanded=\"Boolean(filtered.length || slots.add || noResults)\"\n :aria-label=\"inputLabel\"\n class=\"min-w-0 flex-1 rounded-md border-0 py-1.5 pl-7.25 pr-1.75 leading-none text-c-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.space=\"handleSpace\"\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":""}
|
|
@@ -6,7 +6,7 @@ import { isGroups } from "./types.js";
|
|
|
6
6
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeModels, onMounted, openBlock, ref, renderList, renderSlot, toDisplayString, unref, useId, useModel, useSlots, vModelText, vShow, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
|
|
7
7
|
import { ScalarIconMagnifyingGlass, ScalarIconPlus } from "@scalar/icons";
|
|
8
8
|
//#region src/components/ScalarCombobox/ScalarComboboxOptions.vue?vue&type=script&setup=true&lang.ts
|
|
9
|
-
var _hoisted_1 = { class: "relative flex" };
|
|
9
|
+
var _hoisted_1 = { class: "relative flex m-1 mb-0.75" };
|
|
10
10
|
var _hoisted_2 = [
|
|
11
11
|
"aria-activedescendant",
|
|
12
12
|
"aria-expanded",
|
|
@@ -120,7 +120,7 @@ var ScalarComboboxOptions_vue_vue_type_script_setup_true_lang_default = /*@__PUR
|
|
|
120
120
|
const input = ref(null);
|
|
121
121
|
onMounted(() => setTimeout(() => input.value?.focus(), 0));
|
|
122
122
|
return (_ctx, _cache) => {
|
|
123
|
-
return openBlock(), createElementBlock(Fragment, null, [createElementVNode("div", _hoisted_1, [createVNode(unref(ScalarIconMagnifyingGlass), { class: "pointer-events-none absolute left-
|
|
123
|
+
return openBlock(), createElementBlock(Fragment, null, [createElementVNode("div", _hoisted_1, [createVNode(unref(ScalarIconMagnifyingGlass), { class: "pointer-events-none absolute left-1.75 top-1/2 -translate-y-1/2 text-c-3 size-4" }), withDirectives(createElementVNode("input", {
|
|
124
124
|
ref_key: "input",
|
|
125
125
|
ref: input,
|
|
126
126
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => query.value = $event),
|
|
@@ -129,7 +129,7 @@ var ScalarComboboxOptions_vue_vue_type_script_setup_true_lang_default = /*@__PUR
|
|
|
129
129
|
"aria-controls": id,
|
|
130
130
|
"aria-expanded": Boolean(filtered.value.length || slots.add || __props.noResults),
|
|
131
131
|
"aria-label": __props.inputLabel,
|
|
132
|
-
class: "min-w-0 flex-1 rounded border-0 py-
|
|
132
|
+
class: "min-w-0 flex-1 rounded-md border-0 py-1.5 pl-7.25 pr-1.75 leading-none text-c-1",
|
|
133
133
|
"data-1p-ignore": "",
|
|
134
134
|
placeholder: __props.placeholder,
|
|
135
135
|
role: "combobox",
|
|
@@ -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 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/**\n * Space toggles the active option in multiselect mode while the search box is empty.\n *\n * The options look like checkboxes, so keyboard users press Space to toggle them. Without this\n * handler Space types a leading space into the query, which filters out every option whose label\n * has no space and hides the whole list without any feedback (found by an accessibility audit).\n * Once a query has been typed, Space keeps inserting a character so multi-word labels stay\n * searchable. Key auto-repeat is ignored so holding Space after opening the popover with it does\n * not toggle the option repeatedly, and IME composition is left alone.\n */\nconst handleSpace = (event: KeyboardEvent): void => {\n if (!multiselect || query.value !== '' || event.isComposing) {\n return\n }\n // Suppress repeated spaces too, so holding the key does not start filtering.\n event.preventDefault()\n if (!event.repeat) {\n toggleSelected(activeRef.value)\n }\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-expanded=\"Boolean(filtered.length || slots.add || noResults)\"\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.space=\"handleSpace\"\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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"}
|
|
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/**\n * Space toggles the active option in multiselect mode while the search box is empty.\n *\n * The options look like checkboxes, so keyboard users press Space to toggle them. Without this\n * handler Space types a leading space into the query, which filters out every option whose label\n * has no space and hides the whole list without any feedback (found by an accessibility audit).\n * Once a query has been typed, Space keeps inserting a character so multi-word labels stay\n * searchable. Key auto-repeat is ignored so holding Space after opening the popover with it does\n * not toggle the option repeatedly, and IME composition is left alone.\n */\nconst handleSpace = (event: KeyboardEvent): void => {\n if (!multiselect || query.value !== '' || event.isComposing) {\n return\n }\n // Suppress repeated spaces too, so holding the key does not start filtering.\n event.preventDefault()\n if (!event.repeat) {\n toggleSelected(activeRef.value)\n }\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 <!-- Inset to line up with the options below -->\n <div class=\"relative flex m-1 mb-0.75\">\n <ScalarIconMagnifyingGlass\n class=\"pointer-events-none absolute left-1.75 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-expanded=\"Boolean(filtered.length || slots.add || noResults)\"\n :aria-label=\"inputLabel\"\n class=\"min-w-0 flex-1 rounded-md border-0 py-1.5 pl-7.25 pr-1.75 leading-none text-c-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.space=\"handleSpace\"\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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarComboboxPopover.vue.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxPopover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Popover component\n *\n * Wraps combobox content in a floating popover panel.\n * Handles open/close behavior and keyboard interactions.\n *\n * @example\n * <ScalarComboboxPopover>\n * <button>Toggle</button>\n * <template #popover=\"{ close }\">Content</template>\n * </ScalarComboboxPopover>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { ref } from 'vue'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport type { ScalarPopoverSlots } from '../ScalarPopover'\n\ndefineProps<ScalarFloatingOptions>()\n\ndefineSlots<ScalarPopoverSlots>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n\n/** Expose the popover button so we can close the popup */\nconst popoverButtonRef = ref<typeof PopoverButton | null>(null)\n\n/** Open the popover of the up or down arrows are pressed */\nconst handleKeydown = (e: KeyboardEvent) => {\n if (!['ArrowUp', 'ArrowDown'].includes(e.key)) {\n return\n }\n e.preventDefault()\n e.target?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))\n}\n\ndefineExpose({ popoverButtonRef })\n</script>\n<template>\n <Popover\n v-slot=\"{ open }\"\n as=\"template\">\n <ScalarFloating v-bind=\"$props\">\n <PopoverButton\n ref=\"popoverButtonRef\"\n as=\"template\"\n @keydown=\"handleKeydown\">\n <slot :open />\n </PopoverButton>\n <template\n v-if=\"open\"\n #floating=\"{ width }\">\n <PopoverPanel\n v-slot=\"{ close }\"\n :style=\"{ width }\"\n v-bind=\"\n cx('relative flex flex-col max-h-[inherit] w-40 rounded text-sm')\n \">\n <slot\n :close\n name=\"popover\"\n :open />\n <ScalarFloatingBackdrop />\n </PopoverPanel>\n </template>\n </ScalarFloating>\n </Popover>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarComboboxPopover.vue.js","names":[],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxPopover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Popover component\n *\n * Wraps combobox content in a floating popover panel.\n * Handles open/close behavior and keyboard interactions.\n *\n * @example\n * <ScalarComboboxPopover>\n * <button>Toggle</button>\n * <template #popover=\"{ close }\">Content</template>\n * </ScalarComboboxPopover>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { ref } from 'vue'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport type { ScalarPopoverSlots } from '../ScalarPopover'\n\ndefineProps<ScalarFloatingOptions>()\n\ndefineSlots<ScalarPopoverSlots>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n\n/** Expose the popover button so we can close the popup */\nconst popoverButtonRef = ref<typeof PopoverButton | null>(null)\n\n/** Open the popover of the up or down arrows are pressed */\nconst handleKeydown = (e: KeyboardEvent) => {\n if (!['ArrowUp', 'ArrowDown'].includes(e.key)) {\n return\n }\n e.preventDefault()\n e.target?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))\n}\n\ndefineExpose({ popoverButtonRef })\n</script>\n<template>\n <Popover\n v-slot=\"{ open }\"\n as=\"template\">\n <ScalarFloating v-bind=\"$props\">\n <PopoverButton\n ref=\"popoverButtonRef\"\n as=\"template\"\n @keydown=\"handleKeydown\">\n <slot :open />\n </PopoverButton>\n <template\n v-if=\"open\"\n #floating=\"{ width }\">\n <PopoverPanel\n v-slot=\"{ close }\"\n :style=\"{ width }\"\n v-bind=\"\n cx('relative flex flex-col max-h-[inherit] w-40 rounded-xl text-sm')\n \">\n <slot\n :close\n name=\"popover\"\n :open />\n <ScalarFloatingBackdrop />\n </PopoverPanel>\n </template>\n </ScalarFloating>\n </Popover>\n</template>\n"],"mappings":""}
|
|
@@ -44,7 +44,7 @@ var ScalarComboboxPopover_vue_vue_type_script_setup_true_lang_default = /*@__PUR
|
|
|
44
44
|
_: 2
|
|
45
45
|
}, [open ? {
|
|
46
46
|
name: "floating",
|
|
47
|
-
fn: withCtx(({ width }) => [createVNode(unref(PopoverPanel), mergeProps({ style: { width } }, unref(cx)("relative flex flex-col max-h-[inherit] w-40 rounded text-sm")), {
|
|
47
|
+
fn: withCtx(({ width }) => [createVNode(unref(PopoverPanel), mergeProps({ style: { width } }, unref(cx)("relative flex flex-col max-h-[inherit] w-40 rounded-xl text-sm")), {
|
|
48
48
|
default: withCtx(({ close }) => [renderSlot(_ctx.$slots, "popover", {
|
|
49
49
|
close,
|
|
50
50
|
open
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarComboboxPopover.vue.script.js","names":["$props"],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxPopover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Popover component\n *\n * Wraps combobox content in a floating popover panel.\n * Handles open/close behavior and keyboard interactions.\n *\n * @example\n * <ScalarComboboxPopover>\n * <button>Toggle</button>\n * <template #popover=\"{ close }\">Content</template>\n * </ScalarComboboxPopover>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { ref } from 'vue'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport type { ScalarPopoverSlots } from '../ScalarPopover'\n\ndefineProps<ScalarFloatingOptions>()\n\ndefineSlots<ScalarPopoverSlots>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n\n/** Expose the popover button so we can close the popup */\nconst popoverButtonRef = ref<typeof PopoverButton | null>(null)\n\n/** Open the popover of the up or down arrows are pressed */\nconst handleKeydown = (e: KeyboardEvent) => {\n if (!['ArrowUp', 'ArrowDown'].includes(e.key)) {\n return\n }\n e.preventDefault()\n e.target?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))\n}\n\ndefineExpose({ popoverButtonRef })\n</script>\n<template>\n <Popover\n v-slot=\"{ open }\"\n as=\"template\">\n <ScalarFloating v-bind=\"$props\">\n <PopoverButton\n ref=\"popoverButtonRef\"\n as=\"template\"\n @keydown=\"handleKeydown\">\n <slot :open />\n </PopoverButton>\n <template\n v-if=\"open\"\n #floating=\"{ width }\">\n <PopoverPanel\n v-slot=\"{ close }\"\n :style=\"{ width }\"\n v-bind=\"\n cx('relative flex flex-col max-h-[inherit] w-40 rounded text-sm')\n \">\n <slot\n :close\n name=\"popover\"\n :open />\n <ScalarFloatingBackdrop />\n </PopoverPanel>\n </template>\n </ScalarFloating>\n </Popover>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAiCA,MAAM,EAAE,OAAO,UAAU;;EAGzB,MAAM,mBAAmB,IAAiC,IAAI;;EAG9D,MAAM,iBAAiB,MAAqB;GAC1C,IAAI,CAAC,CAAC,WAAW,WAAW,CAAC,CAAC,SAAS,EAAE,GAAG,GAC1C;GAEF,EAAE,eAAe;GACjB,EAAE,QAAQ,cAAc,IAAI,cAAc,WAAW,EAAE,KAAK,QAAQ,CAAC,CAAC;EACxE;EAEA,SAAa,EAAE,iBAAiB,CAAC;;uBAG/B,YA2BU,MAAA,OAAA,GAAA,EAzBR,IAAG,WAAU,GAAA;sBAwBI,EAzBP,WAAI,CAEd,YAuBiB,MAAA,sBAAA,GAAA,eAAA,mBAvBOA,KAAAA,MAAM,CAAA,GAAA,YAAA;4BAMZ,CALhB,YAKgB,MAAA,aAAA,GAAA;eAJV;MAAJ,KAAI;MACJ,IAAG;MACF,WAAS;;6BACI,CAAd,WAAc,KAAA,QAAA,WAAA,EAAP,KAAI,CAAA,CAAA,CAAA;;;;QAGL,OAAA;WACL;kBAYc,EAZF,YAAK,CAClB,YAWe,MAAA,YAAA,GAXf,WAWe,EATZ,OAAK,EAAI,MAAK,EAAA,GACM,MAAA,EAAA,CAAE,CAAA,
|
|
1
|
+
{"version":3,"file":"ScalarComboboxPopover.vue.script.js","names":["$props"],"sources":["../../../src/components/ScalarCombobox/ScalarComboboxPopover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Combobox Popover component\n *\n * Wraps combobox content in a floating popover panel.\n * Handles open/close behavior and keyboard interactions.\n *\n * @example\n * <ScalarComboboxPopover>\n * <button>Toggle</button>\n * <template #popover=\"{ close }\">Content</template>\n * </ScalarComboboxPopover>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\nimport { ref } from 'vue'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport type { ScalarPopoverSlots } from '../ScalarPopover'\n\ndefineProps<ScalarFloatingOptions>()\n\ndefineSlots<ScalarPopoverSlots>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n\n/** Expose the popover button so we can close the popup */\nconst popoverButtonRef = ref<typeof PopoverButton | null>(null)\n\n/** Open the popover of the up or down arrows are pressed */\nconst handleKeydown = (e: KeyboardEvent) => {\n if (!['ArrowUp', 'ArrowDown'].includes(e.key)) {\n return\n }\n e.preventDefault()\n e.target?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }))\n}\n\ndefineExpose({ popoverButtonRef })\n</script>\n<template>\n <Popover\n v-slot=\"{ open }\"\n as=\"template\">\n <ScalarFloating v-bind=\"$props\">\n <PopoverButton\n ref=\"popoverButtonRef\"\n as=\"template\"\n @keydown=\"handleKeydown\">\n <slot :open />\n </PopoverButton>\n <template\n v-if=\"open\"\n #floating=\"{ width }\">\n <PopoverPanel\n v-slot=\"{ close }\"\n :style=\"{ width }\"\n v-bind=\"\n cx('relative flex flex-col max-h-[inherit] w-40 rounded-xl text-sm')\n \">\n <slot\n :close\n name=\"popover\"\n :open />\n <ScalarFloatingBackdrop />\n </PopoverPanel>\n </template>\n </ScalarFloating>\n </Popover>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EAiCA,MAAM,EAAE,OAAO,UAAU;;EAGzB,MAAM,mBAAmB,IAAiC,IAAI;;EAG9D,MAAM,iBAAiB,MAAqB;GAC1C,IAAI,CAAC,CAAC,WAAW,WAAW,CAAC,CAAC,SAAS,EAAE,GAAG,GAC1C;GAEF,EAAE,eAAe;GACjB,EAAE,QAAQ,cAAc,IAAI,cAAc,WAAW,EAAE,KAAK,QAAQ,CAAC,CAAC;EACxE;EAEA,SAAa,EAAE,iBAAiB,CAAC;;uBAG/B,YA2BU,MAAA,OAAA,GAAA,EAzBR,IAAG,WAAU,GAAA;sBAwBI,EAzBP,WAAI,CAEd,YAuBiB,MAAA,sBAAA,GAAA,eAAA,mBAvBOA,KAAAA,MAAM,CAAA,GAAA,YAAA;4BAMZ,CALhB,YAKgB,MAAA,aAAA,GAAA;eAJV;MAAJ,KAAI;MACJ,IAAG;MACF,WAAS;;6BACI,CAAd,WAAc,KAAA,QAAA,WAAA,EAAP,KAAI,CAAA,CAAA,CAAA;;;;QAGL,OAAA;WACL;kBAYc,EAZF,YAAK,CAClB,YAWe,MAAA,YAAA,GAXf,WAWe,EATZ,OAAK,EAAI,MAAK,EAAA,GACM,MAAA,EAAA,CAAE,CAAA,gEAAA,CAAA,GAAA;wBAMb,EARA,YAAK,CAKf,WAGU,KAAA,QAAA,WAAA;OAFP;OAEA;UACH,YAA0B,MAAA,8BAAA,CAAA,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;EAyElB,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
|
|
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 rounded-xl')\">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1 rounded-[inherit]\">\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":""}
|
|
@@ -2,7 +2,7 @@ import ScalarFloatingBackdrop_default from "../ScalarFloating/ScalarFloatingBack
|
|
|
2
2
|
import { useBindCx } from "@scalar/use-hooks/useBindCx";
|
|
3
3
|
import { createBlock, createElementVNode, createVNode, defineComponent, guardReactiveProps, normalizeProps, openBlock, renderSlot, resolveDynamicComponent, unref, withCtx } from "vue";
|
|
4
4
|
//#region src/components/ScalarDropdown/ScalarDropdownMenu.vue?vue&type=script&setup=true&lang.ts
|
|
5
|
-
var _hoisted_1 = { class: "custom-scroll min-h-0 flex-1" };
|
|
5
|
+
var _hoisted_1 = { class: "custom-scroll min-h-0 flex-1 rounded-[inherit]" };
|
|
6
6
|
var _hoisted_2 = { class: "flex flex-col p-0.75" };
|
|
7
7
|
var ScalarDropdownMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
8
8
|
inheritAttrs: false,
|
|
@@ -11,8 +11,8 @@ var ScalarDropdownMenu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
|
|
|
11
11
|
setup(__props) {
|
|
12
12
|
const { cx } = useBindCx();
|
|
13
13
|
return (_ctx, _cache) => {
|
|
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)
|
|
14
|
+
return openBlock(), createBlock(resolveDynamicComponent(__props.is ?? "div"), normalizeProps(guardReactiveProps(unref(cx)("relative flex w-56 rounded-xl"))), {
|
|
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))])])]),
|
|
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
|
|
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 rounded-xl')\">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1 rounded-[inherit]\">\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,+BAAA,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,YAA0B,MAAA,8BAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
* You can use this component directly if you need to customize the backdrop
|
|
9
9
|
* for a floating component
|
|
10
10
|
*
|
|
11
|
+
* The backdrop inherits its border radius from its parent, so set the radius
|
|
12
|
+
* on the floating element itself and the backdrop will follow it
|
|
13
|
+
*
|
|
11
14
|
* @example
|
|
12
15
|
* <ScalarDropdown>
|
|
13
16
|
* <!-- Menu stuff -->
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarFloatingBackdrop.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarFloating/ScalarFloatingBackdrop.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ScalarFloatingBackdrop.vue.d.ts","sourceRoot":"","sources":["../../../src/components/ScalarFloating/ScalarFloatingBackdrop.vue"],"names":[],"mappings":"AAuDA;;;;;;;;;;;;;;;;;;;;GAoBG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAGzC,QAAA,MAAM,YAAY;cAwCJ,CAAC,KAAK,IAAgB,KAAK,GAAG;EAQxC,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":"ScalarFloatingBackdrop.vue.js","names":[],"sources":["../../../src/components/ScalarFloating/ScalarFloatingBackdrop.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar floating backdrop component\n *\n * Provides an absolutely positioned backdrop for the floating element\n * This is used internally by a number of the Scalar floating components\n * (e.g. Dropdown, Popover, Listbox)\n *\n * You can use this component directly if you need to customize the backdrop\n * for a floating component\n *\n * @example\n * <ScalarDropdown>\n * <!-- Menu stuff -->\n * <template #backdrop>\n * <ScalarFloatingBackdrop />\n * </template>\n * </ScalarDropdown>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <div\n v-bind=\"\n cx('absolute inset-0 -z-1 rounded bg-b-1 shadow-
|
|
1
|
+
{"version":3,"file":"ScalarFloatingBackdrop.vue.js","names":[],"sources":["../../../src/components/ScalarFloating/ScalarFloatingBackdrop.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar floating backdrop component\n *\n * Provides an absolutely positioned backdrop for the floating element\n * This is used internally by a number of the Scalar floating components\n * (e.g. Dropdown, Popover, Listbox)\n *\n * You can use this component directly if you need to customize the backdrop\n * for a floating component\n *\n * The backdrop inherits its border radius from its parent, so set the radius\n * on the floating element itself and the backdrop will follow it\n *\n * @example\n * <ScalarDropdown>\n * <!-- Menu stuff -->\n * <template #backdrop>\n * <ScalarFloatingBackdrop />\n * </template>\n * </ScalarDropdown>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <div\n v-bind=\"\n cx(\n 'absolute inset-0 -z-1 overflow-hidden rounded-[inherit] bg-b-1 shadow-md',\n // Browsers round sub-pixel borders up to a full pixel, so the hairline\n // is an inset shadow painted above the lifted layer instead\n 'after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:shadow-border',\n )\n \">\n <!--\n The lifted brightness lives on an inner layer so it does not also\n brighten the border, which would stop it matching adjacent inputs\n -->\n <div class=\"absolute inset-0 bg-inherit brightness-lifted\">\n <slot />\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { useBindCx } from "@scalar/use-hooks/useBindCx";
|
|
2
|
-
import { createElementBlock, defineComponent, guardReactiveProps, normalizeProps, openBlock, renderSlot, unref } from "vue";
|
|
2
|
+
import { createElementBlock, createElementVNode, defineComponent, guardReactiveProps, normalizeProps, openBlock, renderSlot, unref } from "vue";
|
|
3
|
+
//#region src/components/ScalarFloating/ScalarFloatingBackdrop.vue?vue&type=script&setup=true&lang.ts
|
|
4
|
+
var _hoisted_1 = { class: "absolute inset-0 bg-inherit brightness-lifted" };
|
|
3
5
|
var ScalarFloatingBackdrop_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
4
6
|
inheritAttrs: false,
|
|
5
7
|
__name: "ScalarFloatingBackdrop",
|
|
6
8
|
setup(__props) {
|
|
7
9
|
const { cx } = useBindCx();
|
|
8
10
|
return (_ctx, _cache) => {
|
|
9
|
-
return openBlock(), createElementBlock("div", normalizeProps(guardReactiveProps(unref(cx)("absolute inset-0 -z-1 rounded bg-b-1 shadow-
|
|
11
|
+
return openBlock(), createElementBlock("div", normalizeProps(guardReactiveProps(unref(cx)("absolute inset-0 -z-1 overflow-hidden rounded-[inherit] bg-b-1 shadow-md", "after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:shadow-border"))), [createElementVNode("div", _hoisted_1, [renderSlot(_ctx.$slots, "default")])], 16);
|
|
10
12
|
};
|
|
11
13
|
}
|
|
12
14
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarFloatingBackdrop.vue.script.js","names":[],"sources":["../../../src/components/ScalarFloating/ScalarFloatingBackdrop.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar floating backdrop component\n *\n * Provides an absolutely positioned backdrop for the floating element\n * This is used internally by a number of the Scalar floating components\n * (e.g. Dropdown, Popover, Listbox)\n *\n * You can use this component directly if you need to customize the backdrop\n * for a floating component\n *\n * @example\n * <ScalarDropdown>\n * <!-- Menu stuff -->\n * <template #backdrop>\n * <ScalarFloatingBackdrop />\n * </template>\n * </ScalarDropdown>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <div\n v-bind=\"\n cx('absolute inset-0 -z-1 rounded bg-b-1 shadow-
|
|
1
|
+
{"version":3,"file":"ScalarFloatingBackdrop.vue.script.js","names":[],"sources":["../../../src/components/ScalarFloating/ScalarFloatingBackdrop.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar floating backdrop component\n *\n * Provides an absolutely positioned backdrop for the floating element\n * This is used internally by a number of the Scalar floating components\n * (e.g. Dropdown, Popover, Listbox)\n *\n * You can use this component directly if you need to customize the backdrop\n * for a floating component\n *\n * The backdrop inherits its border radius from its parent, so set the radius\n * on the floating element itself and the backdrop will follow it\n *\n * @example\n * <ScalarDropdown>\n * <!-- Menu stuff -->\n * <template #backdrop>\n * <ScalarFloatingBackdrop />\n * </template>\n * </ScalarDropdown>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <div\n v-bind=\"\n cx(\n 'absolute inset-0 -z-1 overflow-hidden rounded-[inherit] bg-b-1 shadow-md',\n // Browsers round sub-pixel borders up to a full pixel, so the hairline\n // is an inset shadow painted above the lifted layer instead\n 'after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:shadow-border',\n )\n \">\n <!--\n The lifted brightness lives on an inner layer so it does not also\n brighten the border, which would stop it matching adjacent inputs\n -->\n <div class=\"absolute inset-0 bg-inherit brightness-lifted\">\n <slot />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;EA4BA,MAAM,EAAE,OAAO,UAAU;;uBAGvB,mBAgBM,OAAA,eAAA,mBAfW,MAAA,EAAA,CAAE,CAAA,4EAAA,oGAAA,CAAA,CAAA,GAAA,CAYjB,mBAEM,OAFN,YAEM,CADJ,WAAQ,KAAA,QAAA,SAAA,CAAA,CAAA,CAAA,GAAA,EAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarListbox.vue.js","names":[],"sources":["../../../src/components/ScalarListbox/ScalarListbox.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Listbox component\n *\n * A dropdown select component built on HeadlessUI Listbox.\n * Supports single and multiple selection modes.\n *\n * @example\n * <ScalarListbox v-model=\"selected\" :options=\"options\">\n * <ScalarButton>{{ selected?.label ?? 'Select' }}</ScalarButton>\n * </ScalarListbox>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n Listbox,\n ListboxButton,\n ListboxLabel,\n ListboxOptions,\n} from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport ScalarListboxOption from './ScalarListboxItem.vue'\nimport type { Option } from './types'\n\ntype SingleSelectListboxProps = {\n multiple?: false | undefined\n modelValue?: Option | undefined\n}\n\ntype MultipleSelectListboxProps = {\n multiple: true\n modelValue?: Option[] | undefined\n}\n\ndefineProps<\n {\n options: Option[]\n id?: string\n label?: string\n } & (SingleSelectListboxProps | MultipleSelectListboxProps) &\n ScalarFloatingOptions\n>()\n\ndefineEmits<{\n (e: 'update:modelValue', v: Option): void\n}>()\n\ndefineSlots<{\n /** The reference element for the listbox */\n default(props: {\n /** Whether or not the listbox is open */\n open: boolean\n }): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <Listbox\n v-slot=\"{ open }\"\n :modelValue=\"modelValue\"\n :multiple=\"multiple\"\n @update:modelValue=\"(v) => $emit('update:modelValue', v)\">\n <ListboxLabel\n v-if=\"label\"\n class=\"sr-only\">\n {{ label }}\n </ListboxLabel>\n <ScalarFloating\n v-bind=\"$props\"\n :placement=\"placement ?? 'bottom-start'\">\n <ListboxButton\n :id=\"id\"\n as=\"template\">\n <slot :open=\"open\" />\n </ListboxButton>\n <template #floating=\"{ width }\">\n <!-- Background container -->\n <div\n v-if=\"open\"\n :style=\"{ width }\"\n v-bind=\"\n cx(\n 'relative flex max-h-[inherit] w-40 max-w-[inherit] rounded text-sm',\n )\n \">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1\">\n <!-- Options list -->\n <ListboxOptions\n class=\"flex flex-col gap-0.75 p-0.75 -outline-offset-1\">\n <ScalarListboxOption\n v-for=\"option in options\"\n :key=\"option.id\"\n :multiselect=\"multiple\"\n :option=\"option\" />\n </ListboxOptions>\n </div>\n <ScalarFloatingBackdrop />\n </div>\n </template>\n </ScalarFloating>\n </Listbox>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarListbox.vue.js","names":[],"sources":["../../../src/components/ScalarListbox/ScalarListbox.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Listbox component\n *\n * A dropdown select component built on HeadlessUI Listbox.\n * Supports single and multiple selection modes.\n *\n * @example\n * <ScalarListbox v-model=\"selected\" :options=\"options\">\n * <ScalarButton>{{ selected?.label ?? 'Select' }}</ScalarButton>\n * </ScalarListbox>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n Listbox,\n ListboxButton,\n ListboxLabel,\n ListboxOptions,\n} from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport ScalarListboxOption from './ScalarListboxItem.vue'\nimport type { Option } from './types'\n\ntype SingleSelectListboxProps = {\n multiple?: false | undefined\n modelValue?: Option | undefined\n}\n\ntype MultipleSelectListboxProps = {\n multiple: true\n modelValue?: Option[] | undefined\n}\n\ndefineProps<\n {\n options: Option[]\n id?: string\n label?: string\n } & (SingleSelectListboxProps | MultipleSelectListboxProps) &\n ScalarFloatingOptions\n>()\n\ndefineEmits<{\n (e: 'update:modelValue', v: Option): void\n}>()\n\ndefineSlots<{\n /** The reference element for the listbox */\n default(props: {\n /** Whether or not the listbox is open */\n open: boolean\n }): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <Listbox\n v-slot=\"{ open }\"\n :modelValue=\"modelValue\"\n :multiple=\"multiple\"\n @update:modelValue=\"(v) => $emit('update:modelValue', v)\">\n <ListboxLabel\n v-if=\"label\"\n class=\"sr-only\">\n {{ label }}\n </ListboxLabel>\n <ScalarFloating\n v-bind=\"$props\"\n :placement=\"placement ?? 'bottom-start'\">\n <ListboxButton\n :id=\"id\"\n as=\"template\">\n <slot :open=\"open\" />\n </ListboxButton>\n <template #floating=\"{ width }\">\n <!-- Background container -->\n <div\n v-if=\"open\"\n :style=\"{ width }\"\n v-bind=\"\n cx(\n 'relative flex max-h-[inherit] w-40 max-w-[inherit] rounded-xl text-sm',\n )\n \">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1\">\n <!-- Options list -->\n <ListboxOptions\n class=\"flex flex-col gap-0.75 p-0.75 -outline-offset-1\">\n <ScalarListboxOption\n v-for=\"option in options\"\n :key=\"option.id\"\n :multiselect=\"multiple\"\n :option=\"option\" />\n </ListboxOptions>\n </div>\n <ScalarFloatingBackdrop />\n </div>\n </template>\n </ScalarFloating>\n </Listbox>\n</template>\n"],"mappings":""}
|
|
@@ -45,7 +45,7 @@ var ScalarListbox_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
45
45
|
floating: withCtx(({ width }) => [open ? (openBlock(), createElementBlock("div", mergeProps({
|
|
46
46
|
key: 0,
|
|
47
47
|
style: { width }
|
|
48
|
-
}, unref(cx)("relative flex max-h-[inherit] w-40 max-w-[inherit] rounded text-sm")), [createElementVNode("div", _hoisted_1, [createVNode(unref(ListboxOptions), { class: "flex flex-col gap-0.75 p-0.75 -outline-offset-1" }, {
|
|
48
|
+
}, unref(cx)("relative flex max-h-[inherit] w-40 max-w-[inherit] rounded-xl text-sm")), [createElementVNode("div", _hoisted_1, [createVNode(unref(ListboxOptions), { class: "flex flex-col gap-0.75 p-0.75 -outline-offset-1" }, {
|
|
49
49
|
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.options, (option) => {
|
|
50
50
|
return openBlock(), createBlock(ScalarListboxItem_default, {
|
|
51
51
|
key: option.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarListbox.vue.script.js","names":["$emit","$props"],"sources":["../../../src/components/ScalarListbox/ScalarListbox.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Listbox component\n *\n * A dropdown select component built on HeadlessUI Listbox.\n * Supports single and multiple selection modes.\n *\n * @example\n * <ScalarListbox v-model=\"selected\" :options=\"options\">\n * <ScalarButton>{{ selected?.label ?? 'Select' }}</ScalarButton>\n * </ScalarListbox>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n Listbox,\n ListboxButton,\n ListboxLabel,\n ListboxOptions,\n} from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport ScalarListboxOption from './ScalarListboxItem.vue'\nimport type { Option } from './types'\n\ntype SingleSelectListboxProps = {\n multiple?: false | undefined\n modelValue?: Option | undefined\n}\n\ntype MultipleSelectListboxProps = {\n multiple: true\n modelValue?: Option[] | undefined\n}\n\ndefineProps<\n {\n options: Option[]\n id?: string\n label?: string\n } & (SingleSelectListboxProps | MultipleSelectListboxProps) &\n ScalarFloatingOptions\n>()\n\ndefineEmits<{\n (e: 'update:modelValue', v: Option): void\n}>()\n\ndefineSlots<{\n /** The reference element for the listbox */\n default(props: {\n /** Whether or not the listbox is open */\n open: boolean\n }): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <Listbox\n v-slot=\"{ open }\"\n :modelValue=\"modelValue\"\n :multiple=\"multiple\"\n @update:modelValue=\"(v) => $emit('update:modelValue', v)\">\n <ListboxLabel\n v-if=\"label\"\n class=\"sr-only\">\n {{ label }}\n </ListboxLabel>\n <ScalarFloating\n v-bind=\"$props\"\n :placement=\"placement ?? 'bottom-start'\">\n <ListboxButton\n :id=\"id\"\n as=\"template\">\n <slot :open=\"open\" />\n </ListboxButton>\n <template #floating=\"{ width }\">\n <!-- Background container -->\n <div\n v-if=\"open\"\n :style=\"{ width }\"\n v-bind=\"\n cx(\n 'relative flex max-h-[inherit] w-40 max-w-[inherit] rounded text-sm',\n )\n \">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1\">\n <!-- Options list -->\n <ListboxOptions\n class=\"flex flex-col gap-0.75 p-0.75 -outline-offset-1\">\n <ScalarListboxOption\n v-for=\"option in options\"\n :key=\"option.id\"\n :multiselect=\"multiple\"\n :option=\"option\" />\n </ListboxOptions>\n </div>\n <ScalarFloatingBackdrop />\n </div>\n </template>\n </ScalarFloating>\n </Listbox>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgEA,MAAM,EAAE,OAAO,UAAU;;uBAGvB,YA4CU,MAAA,OAAA,GAAA;IA1CP,YAAY,QAAA;IACZ,UAAU,QAAA;IACV,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAMA,KAAAA,MAAK,qBAAsB,CAAC;;sBAKxC,EARL,WAAI,CAKN,QAAA,SAAA,UAAA,GADR,YAIe,MAAA,YAAA,GAAA;;KAFb,OAAM;;4BACK,CAAA,gBAAA,gBAAR,QAAA,KAAK,GAAA,CAAA,CAAA,CAAA;;wCAEV,YAiCiB,MAAA,sBAAA,GAjCjB,WACUC,KAgCO,QAhCD,EACb,WAAW,QAAA,aAAS,eAAA,CAAA,GAAA;KAMV,UAAQ,SAuBX,EAvBe,YAAK,CAGlB,QAAA,UAAA,GADR,mBAqBM,OArBN,WAqBM;;MAnBH,OAAK,EAAI,MAAK;QACM,MAAA,EAAA,CAAE,CAAA,
|
|
1
|
+
{"version":3,"file":"ScalarListbox.vue.script.js","names":["$emit","$props"],"sources":["../../../src/components/ScalarListbox/ScalarListbox.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Listbox component\n *\n * A dropdown select component built on HeadlessUI Listbox.\n * Supports single and multiple selection modes.\n *\n * @example\n * <ScalarListbox v-model=\"selected\" :options=\"options\">\n * <ScalarButton>{{ selected?.label ?? 'Select' }}</ScalarButton>\n * </ScalarListbox>\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n Listbox,\n ListboxButton,\n ListboxLabel,\n ListboxOptions,\n} from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport ScalarListboxOption from './ScalarListboxItem.vue'\nimport type { Option } from './types'\n\ntype SingleSelectListboxProps = {\n multiple?: false | undefined\n modelValue?: Option | undefined\n}\n\ntype MultipleSelectListboxProps = {\n multiple: true\n modelValue?: Option[] | undefined\n}\n\ndefineProps<\n {\n options: Option[]\n id?: string\n label?: string\n } & (SingleSelectListboxProps | MultipleSelectListboxProps) &\n ScalarFloatingOptions\n>()\n\ndefineEmits<{\n (e: 'update:modelValue', v: Option): void\n}>()\n\ndefineSlots<{\n /** The reference element for the listbox */\n default(props: {\n /** Whether or not the listbox is open */\n open: boolean\n }): unknown\n}>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <Listbox\n v-slot=\"{ open }\"\n :modelValue=\"modelValue\"\n :multiple=\"multiple\"\n @update:modelValue=\"(v) => $emit('update:modelValue', v)\">\n <ListboxLabel\n v-if=\"label\"\n class=\"sr-only\">\n {{ label }}\n </ListboxLabel>\n <ScalarFloating\n v-bind=\"$props\"\n :placement=\"placement ?? 'bottom-start'\">\n <ListboxButton\n :id=\"id\"\n as=\"template\">\n <slot :open=\"open\" />\n </ListboxButton>\n <template #floating=\"{ width }\">\n <!-- Background container -->\n <div\n v-if=\"open\"\n :style=\"{ width }\"\n v-bind=\"\n cx(\n 'relative flex max-h-[inherit] w-40 max-w-[inherit] rounded-xl text-sm',\n )\n \">\n <!-- Scroll container -->\n <div class=\"custom-scroll min-h-0 flex-1\">\n <!-- Options list -->\n <ListboxOptions\n class=\"flex flex-col gap-0.75 p-0.75 -outline-offset-1\">\n <ScalarListboxOption\n v-for=\"option in options\"\n :key=\"option.id\"\n :multiselect=\"multiple\"\n :option=\"option\" />\n </ListboxOptions>\n </div>\n <ScalarFloatingBackdrop />\n </div>\n </template>\n </ScalarFloating>\n </Listbox>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgEA,MAAM,EAAE,OAAO,UAAU;;uBAGvB,YA4CU,MAAA,OAAA,GAAA;IA1CP,YAAY,QAAA;IACZ,UAAU,QAAA;IACV,uBAAiB,OAAA,OAAA,OAAA,MAAG,MAAMA,KAAAA,MAAK,qBAAsB,CAAC;;sBAKxC,EARL,WAAI,CAKN,QAAA,SAAA,UAAA,GADR,YAIe,MAAA,YAAA,GAAA;;KAFb,OAAM;;4BACK,CAAA,gBAAA,gBAAR,QAAA,KAAK,GAAA,CAAA,CAAA,CAAA;;wCAEV,YAiCiB,MAAA,sBAAA,GAjCjB,WACUC,KAgCO,QAhCD,EACb,WAAW,QAAA,aAAS,eAAA,CAAA,GAAA;KAMV,UAAQ,SAuBX,EAvBe,YAAK,CAGlB,QAAA,UAAA,GADR,mBAqBM,OArBN,WAqBM;;MAnBH,OAAK,EAAI,MAAK;QACM,MAAA,EAAA,CAAE,CAAA,uEAAA,CAAA,GAAA,CAMvB,mBAUM,OAVN,YAUM,CARJ,YAOiB,MAAA,cAAA,GAAA,EANf,OAAM,kDAAiD,GAAA;6BAE5B,EAAA,UAAA,IAAA,GAD3B,mBAIqB,UAAA,MAAA,WAHF,QAAA,UAAV,WAAM;2BADf,YAIqB,2BAAA;QAFlB,KAAK,OAAO;QACZ,aAAa,QAAA;QACL;;;;WAGf,YAA0B,MAAA,8BAAA,CAAA,CAAA,GAAA,EAAA,KAAA,mBAAA,IAAA,IAAA,CAAA,CAAA;4BAvBd,CAJhB,YAIgB,MAAA,aAAA,GAAA;MAHb,IAAI,QAAA;MACL,IAAG;;6BACkB,CAArB,WAAqB,KAAA,QAAA,WAAA,EAAR,KAAI,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarListboxItem.vue.js","names":[],"sources":["../../../src/components/ScalarListbox/ScalarListboxItem.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Listbox Item component\n *\n * A single option within a ScalarListbox dropdown.\n * Handles active, selected, and disabled states.\n *\n * @example\n * <ScalarListboxItem :option=\"{ id: '1', label: 'Option 1' }\" />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ListboxOption } from '@headlessui/vue'\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\n\nimport ScalarListboxCheckbox from './ScalarListboxCheckbox.vue'\nimport type { Option } from './types'\n\ndefineProps<{\n option: Option\n multiselect?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Layout\n 'group/item',\n 'flex min-w-0 items-center gap-1.5 rounded px-2 py-1.5 text-left',\n // Text / background style\n 'truncate bg-transparent text-c-1',\n // Interaction\n 'cursor-pointer hover:bg-b-2',\n ],\n variants: {\n selected: { true: 'text-c-1' },\n active: { true: 'bg-b-2' },\n disabled: { true: 'pointer-events-none opacity-50' },\n },\n})\n</script>\n<template>\n <ListboxOption\n v-slot=\"{ active, selected }\"\n as=\"template\"\n :disabled=\"option.disabled\"\n :value=\"option\">\n <li :class=\"cx(variants({ active, selected, disabled: option.disabled }))\">\n <ScalarListboxCheckbox\n :multiselect\n :selected />\n <span\n class=\"inline-block min-w-0 flex-1 truncate\"\n :class=\"option.color ? option.color : 'text-c-1'\">\n {{ option.label }}\n </span>\n </li>\n </ListboxOption>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarListboxItem.vue.js","names":[],"sources":["../../../src/components/ScalarListbox/ScalarListboxItem.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Listbox Item component\n *\n * A single option within a ScalarListbox dropdown.\n * Handles active, selected, and disabled states.\n *\n * @example\n * <ScalarListboxItem :option=\"{ id: '1', label: 'Option 1' }\" />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ListboxOption } from '@headlessui/vue'\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\n\nimport ScalarListboxCheckbox from './ScalarListboxCheckbox.vue'\nimport type { Option } from './types'\n\ndefineProps<{\n option: Option\n multiselect?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Layout\n 'group/item',\n 'flex min-w-0 items-center gap-1.5 rounded-md px-2 py-1.5 text-left',\n // Text / background style\n 'truncate bg-transparent text-c-1',\n // Interaction\n 'cursor-pointer hover:bg-b-2',\n ],\n variants: {\n selected: { true: 'text-c-1' },\n active: { true: 'bg-b-2' },\n disabled: { true: 'pointer-events-none opacity-50' },\n },\n})\n</script>\n<template>\n <ListboxOption\n v-slot=\"{ active, selected }\"\n as=\"template\"\n :disabled=\"option.disabled\"\n :value=\"option\">\n <li :class=\"cx(variants({ active, selected, disabled: option.disabled }))\">\n <ScalarListboxCheckbox\n :multiselect\n :selected />\n <span\n class=\"inline-block min-w-0 flex-1 truncate\"\n :class=\"option.color ? option.color : 'text-c-1'\">\n {{ option.label }}\n </span>\n </li>\n </ListboxOption>\n</template>\n"],"mappings":""}
|
|
@@ -12,7 +12,7 @@ var ScalarListboxItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
|
|
|
12
12
|
const variants = cva({
|
|
13
13
|
base: [
|
|
14
14
|
"group/item",
|
|
15
|
-
"flex min-w-0 items-center gap-1.5 rounded px-2 py-1.5 text-left",
|
|
15
|
+
"flex min-w-0 items-center gap-1.5 rounded-md px-2 py-1.5 text-left",
|
|
16
16
|
"truncate bg-transparent text-c-1",
|
|
17
17
|
"cursor-pointer hover:bg-b-2"
|
|
18
18
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarListboxItem.vue.script.js","names":[],"sources":["../../../src/components/ScalarListbox/ScalarListboxItem.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Listbox Item component\n *\n * A single option within a ScalarListbox dropdown.\n * Handles active, selected, and disabled states.\n *\n * @example\n * <ScalarListboxItem :option=\"{ id: '1', label: 'Option 1' }\" />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ListboxOption } from '@headlessui/vue'\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\n\nimport ScalarListboxCheckbox from './ScalarListboxCheckbox.vue'\nimport type { Option } from './types'\n\ndefineProps<{\n option: Option\n multiselect?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Layout\n 'group/item',\n 'flex min-w-0 items-center gap-1.5 rounded px-2 py-1.5 text-left',\n // Text / background style\n 'truncate bg-transparent text-c-1',\n // Interaction\n 'cursor-pointer hover:bg-b-2',\n ],\n variants: {\n selected: { true: 'text-c-1' },\n active: { true: 'bg-b-2' },\n disabled: { true: 'pointer-events-none opacity-50' },\n },\n})\n</script>\n<template>\n <ListboxOption\n v-slot=\"{ active, selected }\"\n as=\"template\"\n :disabled=\"option.disabled\"\n :value=\"option\">\n <li :class=\"cx(variants({ active, selected, disabled: option.disabled }))\">\n <ScalarListboxCheckbox\n :multiselect\n :selected />\n <span\n class=\"inline-block min-w-0 flex-1 truncate\"\n :class=\"option.color ? option.color : 'text-c-1'\">\n {{ option.label }}\n </span>\n </li>\n </ListboxOption>\n</template>\n"],"mappings":";;;;;;;;;;;EAyBA,MAAM,WAAW,IAAI;GACnB,MAAM;IAEJ;IACA;IAEA;IAEA;GACF;GACA,UAAU;IACR,UAAU,EAAE,MAAM,WAAW;IAC7B,QAAQ,EAAE,MAAM,SAAS;IACzB,UAAU,EAAE,MAAM,iCAAiC;GACrD;EACF,CAAC;;uBAGC,YAegB,MAAA,aAAA,GAAA;IAbd,IAAG;IACF,UAAU,QAAA,OAAO;IACjB,OAAO,QAAA;;sBAUH,EAbK,QAAQ,eAAQ,CAI1B,mBASK,MAAA,EATA,OAAK,eAAE,MAAA,EAAA,CAAE,CAAC,MAAA,QAAA,CAAQ,CAAA;KAAG;KAAQ;KAAQ,UAAY,QAAA,OAAO;IAAQ,CAAA,CAAA,CAAA,EAAA,GAAA,CACnE,YAEc,+BAAA;KADX,aAAA,QAAA;KACA;8CACH,mBAIO,QAAA,EAHL,OAAK,eAAA,CAAC,wCACE,QAAA,OAAO,QAAQ,QAAA,OAAO,QAAK,UAAA,CAAA,EAAA,GAAA,gBAChC,QAAA,OAAO,KAAK,GAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"ScalarListboxItem.vue.script.js","names":[],"sources":["../../../src/components/ScalarListbox/ScalarListboxItem.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Listbox Item component\n *\n * A single option within a ScalarListbox dropdown.\n * Handles active, selected, and disabled states.\n *\n * @example\n * <ScalarListboxItem :option=\"{ id: '1', label: 'Option 1' }\" />\n */\nexport default {}\n</script>\n\n<script setup lang=\"ts\">\nimport { ListboxOption } from '@headlessui/vue'\nimport { cva, cx } from '@scalar/use-hooks/useBindCx'\n\nimport ScalarListboxCheckbox from './ScalarListboxCheckbox.vue'\nimport type { Option } from './types'\n\ndefineProps<{\n option: Option\n multiselect?: boolean\n}>()\n\nconst variants = cva({\n base: [\n // Layout\n 'group/item',\n 'flex min-w-0 items-center gap-1.5 rounded-md px-2 py-1.5 text-left',\n // Text / background style\n 'truncate bg-transparent text-c-1',\n // Interaction\n 'cursor-pointer hover:bg-b-2',\n ],\n variants: {\n selected: { true: 'text-c-1' },\n active: { true: 'bg-b-2' },\n disabled: { true: 'pointer-events-none opacity-50' },\n },\n})\n</script>\n<template>\n <ListboxOption\n v-slot=\"{ active, selected }\"\n as=\"template\"\n :disabled=\"option.disabled\"\n :value=\"option\">\n <li :class=\"cx(variants({ active, selected, disabled: option.disabled }))\">\n <ScalarListboxCheckbox\n :multiselect\n :selected />\n <span\n class=\"inline-block min-w-0 flex-1 truncate\"\n :class=\"option.color ? option.color : 'text-c-1'\">\n {{ option.label }}\n </span>\n </li>\n </ListboxOption>\n</template>\n"],"mappings":";;;;;;;;;;;EAyBA,MAAM,WAAW,IAAI;GACnB,MAAM;IAEJ;IACA;IAEA;IAEA;GACF;GACA,UAAU;IACR,UAAU,EAAE,MAAM,WAAW;IAC7B,QAAQ,EAAE,MAAM,SAAS;IACzB,UAAU,EAAE,MAAM,iCAAiC;GACrD;EACF,CAAC;;uBAGC,YAegB,MAAA,aAAA,GAAA;IAbd,IAAG;IACF,UAAU,QAAA,OAAO;IACjB,OAAO,QAAA;;sBAUH,EAbK,QAAQ,eAAQ,CAI1B,mBASK,MAAA,EATA,OAAK,eAAE,MAAA,EAAA,CAAE,CAAC,MAAA,QAAA,CAAQ,CAAA;KAAG;KAAQ;KAAQ,UAAY,QAAA,OAAO;IAAQ,CAAA,CAAA,CAAA,EAAA,GAAA,CACnE,YAEc,+BAAA;KADX,aAAA,QAAA;KACA;8CACH,mBAIO,QAAA,EAHL,OAAK,eAAA,CAAC,wCACE,QAAA,OAAO,QAAQ,QAAA,OAAO,QAAK,UAAA,CAAA,EAAA,GAAA,gBAChC,QAAA,OAAO,KAAK,GAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarPopover.vue.js","names":[],"sources":["../../../src/components/ScalarPopover/ScalarPopover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Popover component\n *\n * A floating panel that appears when a trigger element is clicked.\n * Built on HeadlessUI Popover with Floating UI positioning.\n *\n * @example\n * <ScalarPopover>\n * <button>Open</button>\n * <template #popover=\"{ close }\">Popover content</template>\n * </ScalarPopover>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport type { Slots } from './types'\n\ndefineProps<\n {\n /** Automatically focus the popover panel when it opens */\n focus?: boolean\n } & ScalarFloatingOptions\n>()\n\ndefineSlots<Slots>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <Popover\n v-slot=\"{ open }\"\n as=\"template\">\n <ScalarFloating v-bind=\"$props\">\n <PopoverButton as=\"template\">\n <slot :open=\"open\" />\n </PopoverButton>\n <template #floating=\"{ width, height }\">\n <PopoverPanel\n v-slot=\"{ close }\"\n :focus=\"focus\"\n :style=\"{ width, height }\"\n v-bind=\"cx('relative flex flex-col p-0.75')\">\n <slot\n :close=\"() => close()\"\n name=\"popover\"\n :open=\"open\" />\n <slot\n name=\"backdrop\"\n :open=\"open\">\n <ScalarFloatingBackdrop />\n </slot>\n </PopoverPanel>\n </template>\n </ScalarFloating>\n </Popover>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ScalarPopover.vue.js","names":[],"sources":["../../../src/components/ScalarPopover/ScalarPopover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Popover component\n *\n * A floating panel that appears when a trigger element is clicked.\n * Built on HeadlessUI Popover with Floating UI positioning.\n *\n * @example\n * <ScalarPopover>\n * <button>Open</button>\n * <template #popover=\"{ close }\">Popover content</template>\n * </ScalarPopover>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport type { Slots } from './types'\n\ndefineProps<\n {\n /** Automatically focus the popover panel when it opens */\n focus?: boolean\n } & ScalarFloatingOptions\n>()\n\ndefineSlots<Slots>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <Popover\n v-slot=\"{ open }\"\n as=\"template\">\n <ScalarFloating v-bind=\"$props\">\n <PopoverButton as=\"template\">\n <slot :open=\"open\" />\n </PopoverButton>\n <template #floating=\"{ width, height }\">\n <PopoverPanel\n v-slot=\"{ close }\"\n :focus=\"focus\"\n :style=\"{ width, height }\"\n v-bind=\"cx('relative flex flex-col rounded-xl p-0.75')\">\n <slot\n :close=\"() => close()\"\n name=\"popover\"\n :open=\"open\" />\n <slot\n name=\"backdrop\"\n :open=\"open\">\n <ScalarFloatingBackdrop />\n </slot>\n </PopoverPanel>\n </template>\n </ScalarFloating>\n </Popover>\n</template>\n"],"mappings":""}
|
|
@@ -30,7 +30,7 @@ var ScalarPopover_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
|
|
|
30
30
|
width,
|
|
31
31
|
height
|
|
32
32
|
}
|
|
33
|
-
}, unref(cx)("relative flex flex-col p-0.75")), {
|
|
33
|
+
}, unref(cx)("relative flex flex-col rounded-xl p-0.75")), {
|
|
34
34
|
default: withCtx(({ close }) => [renderSlot(_ctx.$slots, "popover", {
|
|
35
35
|
close: () => close(),
|
|
36
36
|
open
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScalarPopover.vue.script.js","names":["$props"],"sources":["../../../src/components/ScalarPopover/ScalarPopover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Popover component\n *\n * A floating panel that appears when a trigger element is clicked.\n * Built on HeadlessUI Popover with Floating UI positioning.\n *\n * @example\n * <ScalarPopover>\n * <button>Open</button>\n * <template #popover=\"{ close }\">Popover content</template>\n * </ScalarPopover>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport type { Slots } from './types'\n\ndefineProps<\n {\n /** Automatically focus the popover panel when it opens */\n focus?: boolean\n } & ScalarFloatingOptions\n>()\n\ndefineSlots<Slots>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <Popover\n v-slot=\"{ open }\"\n as=\"template\">\n <ScalarFloating v-bind=\"$props\">\n <PopoverButton as=\"template\">\n <slot :open=\"open\" />\n </PopoverButton>\n <template #floating=\"{ width, height }\">\n <PopoverPanel\n v-slot=\"{ close }\"\n :focus=\"focus\"\n :style=\"{ width, height }\"\n v-bind=\"cx('relative flex flex-col p-0.75')\">\n <slot\n :close=\"() => close()\"\n name=\"popover\"\n :open=\"open\" />\n <slot\n name=\"backdrop\"\n :open=\"open\">\n <ScalarFloatingBackdrop />\n </slot>\n </PopoverPanel>\n </template>\n </ScalarFloating>\n </Popover>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAoCA,MAAM,EAAE,OAAO,UAAU;;uBAGvB,YAyBU,MAAA,OAAA,GAAA,EAvBR,IAAG,WAAU,GAAA;sBAsBI,EAvBP,WAAI,CAEd,YAqBiB,MAAA,sBAAA,GAAA,eAAA,mBArBOA,KAAAA,MAAM,CAAA,GAAA;KAIjB,UAAQ,SAeF,EAfM,OAAO,aAAM,CAClC,YAce,MAAA,YAAA,GAdf,WAce;MAZZ,OAAO,QAAA;MACP,OAAK;OAAI;OAAO;MAAM;QACf,MAAA,EAAA,CAAE,CAAA
|
|
1
|
+
{"version":3,"file":"ScalarPopover.vue.script.js","names":["$props"],"sources":["../../../src/components/ScalarPopover/ScalarPopover.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Scalar Popover component\n *\n * A floating panel that appears when a trigger element is clicked.\n * Built on HeadlessUI Popover with Floating UI positioning.\n *\n * @example\n * <ScalarPopover>\n * <button>Open</button>\n * <template #popover=\"{ close }\">Popover content</template>\n * </ScalarPopover>\n */\nexport default {}\n</script>\n<script setup lang=\"ts\">\nimport { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'\nimport { useBindCx } from '@scalar/use-hooks/useBindCx'\n\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n type ScalarFloatingOptions,\n} from '../ScalarFloating'\nimport type { Slots } from './types'\n\ndefineProps<\n {\n /** Automatically focus the popover panel when it opens */\n focus?: boolean\n } & ScalarFloatingOptions\n>()\n\ndefineSlots<Slots>()\n\ndefineOptions({ inheritAttrs: false })\nconst { cx } = useBindCx()\n</script>\n<template>\n <Popover\n v-slot=\"{ open }\"\n as=\"template\">\n <ScalarFloating v-bind=\"$props\">\n <PopoverButton as=\"template\">\n <slot :open=\"open\" />\n </PopoverButton>\n <template #floating=\"{ width, height }\">\n <PopoverPanel\n v-slot=\"{ close }\"\n :focus=\"focus\"\n :style=\"{ width, height }\"\n v-bind=\"cx('relative flex flex-col rounded-xl p-0.75')\">\n <slot\n :close=\"() => close()\"\n name=\"popover\"\n :open=\"open\" />\n <slot\n name=\"backdrop\"\n :open=\"open\">\n <ScalarFloatingBackdrop />\n </slot>\n </PopoverPanel>\n </template>\n </ScalarFloating>\n </Popover>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAoCA,MAAM,EAAE,OAAO,UAAU;;uBAGvB,YAyBU,MAAA,OAAA,GAAA,EAvBR,IAAG,WAAU,GAAA;sBAsBI,EAvBP,WAAI,CAEd,YAqBiB,MAAA,sBAAA,GAAA,eAAA,mBArBOA,KAAAA,MAAM,CAAA,GAAA;KAIjB,UAAQ,SAeF,EAfM,OAAO,aAAM,CAClC,YAce,MAAA,YAAA,GAdf,WAce;MAZZ,OAAO,QAAA;MACP,OAAK;OAAI;OAAO;MAAM;QACf,MAAA,EAAA,CAAE,CAAA,0CAAA,CAAA,GAAA;wBAIO,EAPP,YAAK,CAIf,WAGiB,KAAA,QAAA,WAAA;OAFd,aAAa,MAAK;OAEZ;UACT,WAIO,KAAA,QAAA,YAAA,EAFE,KAAI,SAEN,CADL,YAA0B,MAAA,8BAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;4BAdhB,CAFhB,YAEgB,MAAA,aAAA,GAAA,EAFD,IAAG,WAAU,GAAA;6BACL,CAArB,WAAqB,KAAA,QAAA,WAAA,EAAR,KAAI,CAAA,CAAA,CAAA"}
|
package/dist/style.css
CHANGED
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
--tw-backdrop-sepia: initial;
|
|
87
87
|
--tw-duration: initial;
|
|
88
88
|
--tw-ease: initial;
|
|
89
|
+
--tw-content: "";
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
}
|
|
@@ -783,6 +784,10 @@
|
|
|
783
784
|
left: 0;
|
|
784
785
|
}
|
|
785
786
|
|
|
787
|
+
.scalar-app .left-1\.75 {
|
|
788
|
+
left: 7px;
|
|
789
|
+
}
|
|
790
|
+
|
|
786
791
|
.scalar-app .left-1\/2 {
|
|
787
792
|
left: 50%;
|
|
788
793
|
}
|
|
@@ -791,10 +796,6 @@
|
|
|
791
796
|
left: 8px;
|
|
792
797
|
}
|
|
793
798
|
|
|
794
|
-
.scalar-app .left-2\.5 {
|
|
795
|
-
left: 10px;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
799
|
.scalar-app .left-3 {
|
|
799
800
|
left: 12px;
|
|
800
801
|
}
|
|
@@ -1035,6 +1036,10 @@
|
|
|
1035
1036
|
margin-bottom: 0;
|
|
1036
1037
|
}
|
|
1037
1038
|
|
|
1039
|
+
.scalar-app .mb-0\.75 {
|
|
1040
|
+
margin-bottom: 3px;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1038
1043
|
.scalar-app .-ml-0\.5 {
|
|
1039
1044
|
margin-left: -2px;
|
|
1040
1045
|
}
|
|
@@ -2165,10 +2170,6 @@
|
|
|
2165
2170
|
padding-block: 8px;
|
|
2166
2171
|
}
|
|
2167
2172
|
|
|
2168
|
-
.scalar-app .py-2\.5 {
|
|
2169
|
-
padding-block: 10px;
|
|
2170
|
-
}
|
|
2171
|
-
|
|
2172
2173
|
.scalar-app .py-3 {
|
|
2173
2174
|
padding-block: 12px;
|
|
2174
2175
|
}
|
|
@@ -2201,8 +2202,8 @@
|
|
|
2201
2202
|
padding-right: 6px;
|
|
2202
2203
|
}
|
|
2203
2204
|
|
|
2204
|
-
.scalar-app .pr-
|
|
2205
|
-
padding-right:
|
|
2205
|
+
.scalar-app .pr-1\.75 {
|
|
2206
|
+
padding-right: 7px;
|
|
2206
2207
|
}
|
|
2207
2208
|
|
|
2208
2209
|
.scalar-app .pr-6 {
|
|
@@ -2229,8 +2230,8 @@
|
|
|
2229
2230
|
padding-left: 12px;
|
|
2230
2231
|
}
|
|
2231
2232
|
|
|
2232
|
-
.scalar-app .pl-
|
|
2233
|
-
padding-left:
|
|
2233
|
+
.scalar-app .pl-7\.25 {
|
|
2234
|
+
padding-left: 29px;
|
|
2234
2235
|
}
|
|
2235
2236
|
|
|
2236
2237
|
.scalar-app .pl-\[100\%\] {
|
|
@@ -2766,6 +2767,32 @@
|
|
|
2766
2767
|
font-family: inherit;
|
|
2767
2768
|
}
|
|
2768
2769
|
|
|
2770
|
+
.scalar-app .after\:pointer-events-none:after {
|
|
2771
|
+
content: var(--tw-content);
|
|
2772
|
+
pointer-events: none;
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2775
|
+
.scalar-app .after\:absolute:after {
|
|
2776
|
+
content: var(--tw-content);
|
|
2777
|
+
position: absolute;
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
.scalar-app .after\:inset-0:after {
|
|
2781
|
+
content: var(--tw-content);
|
|
2782
|
+
inset: 0;
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
.scalar-app .after\:rounded-\[inherit\]:after {
|
|
2786
|
+
content: var(--tw-content);
|
|
2787
|
+
border-radius: inherit;
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
.scalar-app .after\:shadow-border:after {
|
|
2791
|
+
content: var(--tw-content);
|
|
2792
|
+
--tw-shadow: inset 0 0 0 var(--scalar-border-width) var(--scalar-border-color);
|
|
2793
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2769
2796
|
.scalar-app .first\:rounded-t-\[inherit\]:first-child {
|
|
2770
2797
|
border-top-left-radius: inherit;
|
|
2771
2798
|
border-top-right-radius: inherit;
|
|
@@ -3501,6 +3528,12 @@
|
|
|
3501
3528
|
inherits: false
|
|
3502
3529
|
}
|
|
3503
3530
|
|
|
3531
|
+
@property --tw-content {
|
|
3532
|
+
syntax: "*";
|
|
3533
|
+
inherits: false;
|
|
3534
|
+
initial-value: "";
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3504
3537
|
@keyframes pulse {
|
|
3505
3538
|
50% {
|
|
3506
3539
|
opacity: .5;
|
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.30.
|
|
13
|
+
"version": "0.30.7",
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=22"
|
|
16
16
|
},
|
|
@@ -217,10 +217,10 @@
|
|
|
217
217
|
"@headlessui/tailwindcss": "^0.2.2",
|
|
218
218
|
"@headlessui/vue": "1.7.23",
|
|
219
219
|
"@scalar/code-highlight": "0.4.8",
|
|
220
|
-
"@scalar/helpers": "0.16.
|
|
220
|
+
"@scalar/helpers": "0.16.1",
|
|
221
221
|
"@scalar/icons": "0.7.6",
|
|
222
222
|
"@scalar/themes": "0.18.1",
|
|
223
|
-
"@scalar/use-hooks": "0.4.
|
|
223
|
+
"@scalar/use-hooks": "0.4.18",
|
|
224
224
|
"@vueuse/core": "13.9.0",
|
|
225
225
|
"cva": "1.0.0-beta.4",
|
|
226
226
|
"radix-vue": "^1.9.17",
|