@sparklingopinions/sparkling-ui 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/aliases.d.ts +47 -10
  2. package/dist/components/Calendar/Calendar.js.map +1 -1
  3. package/dist/components/Calendar/Calendar.vue.d.ts +2 -2
  4. package/dist/components/Calendar/Calendar.vue_vue_type_script_setup_true_lang.js +6 -14
  5. package/dist/components/Calendar/Calendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  6. package/dist/components/Dialog/Dialog.js.map +1 -1
  7. package/dist/components/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js +26 -29
  8. package/dist/components/Dialog/Dialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  9. package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
  10. package/dist/components/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js +1 -1
  11. package/dist/components/DropdownMenu/DropdownMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  12. package/dist/components/Filters/FilterChip.js.map +1 -1
  13. package/dist/components/Filters/FilterChip.vue_vue_type_script_setup_true_lang.js +2 -2
  14. package/dist/components/Filters/FilterChip.vue_vue_type_script_setup_true_lang.js.map +1 -1
  15. package/dist/components/Filters/FilterMenu.js.map +1 -1
  16. package/dist/components/Filters/FilterMenu.vue_vue_type_script_setup_true_lang.js +1 -1
  17. package/dist/components/Filters/FilterMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  18. package/dist/components/Filters/SortMenu.js.map +1 -1
  19. package/dist/components/Filters/SortMenu.vue_vue_type_script_setup_true_lang.js +1 -1
  20. package/dist/components/Filters/SortMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  21. package/dist/components/Input/Input.js.map +1 -1
  22. package/dist/components/Input/Input.vue_vue_type_script_setup_true_lang.js +1 -1
  23. package/dist/components/Input/Input.vue_vue_type_script_setup_true_lang.js.map +1 -1
  24. package/dist/components/Popover/Popover.js.map +1 -1
  25. package/dist/components/Popover/Popover.vue.d.ts +3 -0
  26. package/dist/components/Popover/Popover.vue_vue_type_script_setup_true_lang.js +38 -30
  27. package/dist/components/Popover/Popover.vue_vue_type_script_setup_true_lang.js.map +1 -1
  28. package/dist/components/PropertyList/Editable.js.map +1 -1
  29. package/dist/components/PropertyList/Editable.vue_vue_type_script_setup_true_lang.js +6 -4
  30. package/dist/components/PropertyList/Editable.vue_vue_type_script_setup_true_lang.js.map +1 -1
  31. package/dist/components/PropertyList/PropertyList.js.map +1 -1
  32. package/dist/components/PropertyList/PropertyList.vue.d.ts +17 -2
  33. package/dist/components/PropertyList/PropertyList.vue_vue_type_script_setup_true_lang.js +19 -14
  34. package/dist/components/PropertyList/PropertyList.vue_vue_type_script_setup_true_lang.js.map +1 -1
  35. package/dist/components/PropertyRow/Collapsible.js.map +1 -1
  36. package/dist/components/PropertyRow/Collapsible.vue.d.ts +1 -1
  37. package/dist/components/PropertyRow/Collapsible.vue_vue_type_script_setup_true_lang.js +12 -12
  38. package/dist/components/PropertyRow/Collapsible.vue_vue_type_script_setup_true_lang.js.map +1 -1
  39. package/dist/components/Radio/Radio.js.map +1 -1
  40. package/dist/components/Radio/Radio.vue_vue_type_script_setup_true_lang.js +1 -1
  41. package/dist/components/Radio/Radio.vue_vue_type_script_setup_true_lang.js.map +1 -1
  42. package/dist/components/Select/Select.js.map +1 -1
  43. package/dist/components/Select/Select.vue.d.ts +10 -1
  44. package/dist/components/Select/Select.vue_vue_type_script_setup_true_lang.js +125 -101
  45. package/dist/components/Select/Select.vue_vue_type_script_setup_true_lang.js.map +1 -1
  46. package/dist/components/Textarea/Textarea.js.map +1 -1
  47. package/dist/components/Textarea/Textarea.vue_vue_type_script_setup_true_lang.js +1 -1
  48. package/dist/components/Textarea/Textarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/styles/tailwind.css +4 -2
@@ -1 +1 @@
1
- {"version":3,"file":"FilterChip.js","names":["_sfc_main","FilterChip_vue_vue_type_script_setup_true_lang_default","FilterChip_default"],"sources":["../../../src/components/Filters/FilterChip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n DropdownMenuContent,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuRoot,\n DropdownMenuTrigger,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n RadioGroupItem,\n RadioGroupRoot\n} from 'reka-ui'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Icon from '../Icon/Icon.vue'\nimport Input from '../Input/Input.vue'\nimport SegmentedControl from '../SegmentedControl/SegmentedControl.vue'\nimport CheckIcon from '../internal/CheckIcon.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport { datePresets as defaultDatePresets, describeFilter, filterOperators } from './defaults'\nimport type { FilterFieldType, FilterOperator, FilterOption, FilterValue } from './types'\n\nexport interface FilterChipProps {\n /** A filter, read as a sentence; `add` is the quiet \"+ Filter\" that starts one (FilterMenu includes it). */\n kind?: 'filter' | 'add'\n field?: string\n /** Picks the editor: a checklist for enum, person and company, an input for text and number, presets for date, Yes / No for boolean. */\n type?: FilterFieldType\n /** An app icon for the field, instead of the type's glyph. */\n icon?: string\n /** The operators offered; English ones by type by default. */\n operators?: FilterOperator[]\n /** The choices for enum, person and company. */\n options?: FilterOption[]\n /** The live result count in the panel's footer, e.g. \"120 people\". */\n status?: string\n /** The plural noun once more than two values are picked: \"3 stages\". */\n valueLabel?: string\n datePresets?: string[]\n /** Adds a Remove action to the panel (`@remove`). */\n onRemove?: () => void\n removeLabel?: string\n addLabel?: string\n operatorLabel?: string\n searchPlaceholder?: string\n valuePlaceholder?: string\n doneLabel?: string\n closeLabel?: string\n yesLabel?: string\n noLabel?: string\n}\n\n// Attributes and listeners go to the chip itself; the root is a renderless popover.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterChipProps>(), {\n kind: 'filter',\n field: undefined,\n type: 'enum',\n icon: undefined,\n operators: undefined,\n options: () => [],\n status: undefined,\n valueLabel: 'values',\n datePresets: () => defaultDatePresets,\n onRemove: undefined,\n removeLabel: 'Remove',\n addLabel: 'Filter',\n operatorLabel: 'Operator',\n searchPlaceholder: 'Search…',\n valuePlaceholder: 'Type a value',\n doneLabel: 'Done',\n closeLabel: 'Close',\n yesLabel: 'Yes',\n noLabel: 'No'\n})\n\nconst op = defineModel<string>('op')\nconst value = defineModel<FilterValue>({ default: null })\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n /** Your own editor, in place of the type's. */\n default?: () => unknown\n}>()\n\nconst attrs = useAttrs()\n\nconst ops = computed(() => props.operators ?? filterOperators[props.type])\nconst current = computed(() => ops.value.find((o) => o.value === op.value))\nconst needsValue = computed(() => !current.value?.noValue)\nconst text = computed(() =>\n needsValue.value\n ? describeFilter(value.value, props.options, {\n valueLabel: props.valueLabel,\n yesLabel: props.yesLabel,\n noLabel: props.noLabel\n })\n : ''\n)\nconst isChecklist = computed(() => ['enum', 'person', 'company'].includes(props.type))\n\nconst query = ref('')\nconst listed = computed(() => {\n const q = query.value.trim().toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nconst picked = computed(() => (Array.isArray(value.value) ? value.value : []))\n\nfunction toggle(choice: string | number) {\n value.value = picked.value.includes(choice) ? picked.value.filter((v) => v !== choice) : [...picked.value, choice]\n}\n\nfunction remove() {\n open.value = false\n props.onRemove?.()\n}\n\nconst chip =\n 'inline-flex h-7.5 items-center gap-1.5 rounded-lg border text-13 whitespace-nowrap outline-hidden transition-[border-color,box-shadow] duration-150 focus-visible:sui-ring'\nconst row =\n 'flex min-h-8 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-left text-13.5 outline-hidden transition-colors duration-100 focus-visible:sui-ring-inset'\nconst rowOn = 'bg-sui-accent-wash font-semibold text-sui-accent'\nconst rowOff = 'text-sui-ink hover:bg-sui-sunken'\nconst hueDots: Record<string, string> = {\n blue: 'bg-sui-hue-blue-ink',\n green: 'bg-sui-hue-green-ink',\n orange: 'bg-sui-hue-orange-ink',\n pink: 'bg-sui-hue-pink-ink',\n purple: 'bg-sui-hue-purple-ink',\n slate: 'bg-sui-hue-slate-ink',\n red: 'bg-sui-hue-red-ink',\n amber: 'bg-sui-hue-amber-ink'\n}\n</script>\n\n<!-- A view's filter as a sentence chip (\"Stage is any of Lead, Customer\"), whose panel changes it as you go. -->\n<template>\n <button\n v-if=\"kind === 'add'\"\n v-bind=\"attrs\"\n class=\"border-dashed border-sui-line-strong px-2 font-medium text-sui-ink-muted hover:border-sui-ink-muted hover:text-sui-ink-body\"\n :class=\"chip\"\n type=\"button\"\n >\n <FilterGlyph name=\"plus\" />\n {{ addLabel }}\n </button>\n <PopoverRoot v-else v-model:open=\"open\">\n <PopoverTrigger\n v-bind=\"attrs\"\n class=\"border-sui-accent-line bg-sui-accent-wash pr-1.5 pl-2 text-sui-accent hover:border-sui-accent-bright data-[state=open]:border-sui-accent-solid data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n :class=\"chip\"\n >\n <Icon v-if=\"icon\" class=\"size-3.5 opacity-80\" color=\"accent\" :name=\"icon\" />\n <FilterGlyph v-else class=\"opacity-80\" :name=\"type\" />\n <!-- Real spaces between the words, so the chip's name reads as a sentence. -->\n <span\n ><span class=\"font-medium\">{{ field }}</span\n ><template v-if=\"current\">{{ ' ' }}{{ current.label }}</template\n ><template v-if=\"text\"\n >{{ ' ' }}<span class=\"font-semibold\">{{ text }}</span></template\n ></span\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 shrink-0 fill-none stroke-current opacity-70\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n >\n <FilterFrame :close-label=\"closeLabel\" :enter-label=\"doneLabel\" :status=\"status\" @enter=\"open = false\">\n <div class=\"flex h-11 items-center gap-1.5 pr-1.5 pl-3.5 text-sui-ink-muted\">\n <Icon v-if=\"icon\" color=\"ink-muted\" :name=\"icon\" />\n <FilterGlyph v-else class=\"size-4\" :name=\"type\" />\n <span class=\"text-sm font-semibold text-sui-ink\">{{ field }}</span>\n <DropdownMenuRoot v-if=\"ops.length > 1\">\n <DropdownMenuTrigger\n :aria-label=\"`${operatorLabel}: ${current?.label ?? ''}`\"\n class=\"inline-flex h-7 items-center gap-0.5 rounded-md pr-1 pl-1.5 text-13.5 font-medium text-sui-accent outline-hidden transition-colors duration-150 hover:bg-sui-accent-wash focus-visible:sui-ring-inset data-[state=open]:bg-sui-accent-wash\"\n >\n {{ current?.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </DropdownMenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuContent\n align=\"start\"\n class=\"z-[1001] w-44 rounded-lg border border-sui-line bg-sui-surface p-1 shadow-lg data-[state=open]:animate-sui-menu-in\"\n :side-offset=\"4\"\n >\n <DropdownMenuRadioGroup v-model=\"op\">\n <DropdownMenuRadioItem\n v-for=\"operator in ops\"\n :key=\"operator.value\"\n class=\"flex h-8 cursor-pointer items-center justify-between rounded-md px-2.5 text-13.5 text-sui-ink-body outline-hidden select-none data-highlighted:bg-sui-sunken data-[state=checked]:font-semibold data-[state=checked]:text-sui-ink\"\n :value=\"operator.value\"\n >\n {{ operator.label }}\n <CheckIcon v-if=\"operator.value === op\" />\n </DropdownMenuRadioItem>\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenuPortal>\n </DropdownMenuRoot>\n <span v-else class=\"text-13.5 text-sui-ink-muted\">{{ current?.label }}</span>\n <button\n v-if=\"onRemove\"\n class=\"ml-auto inline-flex h-7 items-center gap-1.5 rounded-lg px-2 text-12.5 font-medium text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-danger-soft hover:text-sui-danger focus-visible:sui-ring-inset\"\n type=\"button\"\n @click=\"remove\"\n >\n <FilterGlyph name=\"trash\" />\n {{ removeLabel }}\n </button>\n </div>\n\n <slot v-if=\"$slots.default\" />\n <template v-else-if=\"needsValue\">\n <template v-if=\"isChecklist\">\n <div\n v-if=\"options.length > 6\"\n class=\"mx-2 mb-1 flex h-9 items-center gap-2 rounded-lg border border-sui-line-subtle px-2.5 text-sui-ink-muted\"\n >\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <!-- focus: classes too: an app's forms plugin rings focused text fields, and outranks plain utilities. -->\n <input\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n autofocus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <div class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\">\n <label\n v-for=\"option in listed\"\n :key=\"option.value\"\n :class=\"[row, picked.includes(option.value) ? rowOn : rowOff]\"\n >\n <Checkbox :model-value=\"picked.includes(option.value)\" @update:model-value=\"toggle(option.value)\" />\n <span v-if=\"option.color\" class=\"size-1.5 shrink-0 rounded-full\" :class=\"hueDots[option.color]\" />\n <span class=\"min-w-0 flex-1 truncate\">{{ option.label }}</span>\n <span v-if=\"option.count != null\" class=\"text-xs font-normal text-sui-ink-muted tabular-nums\">{{\n option.count\n }}</span>\n </label>\n </div>\n </template>\n <div v-else-if=\"type === 'text' || type === 'number'\" class=\"px-2 pt-1 pb-2\">\n <Input\n :aria-label=\"field\"\n autofocus\n :model-value=\"value == null ? '' : String(value)\"\n :placeholder=\"valuePlaceholder\"\n :type=\"type === 'number' ? 'number' : 'text'\"\n @update:model-value=\"value = $event ?? null\"\n />\n </div>\n <RadioGroupRoot\n v-else-if=\"type === 'date'\"\n :aria-label=\"field\"\n class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\"\n :model-value=\"typeof value === 'string' ? value : undefined\"\n @update:model-value=\"value = String($event)\"\n >\n <RadioGroupItem\n v-for=\"preset in datePresets\"\n :key=\"preset\"\n :class=\"[row, preset === value ? rowOn : rowOff]\"\n :value=\"preset\"\n >\n <FilterGlyph\n class=\"size-4\"\n :class=\"preset === value ? 'text-sui-accent' : 'text-sui-ink-muted'\"\n name=\"date\"\n />\n <span class=\"min-w-0 flex-1 truncate\">{{ preset }}</span>\n <CheckIcon v-if=\"preset === value\" />\n </RadioGroupItem>\n </RadioGroupRoot>\n <div v-else-if=\"type === 'boolean'\" class=\"px-2.5 pt-1 pb-2.5\">\n <SegmentedControl\n :aria-label=\"field\"\n :model-value=\"value ? 'yes' : 'no'\"\n :options=\"[\n { value: 'yes', label: yesLabel },\n { value: 'no', label: noLabel }\n ]\"\n @update:model-value=\"value = $event === 'yes'\"\n />\n </div>\n </template>\n </FilterFrame>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"FilterChip.js","names":["_sfc_main","FilterChip_vue_vue_type_script_setup_true_lang_default","FilterChip_default"],"sources":["../../../src/components/Filters/FilterChip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n DropdownMenuContent,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuRoot,\n DropdownMenuTrigger,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n RadioGroupItem,\n RadioGroupRoot\n} from 'reka-ui'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Icon from '../Icon/Icon.vue'\nimport Input from '../Input/Input.vue'\nimport SegmentedControl from '../SegmentedControl/SegmentedControl.vue'\nimport CheckIcon from '../internal/CheckIcon.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport { datePresets as defaultDatePresets, describeFilter, filterOperators } from './defaults'\nimport type { FilterFieldType, FilterOperator, FilterOption, FilterValue } from './types'\n\nexport interface FilterChipProps {\n /** A filter, read as a sentence; `add` is the quiet \"+ Filter\" that starts one (FilterMenu includes it). */\n kind?: 'filter' | 'add'\n field?: string\n /** Picks the editor: a checklist for enum, person and company, an input for text and number, presets for date, Yes / No for boolean. */\n type?: FilterFieldType\n /** An app icon for the field, instead of the type's glyph. */\n icon?: string\n /** The operators offered; English ones by type by default. */\n operators?: FilterOperator[]\n /** The choices for enum, person and company. */\n options?: FilterOption[]\n /** The live result count in the panel's footer, e.g. \"120 people\". */\n status?: string\n /** The plural noun once more than two values are picked: \"3 stages\". */\n valueLabel?: string\n datePresets?: string[]\n /** Adds a Remove action to the panel (`@remove`). */\n onRemove?: () => void\n removeLabel?: string\n addLabel?: string\n operatorLabel?: string\n searchPlaceholder?: string\n valuePlaceholder?: string\n doneLabel?: string\n closeLabel?: string\n yesLabel?: string\n noLabel?: string\n}\n\n// Attributes and listeners go to the chip itself; the root is a renderless popover.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterChipProps>(), {\n kind: 'filter',\n field: undefined,\n type: 'enum',\n icon: undefined,\n operators: undefined,\n options: () => [],\n status: undefined,\n valueLabel: 'values',\n datePresets: () => defaultDatePresets,\n onRemove: undefined,\n removeLabel: 'Remove',\n addLabel: 'Filter',\n operatorLabel: 'Operator',\n searchPlaceholder: 'Search…',\n valuePlaceholder: 'Type a value',\n doneLabel: 'Done',\n closeLabel: 'Close',\n yesLabel: 'Yes',\n noLabel: 'No'\n})\n\nconst op = defineModel<string>('op')\nconst value = defineModel<FilterValue>({ default: null })\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n /** Your own editor, in place of the type's. */\n default?: () => unknown\n}>()\n\nconst attrs = useAttrs()\n\nconst ops = computed(() => props.operators ?? filterOperators[props.type])\nconst current = computed(() => ops.value.find((o) => o.value === op.value))\nconst needsValue = computed(() => !current.value?.noValue)\nconst text = computed(() =>\n needsValue.value\n ? describeFilter(value.value, props.options, {\n valueLabel: props.valueLabel,\n yesLabel: props.yesLabel,\n noLabel: props.noLabel\n })\n : ''\n)\nconst isChecklist = computed(() => ['enum', 'person', 'company'].includes(props.type))\n\nconst query = ref('')\nconst listed = computed(() => {\n const q = query.value.trim().toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nconst picked = computed(() => (Array.isArray(value.value) ? value.value : []))\n\nfunction toggle(choice: string | number) {\n value.value = picked.value.includes(choice) ? picked.value.filter((v) => v !== choice) : [...picked.value, choice]\n}\n\nfunction remove() {\n open.value = false\n props.onRemove?.()\n}\n\nconst chip =\n 'inline-flex h-7.5 items-center gap-1.5 rounded-lg border text-13 whitespace-nowrap outline-hidden transition-[border-color,box-shadow] duration-150 focus-visible:sui-ring'\nconst row =\n 'flex min-h-8 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-left text-13.5 outline-hidden transition-colors duration-100 focus-visible:sui-ring-inset'\nconst rowOn = 'bg-sui-accent-wash font-semibold text-sui-accent'\nconst rowOff = 'text-sui-ink hover:bg-sui-sunken'\nconst hueDots: Record<string, string> = {\n blue: 'bg-sui-hue-blue-ink',\n green: 'bg-sui-hue-green-ink',\n orange: 'bg-sui-hue-orange-ink',\n pink: 'bg-sui-hue-pink-ink',\n purple: 'bg-sui-hue-purple-ink',\n slate: 'bg-sui-hue-slate-ink',\n red: 'bg-sui-hue-red-ink',\n amber: 'bg-sui-hue-amber-ink'\n}\n</script>\n\n<!-- A view's filter as a sentence chip (\"Stage is any of Lead, Customer\"), whose panel changes it as you go. -->\n<template>\n <button\n v-if=\"kind === 'add'\"\n v-bind=\"attrs\"\n class=\"border-dashed border-sui-line-strong px-2 font-medium text-sui-ink-muted hover:border-sui-ink-muted hover:text-sui-ink-body\"\n :class=\"chip\"\n type=\"button\"\n >\n <FilterGlyph name=\"plus\" />\n {{ addLabel }}\n </button>\n <PopoverRoot v-else v-model:open=\"open\">\n <PopoverTrigger\n v-bind=\"attrs\"\n class=\"border-sui-accent-line bg-sui-accent-wash pr-1.5 pl-2 text-sui-accent hover:border-sui-accent-bright data-[state=open]:border-sui-accent-solid data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n :class=\"chip\"\n >\n <Icon v-if=\"icon\" class=\"size-3.5 opacity-80\" color=\"accent\" :name=\"icon\" />\n <FilterGlyph v-else class=\"opacity-80\" :name=\"type\" />\n <!-- Real spaces between the words, so the chip's name reads as a sentence. -->\n <span\n ><span class=\"font-medium\">{{ field }}</span\n ><template v-if=\"current\">{{ ' ' }}{{ current.label }}</template\n ><template v-if=\"text\"\n >{{ ' ' }}<span class=\"font-semibold\">{{ text }}</span></template\n ></span\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 shrink-0 fill-none stroke-current opacity-70\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n >\n <FilterFrame :close-label=\"closeLabel\" :enter-label=\"doneLabel\" :status=\"status\" @enter=\"open = false\">\n <div class=\"flex h-11 items-center gap-1.5 pr-1.5 pl-3.5 text-sui-ink-muted\">\n <Icon v-if=\"icon\" color=\"ink-muted\" :name=\"icon\" />\n <FilterGlyph v-else class=\"size-4\" :name=\"type\" />\n <span class=\"text-sm font-semibold text-sui-ink\">{{ field }}</span>\n <DropdownMenuRoot v-if=\"ops.length > 1\">\n <DropdownMenuTrigger\n :aria-label=\"`${operatorLabel}: ${current?.label ?? ''}`\"\n class=\"inline-flex h-7 items-center gap-0.5 rounded-md pr-1 pl-1.5 text-13.5 font-medium text-sui-accent outline-hidden transition-colors duration-150 hover:bg-sui-accent-wash focus-visible:sui-ring-inset data-[state=open]:bg-sui-accent-wash\"\n >\n {{ current?.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </DropdownMenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuContent\n align=\"start\"\n class=\"z-[1100] w-44 rounded-lg border border-sui-line bg-sui-surface p-1 shadow-lg data-[state=open]:animate-sui-menu-in\"\n :side-offset=\"4\"\n >\n <DropdownMenuRadioGroup v-model=\"op\">\n <DropdownMenuRadioItem\n v-for=\"operator in ops\"\n :key=\"operator.value\"\n class=\"flex h-8 cursor-pointer items-center justify-between rounded-md px-2.5 text-13.5 text-sui-ink-body outline-hidden select-none data-highlighted:bg-sui-sunken data-[state=checked]:font-semibold data-[state=checked]:text-sui-ink\"\n :value=\"operator.value\"\n >\n {{ operator.label }}\n <CheckIcon v-if=\"operator.value === op\" />\n </DropdownMenuRadioItem>\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenuPortal>\n </DropdownMenuRoot>\n <span v-else class=\"text-13.5 text-sui-ink-muted\">{{ current?.label }}</span>\n <button\n v-if=\"onRemove\"\n class=\"ml-auto inline-flex h-7 items-center gap-1.5 rounded-lg px-2 text-12.5 font-medium text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-danger-soft hover:text-sui-danger focus-visible:sui-ring-inset\"\n type=\"button\"\n @click=\"remove\"\n >\n <FilterGlyph name=\"trash\" />\n {{ removeLabel }}\n </button>\n </div>\n\n <slot v-if=\"$slots.default\" />\n <template v-else-if=\"needsValue\">\n <template v-if=\"isChecklist\">\n <div\n v-if=\"options.length > 6\"\n class=\"mx-2 mb-1 flex h-9 items-center gap-2 rounded-lg border border-sui-line-subtle px-2.5 text-sui-ink-muted\"\n >\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <!-- focus: classes too: an app's forms plugin rings focused text fields, and outranks plain utilities. -->\n <input\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n autofocus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <div class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\">\n <label\n v-for=\"option in listed\"\n :key=\"option.value\"\n :class=\"[row, picked.includes(option.value) ? rowOn : rowOff]\"\n >\n <Checkbox :model-value=\"picked.includes(option.value)\" @update:model-value=\"toggle(option.value)\" />\n <span v-if=\"option.color\" class=\"size-1.5 shrink-0 rounded-full\" :class=\"hueDots[option.color]\" />\n <span class=\"min-w-0 flex-1 truncate\">{{ option.label }}</span>\n <span v-if=\"option.count != null\" class=\"text-xs font-normal text-sui-ink-muted tabular-nums\">{{\n option.count\n }}</span>\n </label>\n </div>\n </template>\n <div v-else-if=\"type === 'text' || type === 'number'\" class=\"px-2 pt-1 pb-2\">\n <Input\n :aria-label=\"field\"\n autofocus\n :model-value=\"value == null ? '' : String(value)\"\n :placeholder=\"valuePlaceholder\"\n :type=\"type === 'number' ? 'number' : 'text'\"\n @update:model-value=\"value = $event ?? null\"\n />\n </div>\n <RadioGroupRoot\n v-else-if=\"type === 'date'\"\n :aria-label=\"field\"\n class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\"\n :model-value=\"typeof value === 'string' ? value : undefined\"\n @update:model-value=\"value = String($event)\"\n >\n <RadioGroupItem\n v-for=\"preset in datePresets\"\n :key=\"preset\"\n :class=\"[row, preset === value ? rowOn : rowOff]\"\n :value=\"preset\"\n >\n <FilterGlyph\n class=\"size-4\"\n :class=\"preset === value ? 'text-sui-accent' : 'text-sui-ink-muted'\"\n name=\"date\"\n />\n <span class=\"min-w-0 flex-1 truncate\">{{ preset }}</span>\n <CheckIcon v-if=\"preset === value\" />\n </RadioGroupItem>\n </RadioGroupRoot>\n <div v-else-if=\"type === 'boolean'\" class=\"px-2.5 pt-1 pb-2.5\">\n <SegmentedControl\n :aria-label=\"field\"\n :model-value=\"value ? 'yes' : 'no'\"\n :options=\"[\n { value: 'yes', label: yesLabel },\n { value: 'no', label: noLabel }\n ]\"\n @update:model-value=\"value = $event === 'yes'\"\n />\n </div>\n </template>\n </FilterFrame>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
@@ -141,7 +141,7 @@ var j = { class: "font-medium" }, M = { class: "font-semibold" }, N = { class: "
141
141
  }, 16), h(C(E), null, {
142
142
  default: T(() => [h(C(pe), {
143
143
  align: "start",
144
- class: "z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in",
144
+ class: "z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in",
145
145
  "side-offset": 8
146
146
  }, {
147
147
  default: T(() => [h(te, {
@@ -177,7 +177,7 @@ var j = { class: "font-medium" }, M = { class: "font-semibold" }, N = { class: "
177
177
  }, 8, ["aria-label"]), h(C(ce), null, {
178
178
  default: T(() => [h(C(se), {
179
179
  align: "start",
180
- class: "z-[1001] w-44 rounded-lg border border-sui-line bg-sui-surface p-1 shadow-lg data-[state=open]:animate-sui-menu-in",
180
+ class: "z-[1100] w-44 rounded-lg border border-sui-line bg-sui-surface p-1 shadow-lg data-[state=open]:animate-sui-menu-in",
181
181
  "side-offset": 4
182
182
  }, {
183
183
  default: T(() => [h(C(le), {
@@ -1 +1 @@
1
- {"version":3,"file":"FilterChip.vue_vue_type_script_setup_true_lang.js","names":["$slots","defaultDatePresets","_useModel","_openBlock","_createElementBlock","_mergeProps","_unref","_createVNode","FilterGlyph","_createTextVNode","_toDisplayString","_createBlock","_withCtx","Icon","_createElementVNode","_Fragment","_createCommentVNode","FilterFrame","_renderList","CheckIcon","_renderSlot","_withDirectives","_vModelText","_normalizeClass","Checkbox","Input","SegmentedControl","Icon_default","Checkbox_default","Input_default","SegmentedControl_default","CheckIcon_default","FilterFrame_default","FilterGlyph_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","chip","row","rowOn","rowOff","FilterChip_vue_vue_type_script_setup_true_lang_default","datePresets","\"op\"","\"opModifiers\"","\"modelValue\"","\"modelModifiers\"","\"open\"","\"openModifiers\"","props","__props","op","useModel","value","open","attrs","useAttrs","ops","computed","filterOperators","current","o","needsValue","text","describeFilter","isChecklist","query","ref","listed","q","picked","toggle","choice","v","remove","hueDots","openBlock","createElementBlock","mergeProps","unref","createVNode","createTextVNode","toDisplayString","createBlock","PopoverRoot","_cache","$event","withCtx","PopoverTrigger","createElementVNode","Fragment","createCommentVNode","PopoverPortal","PopoverContent","DropdownMenuRoot","DropdownMenuTrigger","DropdownMenuPortal","DropdownMenuContent","DropdownMenuRadioGroup","renderList","DropdownMenuRadioItem","operator","_ctx","renderSlot","withDirectives","vModelText","option","normalizeClass","RadioGroupRoot","RadioGroupItem","preset"],"sources":["../../../src/components/Filters/FilterChip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n DropdownMenuContent,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuRoot,\n DropdownMenuTrigger,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n RadioGroupItem,\n RadioGroupRoot\n} from 'reka-ui'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Icon from '../Icon/Icon.vue'\nimport Input from '../Input/Input.vue'\nimport SegmentedControl from '../SegmentedControl/SegmentedControl.vue'\nimport CheckIcon from '../internal/CheckIcon.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport { datePresets as defaultDatePresets, describeFilter, filterOperators } from './defaults'\nimport type { FilterFieldType, FilterOperator, FilterOption, FilterValue } from './types'\n\nexport interface FilterChipProps {\n /** A filter, read as a sentence; `add` is the quiet \"+ Filter\" that starts one (FilterMenu includes it). */\n kind?: 'filter' | 'add'\n field?: string\n /** Picks the editor: a checklist for enum, person and company, an input for text and number, presets for date, Yes / No for boolean. */\n type?: FilterFieldType\n /** An app icon for the field, instead of the type's glyph. */\n icon?: string\n /** The operators offered; English ones by type by default. */\n operators?: FilterOperator[]\n /** The choices for enum, person and company. */\n options?: FilterOption[]\n /** The live result count in the panel's footer, e.g. \"120 people\". */\n status?: string\n /** The plural noun once more than two values are picked: \"3 stages\". */\n valueLabel?: string\n datePresets?: string[]\n /** Adds a Remove action to the panel (`@remove`). */\n onRemove?: () => void\n removeLabel?: string\n addLabel?: string\n operatorLabel?: string\n searchPlaceholder?: string\n valuePlaceholder?: string\n doneLabel?: string\n closeLabel?: string\n yesLabel?: string\n noLabel?: string\n}\n\n// Attributes and listeners go to the chip itself; the root is a renderless popover.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterChipProps>(), {\n kind: 'filter',\n field: undefined,\n type: 'enum',\n icon: undefined,\n operators: undefined,\n options: () => [],\n status: undefined,\n valueLabel: 'values',\n datePresets: () => defaultDatePresets,\n onRemove: undefined,\n removeLabel: 'Remove',\n addLabel: 'Filter',\n operatorLabel: 'Operator',\n searchPlaceholder: 'Search…',\n valuePlaceholder: 'Type a value',\n doneLabel: 'Done',\n closeLabel: 'Close',\n yesLabel: 'Yes',\n noLabel: 'No'\n})\n\nconst op = defineModel<string>('op')\nconst value = defineModel<FilterValue>({ default: null })\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n /** Your own editor, in place of the type's. */\n default?: () => unknown\n}>()\n\nconst attrs = useAttrs()\n\nconst ops = computed(() => props.operators ?? filterOperators[props.type])\nconst current = computed(() => ops.value.find((o) => o.value === op.value))\nconst needsValue = computed(() => !current.value?.noValue)\nconst text = computed(() =>\n needsValue.value\n ? describeFilter(value.value, props.options, {\n valueLabel: props.valueLabel,\n yesLabel: props.yesLabel,\n noLabel: props.noLabel\n })\n : ''\n)\nconst isChecklist = computed(() => ['enum', 'person', 'company'].includes(props.type))\n\nconst query = ref('')\nconst listed = computed(() => {\n const q = query.value.trim().toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nconst picked = computed(() => (Array.isArray(value.value) ? value.value : []))\n\nfunction toggle(choice: string | number) {\n value.value = picked.value.includes(choice) ? picked.value.filter((v) => v !== choice) : [...picked.value, choice]\n}\n\nfunction remove() {\n open.value = false\n props.onRemove?.()\n}\n\nconst chip =\n 'inline-flex h-7.5 items-center gap-1.5 rounded-lg border text-13 whitespace-nowrap outline-hidden transition-[border-color,box-shadow] duration-150 focus-visible:sui-ring'\nconst row =\n 'flex min-h-8 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-left text-13.5 outline-hidden transition-colors duration-100 focus-visible:sui-ring-inset'\nconst rowOn = 'bg-sui-accent-wash font-semibold text-sui-accent'\nconst rowOff = 'text-sui-ink hover:bg-sui-sunken'\nconst hueDots: Record<string, string> = {\n blue: 'bg-sui-hue-blue-ink',\n green: 'bg-sui-hue-green-ink',\n orange: 'bg-sui-hue-orange-ink',\n pink: 'bg-sui-hue-pink-ink',\n purple: 'bg-sui-hue-purple-ink',\n slate: 'bg-sui-hue-slate-ink',\n red: 'bg-sui-hue-red-ink',\n amber: 'bg-sui-hue-amber-ink'\n}\n</script>\n\n<!-- A view's filter as a sentence chip (\"Stage is any of Lead, Customer\"), whose panel changes it as you go. -->\n<template>\n <button\n v-if=\"kind === 'add'\"\n v-bind=\"attrs\"\n class=\"border-dashed border-sui-line-strong px-2 font-medium text-sui-ink-muted hover:border-sui-ink-muted hover:text-sui-ink-body\"\n :class=\"chip\"\n type=\"button\"\n >\n <FilterGlyph name=\"plus\" />\n {{ addLabel }}\n </button>\n <PopoverRoot v-else v-model:open=\"open\">\n <PopoverTrigger\n v-bind=\"attrs\"\n class=\"border-sui-accent-line bg-sui-accent-wash pr-1.5 pl-2 text-sui-accent hover:border-sui-accent-bright data-[state=open]:border-sui-accent-solid data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n :class=\"chip\"\n >\n <Icon v-if=\"icon\" class=\"size-3.5 opacity-80\" color=\"accent\" :name=\"icon\" />\n <FilterGlyph v-else class=\"opacity-80\" :name=\"type\" />\n <!-- Real spaces between the words, so the chip's name reads as a sentence. -->\n <span\n ><span class=\"font-medium\">{{ field }}</span\n ><template v-if=\"current\">{{ ' ' }}{{ current.label }}</template\n ><template v-if=\"text\"\n >{{ ' ' }}<span class=\"font-semibold\">{{ text }}</span></template\n ></span\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 shrink-0 fill-none stroke-current opacity-70\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n >\n <FilterFrame :close-label=\"closeLabel\" :enter-label=\"doneLabel\" :status=\"status\" @enter=\"open = false\">\n <div class=\"flex h-11 items-center gap-1.5 pr-1.5 pl-3.5 text-sui-ink-muted\">\n <Icon v-if=\"icon\" color=\"ink-muted\" :name=\"icon\" />\n <FilterGlyph v-else class=\"size-4\" :name=\"type\" />\n <span class=\"text-sm font-semibold text-sui-ink\">{{ field }}</span>\n <DropdownMenuRoot v-if=\"ops.length > 1\">\n <DropdownMenuTrigger\n :aria-label=\"`${operatorLabel}: ${current?.label ?? ''}`\"\n class=\"inline-flex h-7 items-center gap-0.5 rounded-md pr-1 pl-1.5 text-13.5 font-medium text-sui-accent outline-hidden transition-colors duration-150 hover:bg-sui-accent-wash focus-visible:sui-ring-inset data-[state=open]:bg-sui-accent-wash\"\n >\n {{ current?.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </DropdownMenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuContent\n align=\"start\"\n class=\"z-[1001] w-44 rounded-lg border border-sui-line bg-sui-surface p-1 shadow-lg data-[state=open]:animate-sui-menu-in\"\n :side-offset=\"4\"\n >\n <DropdownMenuRadioGroup v-model=\"op\">\n <DropdownMenuRadioItem\n v-for=\"operator in ops\"\n :key=\"operator.value\"\n class=\"flex h-8 cursor-pointer items-center justify-between rounded-md px-2.5 text-13.5 text-sui-ink-body outline-hidden select-none data-highlighted:bg-sui-sunken data-[state=checked]:font-semibold data-[state=checked]:text-sui-ink\"\n :value=\"operator.value\"\n >\n {{ operator.label }}\n <CheckIcon v-if=\"operator.value === op\" />\n </DropdownMenuRadioItem>\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenuPortal>\n </DropdownMenuRoot>\n <span v-else class=\"text-13.5 text-sui-ink-muted\">{{ current?.label }}</span>\n <button\n v-if=\"onRemove\"\n class=\"ml-auto inline-flex h-7 items-center gap-1.5 rounded-lg px-2 text-12.5 font-medium text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-danger-soft hover:text-sui-danger focus-visible:sui-ring-inset\"\n type=\"button\"\n @click=\"remove\"\n >\n <FilterGlyph name=\"trash\" />\n {{ removeLabel }}\n </button>\n </div>\n\n <slot v-if=\"$slots.default\" />\n <template v-else-if=\"needsValue\">\n <template v-if=\"isChecklist\">\n <div\n v-if=\"options.length > 6\"\n class=\"mx-2 mb-1 flex h-9 items-center gap-2 rounded-lg border border-sui-line-subtle px-2.5 text-sui-ink-muted\"\n >\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <!-- focus: classes too: an app's forms plugin rings focused text fields, and outranks plain utilities. -->\n <input\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n autofocus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <div class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\">\n <label\n v-for=\"option in listed\"\n :key=\"option.value\"\n :class=\"[row, picked.includes(option.value) ? rowOn : rowOff]\"\n >\n <Checkbox :model-value=\"picked.includes(option.value)\" @update:model-value=\"toggle(option.value)\" />\n <span v-if=\"option.color\" class=\"size-1.5 shrink-0 rounded-full\" :class=\"hueDots[option.color]\" />\n <span class=\"min-w-0 flex-1 truncate\">{{ option.label }}</span>\n <span v-if=\"option.count != null\" class=\"text-xs font-normal text-sui-ink-muted tabular-nums\">{{\n option.count\n }}</span>\n </label>\n </div>\n </template>\n <div v-else-if=\"type === 'text' || type === 'number'\" class=\"px-2 pt-1 pb-2\">\n <Input\n :aria-label=\"field\"\n autofocus\n :model-value=\"value == null ? '' : String(value)\"\n :placeholder=\"valuePlaceholder\"\n :type=\"type === 'number' ? 'number' : 'text'\"\n @update:model-value=\"value = $event ?? null\"\n />\n </div>\n <RadioGroupRoot\n v-else-if=\"type === 'date'\"\n :aria-label=\"field\"\n class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\"\n :model-value=\"typeof value === 'string' ? value : undefined\"\n @update:model-value=\"value = String($event)\"\n >\n <RadioGroupItem\n v-for=\"preset in datePresets\"\n :key=\"preset\"\n :class=\"[row, preset === value ? rowOn : rowOff]\"\n :value=\"preset\"\n >\n <FilterGlyph\n class=\"size-4\"\n :class=\"preset === value ? 'text-sui-accent' : 'text-sui-ink-muted'\"\n name=\"date\"\n />\n <span class=\"min-w-0 flex-1 truncate\">{{ preset }}</span>\n <CheckIcon v-if=\"preset === value\" />\n </RadioGroupItem>\n </RadioGroupRoot>\n <div v-else-if=\"type === 'boolean'\" class=\"px-2.5 pt-1 pb-2.5\">\n <SegmentedControl\n :aria-label=\"field\"\n :model-value=\"value ? 'yes' : 'no'\"\n :options=\"[\n { value: 'yes', label: yesLabel },\n { value: 'no', label: noLabel }\n ]\"\n @update:model-value=\"value = $event === 'yes'\"\n />\n </div>\n </template>\n </FilterFrame>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"FilterChip.vue_vue_type_script_setup_true_lang.js","names":["$slots","defaultDatePresets","_useModel","_openBlock","_createElementBlock","_mergeProps","_unref","_createVNode","FilterGlyph","_createTextVNode","_toDisplayString","_createBlock","_withCtx","Icon","_createElementVNode","_Fragment","_createCommentVNode","FilterFrame","_renderList","CheckIcon","_renderSlot","_withDirectives","_vModelText","_normalizeClass","Checkbox","Input","SegmentedControl","Icon_default","Checkbox_default","Input_default","SegmentedControl_default","CheckIcon_default","FilterFrame_default","FilterGlyph_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","chip","row","rowOn","rowOff","FilterChip_vue_vue_type_script_setup_true_lang_default","datePresets","\"op\"","\"opModifiers\"","\"modelValue\"","\"modelModifiers\"","\"open\"","\"openModifiers\"","props","__props","op","useModel","value","open","attrs","useAttrs","ops","computed","filterOperators","current","o","needsValue","text","describeFilter","isChecklist","query","ref","listed","q","picked","toggle","choice","v","remove","hueDots","openBlock","createElementBlock","mergeProps","unref","createVNode","createTextVNode","toDisplayString","createBlock","PopoverRoot","_cache","$event","withCtx","PopoverTrigger","createElementVNode","Fragment","createCommentVNode","PopoverPortal","PopoverContent","DropdownMenuRoot","DropdownMenuTrigger","DropdownMenuPortal","DropdownMenuContent","DropdownMenuRadioGroup","renderList","DropdownMenuRadioItem","operator","_ctx","renderSlot","withDirectives","vModelText","option","normalizeClass","RadioGroupRoot","RadioGroupItem","preset"],"sources":["../../../src/components/Filters/FilterChip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n DropdownMenuContent,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuRoot,\n DropdownMenuTrigger,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger,\n RadioGroupItem,\n RadioGroupRoot\n} from 'reka-ui'\n\nimport Checkbox from '../Checkbox/Checkbox.vue'\nimport Icon from '../Icon/Icon.vue'\nimport Input from '../Input/Input.vue'\nimport SegmentedControl from '../SegmentedControl/SegmentedControl.vue'\nimport CheckIcon from '../internal/CheckIcon.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport { datePresets as defaultDatePresets, describeFilter, filterOperators } from './defaults'\nimport type { FilterFieldType, FilterOperator, FilterOption, FilterValue } from './types'\n\nexport interface FilterChipProps {\n /** A filter, read as a sentence; `add` is the quiet \"+ Filter\" that starts one (FilterMenu includes it). */\n kind?: 'filter' | 'add'\n field?: string\n /** Picks the editor: a checklist for enum, person and company, an input for text and number, presets for date, Yes / No for boolean. */\n type?: FilterFieldType\n /** An app icon for the field, instead of the type's glyph. */\n icon?: string\n /** The operators offered; English ones by type by default. */\n operators?: FilterOperator[]\n /** The choices for enum, person and company. */\n options?: FilterOption[]\n /** The live result count in the panel's footer, e.g. \"120 people\". */\n status?: string\n /** The plural noun once more than two values are picked: \"3 stages\". */\n valueLabel?: string\n datePresets?: string[]\n /** Adds a Remove action to the panel (`@remove`). */\n onRemove?: () => void\n removeLabel?: string\n addLabel?: string\n operatorLabel?: string\n searchPlaceholder?: string\n valuePlaceholder?: string\n doneLabel?: string\n closeLabel?: string\n yesLabel?: string\n noLabel?: string\n}\n\n// Attributes and listeners go to the chip itself; the root is a renderless popover.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterChipProps>(), {\n kind: 'filter',\n field: undefined,\n type: 'enum',\n icon: undefined,\n operators: undefined,\n options: () => [],\n status: undefined,\n valueLabel: 'values',\n datePresets: () => defaultDatePresets,\n onRemove: undefined,\n removeLabel: 'Remove',\n addLabel: 'Filter',\n operatorLabel: 'Operator',\n searchPlaceholder: 'Search…',\n valuePlaceholder: 'Type a value',\n doneLabel: 'Done',\n closeLabel: 'Close',\n yesLabel: 'Yes',\n noLabel: 'No'\n})\n\nconst op = defineModel<string>('op')\nconst value = defineModel<FilterValue>({ default: null })\nconst open = defineModel<boolean>('open', { default: false })\n\ndefineSlots<{\n /** Your own editor, in place of the type's. */\n default?: () => unknown\n}>()\n\nconst attrs = useAttrs()\n\nconst ops = computed(() => props.operators ?? filterOperators[props.type])\nconst current = computed(() => ops.value.find((o) => o.value === op.value))\nconst needsValue = computed(() => !current.value?.noValue)\nconst text = computed(() =>\n needsValue.value\n ? describeFilter(value.value, props.options, {\n valueLabel: props.valueLabel,\n yesLabel: props.yesLabel,\n noLabel: props.noLabel\n })\n : ''\n)\nconst isChecklist = computed(() => ['enum', 'person', 'company'].includes(props.type))\n\nconst query = ref('')\nconst listed = computed(() => {\n const q = query.value.trim().toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nconst picked = computed(() => (Array.isArray(value.value) ? value.value : []))\n\nfunction toggle(choice: string | number) {\n value.value = picked.value.includes(choice) ? picked.value.filter((v) => v !== choice) : [...picked.value, choice]\n}\n\nfunction remove() {\n open.value = false\n props.onRemove?.()\n}\n\nconst chip =\n 'inline-flex h-7.5 items-center gap-1.5 rounded-lg border text-13 whitespace-nowrap outline-hidden transition-[border-color,box-shadow] duration-150 focus-visible:sui-ring'\nconst row =\n 'flex min-h-8 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-left text-13.5 outline-hidden transition-colors duration-100 focus-visible:sui-ring-inset'\nconst rowOn = 'bg-sui-accent-wash font-semibold text-sui-accent'\nconst rowOff = 'text-sui-ink hover:bg-sui-sunken'\nconst hueDots: Record<string, string> = {\n blue: 'bg-sui-hue-blue-ink',\n green: 'bg-sui-hue-green-ink',\n orange: 'bg-sui-hue-orange-ink',\n pink: 'bg-sui-hue-pink-ink',\n purple: 'bg-sui-hue-purple-ink',\n slate: 'bg-sui-hue-slate-ink',\n red: 'bg-sui-hue-red-ink',\n amber: 'bg-sui-hue-amber-ink'\n}\n</script>\n\n<!-- A view's filter as a sentence chip (\"Stage is any of Lead, Customer\"), whose panel changes it as you go. -->\n<template>\n <button\n v-if=\"kind === 'add'\"\n v-bind=\"attrs\"\n class=\"border-dashed border-sui-line-strong px-2 font-medium text-sui-ink-muted hover:border-sui-ink-muted hover:text-sui-ink-body\"\n :class=\"chip\"\n type=\"button\"\n >\n <FilterGlyph name=\"plus\" />\n {{ addLabel }}\n </button>\n <PopoverRoot v-else v-model:open=\"open\">\n <PopoverTrigger\n v-bind=\"attrs\"\n class=\"border-sui-accent-line bg-sui-accent-wash pr-1.5 pl-2 text-sui-accent hover:border-sui-accent-bright data-[state=open]:border-sui-accent-solid data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n :class=\"chip\"\n >\n <Icon v-if=\"icon\" class=\"size-3.5 opacity-80\" color=\"accent\" :name=\"icon\" />\n <FilterGlyph v-else class=\"opacity-80\" :name=\"type\" />\n <!-- Real spaces between the words, so the chip's name reads as a sentence. -->\n <span\n ><span class=\"font-medium\">{{ field }}</span\n ><template v-if=\"current\">{{ ' ' }}{{ current.label }}</template\n ><template v-if=\"text\"\n >{{ ' ' }}<span class=\"font-semibold\">{{ text }}</span></template\n ></span\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 shrink-0 fill-none stroke-current opacity-70\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n >\n <FilterFrame :close-label=\"closeLabel\" :enter-label=\"doneLabel\" :status=\"status\" @enter=\"open = false\">\n <div class=\"flex h-11 items-center gap-1.5 pr-1.5 pl-3.5 text-sui-ink-muted\">\n <Icon v-if=\"icon\" color=\"ink-muted\" :name=\"icon\" />\n <FilterGlyph v-else class=\"size-4\" :name=\"type\" />\n <span class=\"text-sm font-semibold text-sui-ink\">{{ field }}</span>\n <DropdownMenuRoot v-if=\"ops.length > 1\">\n <DropdownMenuTrigger\n :aria-label=\"`${operatorLabel}: ${current?.label ?? ''}`\"\n class=\"inline-flex h-7 items-center gap-0.5 rounded-md pr-1 pl-1.5 text-13.5 font-medium text-sui-accent outline-hidden transition-colors duration-150 hover:bg-sui-accent-wash focus-visible:sui-ring-inset data-[state=open]:bg-sui-accent-wash\"\n >\n {{ current?.label }}\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </DropdownMenuTrigger>\n <DropdownMenuPortal>\n <DropdownMenuContent\n align=\"start\"\n class=\"z-[1100] w-44 rounded-lg border border-sui-line bg-sui-surface p-1 shadow-lg data-[state=open]:animate-sui-menu-in\"\n :side-offset=\"4\"\n >\n <DropdownMenuRadioGroup v-model=\"op\">\n <DropdownMenuRadioItem\n v-for=\"operator in ops\"\n :key=\"operator.value\"\n class=\"flex h-8 cursor-pointer items-center justify-between rounded-md px-2.5 text-13.5 text-sui-ink-body outline-hidden select-none data-highlighted:bg-sui-sunken data-[state=checked]:font-semibold data-[state=checked]:text-sui-ink\"\n :value=\"operator.value\"\n >\n {{ operator.label }}\n <CheckIcon v-if=\"operator.value === op\" />\n </DropdownMenuRadioItem>\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenuPortal>\n </DropdownMenuRoot>\n <span v-else class=\"text-13.5 text-sui-ink-muted\">{{ current?.label }}</span>\n <button\n v-if=\"onRemove\"\n class=\"ml-auto inline-flex h-7 items-center gap-1.5 rounded-lg px-2 text-12.5 font-medium text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-danger-soft hover:text-sui-danger focus-visible:sui-ring-inset\"\n type=\"button\"\n @click=\"remove\"\n >\n <FilterGlyph name=\"trash\" />\n {{ removeLabel }}\n </button>\n </div>\n\n <slot v-if=\"$slots.default\" />\n <template v-else-if=\"needsValue\">\n <template v-if=\"isChecklist\">\n <div\n v-if=\"options.length > 6\"\n class=\"mx-2 mb-1 flex h-9 items-center gap-2 rounded-lg border border-sui-line-subtle px-2.5 text-sui-ink-muted\"\n >\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <!-- focus: classes too: an app's forms plugin rings focused text fields, and outranks plain utilities. -->\n <input\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n autofocus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <div class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\">\n <label\n v-for=\"option in listed\"\n :key=\"option.value\"\n :class=\"[row, picked.includes(option.value) ? rowOn : rowOff]\"\n >\n <Checkbox :model-value=\"picked.includes(option.value)\" @update:model-value=\"toggle(option.value)\" />\n <span v-if=\"option.color\" class=\"size-1.5 shrink-0 rounded-full\" :class=\"hueDots[option.color]\" />\n <span class=\"min-w-0 flex-1 truncate\">{{ option.label }}</span>\n <span v-if=\"option.count != null\" class=\"text-xs font-normal text-sui-ink-muted tabular-nums\">{{\n option.count\n }}</span>\n </label>\n </div>\n </template>\n <div v-else-if=\"type === 'text' || type === 'number'\" class=\"px-2 pt-1 pb-2\">\n <Input\n :aria-label=\"field\"\n autofocus\n :model-value=\"value == null ? '' : String(value)\"\n :placeholder=\"valuePlaceholder\"\n :type=\"type === 'number' ? 'number' : 'text'\"\n @update:model-value=\"value = $event ?? null\"\n />\n </div>\n <RadioGroupRoot\n v-else-if=\"type === 'date'\"\n :aria-label=\"field\"\n class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\"\n :model-value=\"typeof value === 'string' ? value : undefined\"\n @update:model-value=\"value = String($event)\"\n >\n <RadioGroupItem\n v-for=\"preset in datePresets\"\n :key=\"preset\"\n :class=\"[row, preset === value ? rowOn : rowOff]\"\n :value=\"preset\"\n >\n <FilterGlyph\n class=\"size-4\"\n :class=\"preset === value ? 'text-sui-accent' : 'text-sui-ink-muted'\"\n name=\"date\"\n />\n <span class=\"min-w-0 flex-1 truncate\">{{ preset }}</span>\n <CheckIcon v-if=\"preset === value\" />\n </RadioGroupItem>\n </RadioGroupRoot>\n <div v-else-if=\"type === 'boolean'\" class=\"px-2.5 pt-1 pb-2.5\">\n <SegmentedControl\n :aria-label=\"field\"\n :model-value=\"value ? 'yes' : 'no'\"\n :options=\"[\n { value: 'yes', label: yesLabel },\n { value: 'no', label: noLabel }\n ]\"\n @update:model-value=\"value = $event === 'yes'\"\n />\n </div>\n </template>\n </FilterFrame>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"FilterMenu.js","names":["_sfc_main","FilterMenu_vue_vue_type_script_setup_true_lang_default","FilterMenu_default"],"sources":["../../../src/components/Filters/FilterMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n ListboxContent,\n ListboxFilter,\n ListboxGroup,\n ListboxGroupLabel,\n ListboxItem,\n ListboxRoot,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger\n} from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport type { FilterField } from './types'\n\nexport interface FilterMenuProps {\n fields: FilterField[]\n /** Fields already filtering, marked \"In use\"; picking one should open its chip, not add a second. */\n inUse?: string[]\n /** chip: the dashed \"+ Filter\" in the view bar. button: the page header's Filters button, tinted while filters are in use. */\n as?: 'chip' | 'button'\n /** The footer's status; \"{count} fields\" by default. */\n status?: string\n label?: string\n buttonLabel?: string\n searchPlaceholder?: string\n inUseLabel?: string\n addLabel?: string\n closeLabel?: string\n /** `{count}` is the number of fields. */\n fieldsLabel?: string\n /** `{query}` is what was typed. */\n noMatchLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterMenuProps>(), {\n inUse: () => [],\n as: 'chip',\n status: undefined,\n label: 'Filter',\n buttonLabel: 'Filters',\n searchPlaceholder: 'Filter by…',\n inUseLabel: 'In use',\n addLabel: 'Add',\n closeLabel: 'Close',\n fieldsLabel: '{count} fields',\n noMatchLabel: 'No field matches “{query}”.'\n})\n\nconst emit = defineEmits<{ pick: [name: string] }>()\n\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\nconst query = ref('')\n// Only the keyboard's highlight gets the focus ring; the pointer's is just a tint.\nconst keyboard = ref(false)\n\nconst groups = computed(() => {\n const q = query.value.trim().toLowerCase()\n const shown = props.fields.filter((f) => !q || f.label.toLowerCase().includes(q))\n return [...new Set(shown.map((f) => f.group ?? ''))].map((name) => ({\n name,\n fields: shown.filter((f) => (f.group ?? '') === name)\n }))\n})\n\nfunction pick(name: unknown) {\n if (typeof name !== 'string') return\n open.value = false\n query.value = ''\n emit('pick', name)\n}\n\nfunction onOpen(isOpen: boolean) {\n if (!isOpen) query.value = ''\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) keyboard.value = true\n}\n</script>\n\n<!-- The field list behind \"+ Filter\": search, fields grouped with their type, and which are already filtering. -->\n<template>\n <PopoverRoot v-model:open=\"open\" @update:open=\"onOpen\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :variant=\"inUse.length ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M2.5 3.5h11l-4.25 5v4l-2.5 1v-5z\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-dashed border-sui-line-strong px-2 text-13 font-medium whitespace-nowrap text-sui-ink-muted outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-ink-muted hover:text-sui-ink-body focus-visible:sui-ring data-[state=open]:border-solid data-[state=open]:border-sui-accent-solid data-[state=open]:text-sui-accent data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <FilterGlyph name=\"plus\" />\n {{ label }}\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n @keydown=\"onKeydown\"\n @pointermove=\"keyboard = false\"\n >\n <ListboxRoot highlight-on-hover @update:model-value=\"pick\">\n <FilterFrame\n :close-label=\"closeLabel\"\n :enter-label=\"addLabel\"\n :status=\"status ?? fieldsLabel.replace('{count}', String(fields.length))\"\n >\n <div class=\"flex h-11 items-center gap-2 border-b border-sui-line-subtle px-3.5 text-sui-ink-muted\">\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <ListboxFilter\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n auto-focus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <ListboxContent\n :aria-label=\"searchPlaceholder\"\n class=\"group/list max-h-64 overflow-auto px-1.5 pt-1 pb-1.5 outline-hidden\"\n :data-keyboard=\"keyboard || undefined\"\n >\n <ListboxGroup v-for=\"group in groups\" :key=\"group.name\">\n <ListboxGroupLabel\n v-if=\"group.name\"\n class=\"m-0 px-2 pt-2.5 pb-1 text-11 font-semibold tracking-caps text-sui-ink-muted uppercase\"\n >\n {{ group.name }}\n </ListboxGroupLabel>\n <ListboxItem\n v-for=\"field in group.fields\"\n :key=\"field.name\"\n class=\"flex min-h-8 cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-13.5 text-sui-ink outline-hidden select-none data-highlighted:bg-sui-sunken group-data-keyboard/list:data-highlighted:sui-ring-inset\"\n :value=\"field.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-sui-sunken text-sui-ink-body\"\n >\n <FilterGlyph :name=\"field.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ field.label }}</span>\n <span\n v-if=\"inUse.includes(field.name)\"\n class=\"inline-flex items-center gap-1.5 text-xs font-medium text-sui-accent\"\n >\n <span class=\"size-1.5 rounded-full bg-sui-accent-solid\" />\n {{ inUseLabel }}\n </span>\n </ListboxItem>\n </ListboxGroup>\n <p v-if=\"!groups.length\" class=\"m-0 px-2 py-3 text-13 text-sui-ink-body\">\n {{ noMatchLabel.replace('{query}', query) }}\n </p>\n </ListboxContent>\n </FilterFrame>\n </ListboxRoot>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"FilterMenu.js","names":["_sfc_main","FilterMenu_vue_vue_type_script_setup_true_lang_default","FilterMenu_default"],"sources":["../../../src/components/Filters/FilterMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n ListboxContent,\n ListboxFilter,\n ListboxGroup,\n ListboxGroupLabel,\n ListboxItem,\n ListboxRoot,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger\n} from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport type { FilterField } from './types'\n\nexport interface FilterMenuProps {\n fields: FilterField[]\n /** Fields already filtering, marked \"In use\"; picking one should open its chip, not add a second. */\n inUse?: string[]\n /** chip: the dashed \"+ Filter\" in the view bar. button: the page header's Filters button, tinted while filters are in use. */\n as?: 'chip' | 'button'\n /** The footer's status; \"{count} fields\" by default. */\n status?: string\n label?: string\n buttonLabel?: string\n searchPlaceholder?: string\n inUseLabel?: string\n addLabel?: string\n closeLabel?: string\n /** `{count}` is the number of fields. */\n fieldsLabel?: string\n /** `{query}` is what was typed. */\n noMatchLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterMenuProps>(), {\n inUse: () => [],\n as: 'chip',\n status: undefined,\n label: 'Filter',\n buttonLabel: 'Filters',\n searchPlaceholder: 'Filter by…',\n inUseLabel: 'In use',\n addLabel: 'Add',\n closeLabel: 'Close',\n fieldsLabel: '{count} fields',\n noMatchLabel: 'No field matches “{query}”.'\n})\n\nconst emit = defineEmits<{ pick: [name: string] }>()\n\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\nconst query = ref('')\n// Only the keyboard's highlight gets the focus ring; the pointer's is just a tint.\nconst keyboard = ref(false)\n\nconst groups = computed(() => {\n const q = query.value.trim().toLowerCase()\n const shown = props.fields.filter((f) => !q || f.label.toLowerCase().includes(q))\n return [...new Set(shown.map((f) => f.group ?? ''))].map((name) => ({\n name,\n fields: shown.filter((f) => (f.group ?? '') === name)\n }))\n})\n\nfunction pick(name: unknown) {\n if (typeof name !== 'string') return\n open.value = false\n query.value = ''\n emit('pick', name)\n}\n\nfunction onOpen(isOpen: boolean) {\n if (!isOpen) query.value = ''\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) keyboard.value = true\n}\n</script>\n\n<!-- The field list behind \"+ Filter\": search, fields grouped with their type, and which are already filtering. -->\n<template>\n <PopoverRoot v-model:open=\"open\" @update:open=\"onOpen\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :variant=\"inUse.length ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M2.5 3.5h11l-4.25 5v4l-2.5 1v-5z\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-dashed border-sui-line-strong px-2 text-13 font-medium whitespace-nowrap text-sui-ink-muted outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-ink-muted hover:text-sui-ink-body focus-visible:sui-ring data-[state=open]:border-solid data-[state=open]:border-sui-accent-solid data-[state=open]:text-sui-accent data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <FilterGlyph name=\"plus\" />\n {{ label }}\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n @keydown=\"onKeydown\"\n @pointermove=\"keyboard = false\"\n >\n <ListboxRoot highlight-on-hover @update:model-value=\"pick\">\n <FilterFrame\n :close-label=\"closeLabel\"\n :enter-label=\"addLabel\"\n :status=\"status ?? fieldsLabel.replace('{count}', String(fields.length))\"\n >\n <div class=\"flex h-11 items-center gap-2 border-b border-sui-line-subtle px-3.5 text-sui-ink-muted\">\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <ListboxFilter\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n auto-focus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <ListboxContent\n :aria-label=\"searchPlaceholder\"\n class=\"group/list max-h-64 overflow-auto px-1.5 pt-1 pb-1.5 outline-hidden\"\n :data-keyboard=\"keyboard || undefined\"\n >\n <ListboxGroup v-for=\"group in groups\" :key=\"group.name\">\n <ListboxGroupLabel\n v-if=\"group.name\"\n class=\"m-0 px-2 pt-2.5 pb-1 text-11 font-semibold tracking-caps text-sui-ink-muted uppercase\"\n >\n {{ group.name }}\n </ListboxGroupLabel>\n <ListboxItem\n v-for=\"field in group.fields\"\n :key=\"field.name\"\n class=\"flex min-h-8 cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-13.5 text-sui-ink outline-hidden select-none data-highlighted:bg-sui-sunken group-data-keyboard/list:data-highlighted:sui-ring-inset\"\n :value=\"field.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-sui-sunken text-sui-ink-body\"\n >\n <FilterGlyph :name=\"field.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ field.label }}</span>\n <span\n v-if=\"inUse.includes(field.name)\"\n class=\"inline-flex items-center gap-1.5 text-xs font-medium text-sui-accent\"\n >\n <span class=\"size-1.5 rounded-full bg-sui-accent-solid\" />\n {{ inUseLabel }}\n </span>\n </ListboxItem>\n </ListboxGroup>\n <p v-if=\"!groups.length\" class=\"m-0 px-2 py-3 text-13 text-sui-ink-body\">\n {{ noMatchLabel.replace('{query}', query) }}\n </p>\n </ListboxContent>\n </FilterFrame>\n </ListboxRoot>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
@@ -81,7 +81,7 @@ var M = { class: "flex h-11 items-center gap-2 border-b border-sui-line-subtle p
81
81
  }, 16)), u(v(k), null, {
82
82
  default: x(() => [u(v(O), {
83
83
  align: "start",
84
- class: "z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in",
84
+ class: "z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in",
85
85
  "side-offset": 8,
86
86
  onKeydown: K,
87
87
  onPointermove: f[1] ||= (e) => H.value = !1
@@ -1 +1 @@
1
- {"version":3,"file":"FilterMenu.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_unref","_withCtx","_createVNode","Button","_mergeProps","_createElementVNode","_createTextVNode","_toDisplayString","FilterGlyph","FilterFrame","_createElementBlock","_Fragment","_renderList","_createCommentVNode","Button_default","FilterFrame_default","FilterGlyph_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","FilterMenu_vue_vue_type_script_setup_true_lang_default","\"open\"","\"openModifiers\"","__emit","props","__props","emit","open","useModel","attrs","useAttrs","query","ref","keyboard","groups","computed","q","shown","f","name","pick","onOpen","isOpen","onKeydown","event","openBlock","createBlock","unref","PopoverRoot","_cache","$event","withCtx","PopoverTrigger","createVNode","mergeProps","createElementVNode","createTextVNode","toDisplayString","PopoverPortal","PopoverContent","ListboxRoot","ListboxFilter","ListboxContent","createElementBlock","Fragment","renderList","ListboxGroup","group","ListboxGroupLabel","createCommentVNode","ListboxItem","field"],"sources":["../../../src/components/Filters/FilterMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n ListboxContent,\n ListboxFilter,\n ListboxGroup,\n ListboxGroupLabel,\n ListboxItem,\n ListboxRoot,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger\n} from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport type { FilterField } from './types'\n\nexport interface FilterMenuProps {\n fields: FilterField[]\n /** Fields already filtering, marked \"In use\"; picking one should open its chip, not add a second. */\n inUse?: string[]\n /** chip: the dashed \"+ Filter\" in the view bar. button: the page header's Filters button, tinted while filters are in use. */\n as?: 'chip' | 'button'\n /** The footer's status; \"{count} fields\" by default. */\n status?: string\n label?: string\n buttonLabel?: string\n searchPlaceholder?: string\n inUseLabel?: string\n addLabel?: string\n closeLabel?: string\n /** `{count}` is the number of fields. */\n fieldsLabel?: string\n /** `{query}` is what was typed. */\n noMatchLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterMenuProps>(), {\n inUse: () => [],\n as: 'chip',\n status: undefined,\n label: 'Filter',\n buttonLabel: 'Filters',\n searchPlaceholder: 'Filter by…',\n inUseLabel: 'In use',\n addLabel: 'Add',\n closeLabel: 'Close',\n fieldsLabel: '{count} fields',\n noMatchLabel: 'No field matches “{query}”.'\n})\n\nconst emit = defineEmits<{ pick: [name: string] }>()\n\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\nconst query = ref('')\n// Only the keyboard's highlight gets the focus ring; the pointer's is just a tint.\nconst keyboard = ref(false)\n\nconst groups = computed(() => {\n const q = query.value.trim().toLowerCase()\n const shown = props.fields.filter((f) => !q || f.label.toLowerCase().includes(q))\n return [...new Set(shown.map((f) => f.group ?? ''))].map((name) => ({\n name,\n fields: shown.filter((f) => (f.group ?? '') === name)\n }))\n})\n\nfunction pick(name: unknown) {\n if (typeof name !== 'string') return\n open.value = false\n query.value = ''\n emit('pick', name)\n}\n\nfunction onOpen(isOpen: boolean) {\n if (!isOpen) query.value = ''\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) keyboard.value = true\n}\n</script>\n\n<!-- The field list behind \"+ Filter\": search, fields grouped with their type, and which are already filtering. -->\n<template>\n <PopoverRoot v-model:open=\"open\" @update:open=\"onOpen\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :variant=\"inUse.length ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M2.5 3.5h11l-4.25 5v4l-2.5 1v-5z\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-dashed border-sui-line-strong px-2 text-13 font-medium whitespace-nowrap text-sui-ink-muted outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-ink-muted hover:text-sui-ink-body focus-visible:sui-ring data-[state=open]:border-solid data-[state=open]:border-sui-accent-solid data-[state=open]:text-sui-accent data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <FilterGlyph name=\"plus\" />\n {{ label }}\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n @keydown=\"onKeydown\"\n @pointermove=\"keyboard = false\"\n >\n <ListboxRoot highlight-on-hover @update:model-value=\"pick\">\n <FilterFrame\n :close-label=\"closeLabel\"\n :enter-label=\"addLabel\"\n :status=\"status ?? fieldsLabel.replace('{count}', String(fields.length))\"\n >\n <div class=\"flex h-11 items-center gap-2 border-b border-sui-line-subtle px-3.5 text-sui-ink-muted\">\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <ListboxFilter\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n auto-focus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <ListboxContent\n :aria-label=\"searchPlaceholder\"\n class=\"group/list max-h-64 overflow-auto px-1.5 pt-1 pb-1.5 outline-hidden\"\n :data-keyboard=\"keyboard || undefined\"\n >\n <ListboxGroup v-for=\"group in groups\" :key=\"group.name\">\n <ListboxGroupLabel\n v-if=\"group.name\"\n class=\"m-0 px-2 pt-2.5 pb-1 text-11 font-semibold tracking-caps text-sui-ink-muted uppercase\"\n >\n {{ group.name }}\n </ListboxGroupLabel>\n <ListboxItem\n v-for=\"field in group.fields\"\n :key=\"field.name\"\n class=\"flex min-h-8 cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-13.5 text-sui-ink outline-hidden select-none data-highlighted:bg-sui-sunken group-data-keyboard/list:data-highlighted:sui-ring-inset\"\n :value=\"field.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-sui-sunken text-sui-ink-body\"\n >\n <FilterGlyph :name=\"field.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ field.label }}</span>\n <span\n v-if=\"inUse.includes(field.name)\"\n class=\"inline-flex items-center gap-1.5 text-xs font-medium text-sui-accent\"\n >\n <span class=\"size-1.5 rounded-full bg-sui-accent-solid\" />\n {{ inUseLabel }}\n </span>\n </ListboxItem>\n </ListboxGroup>\n <p v-if=\"!groups.length\" class=\"m-0 px-2 py-3 text-13 text-sui-ink-body\">\n {{ noMatchLabel.replace('{query}', query) }}\n </p>\n </ListboxContent>\n </FilterFrame>\n </ListboxRoot>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"FilterMenu.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_unref","_withCtx","_createVNode","Button","_mergeProps","_createElementVNode","_createTextVNode","_toDisplayString","FilterGlyph","FilterFrame","_createElementBlock","_Fragment","_renderList","_createCommentVNode","Button_default","FilterFrame_default","FilterGlyph_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","FilterMenu_vue_vue_type_script_setup_true_lang_default","\"open\"","\"openModifiers\"","__emit","props","__props","emit","open","useModel","attrs","useAttrs","query","ref","keyboard","groups","computed","q","shown","f","name","pick","onOpen","isOpen","onKeydown","event","openBlock","createBlock","unref","PopoverRoot","_cache","$event","withCtx","PopoverTrigger","createVNode","mergeProps","createElementVNode","createTextVNode","toDisplayString","PopoverPortal","PopoverContent","ListboxRoot","ListboxFilter","ListboxContent","createElementBlock","Fragment","renderList","ListboxGroup","group","ListboxGroupLabel","createCommentVNode","ListboxItem","field"],"sources":["../../../src/components/Filters/FilterMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useAttrs } from 'vue'\n\nimport {\n ListboxContent,\n ListboxFilter,\n ListboxGroup,\n ListboxGroupLabel,\n ListboxItem,\n ListboxRoot,\n PopoverContent,\n PopoverPortal,\n PopoverRoot,\n PopoverTrigger\n} from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport type { FilterField } from './types'\n\nexport interface FilterMenuProps {\n fields: FilterField[]\n /** Fields already filtering, marked \"In use\"; picking one should open its chip, not add a second. */\n inUse?: string[]\n /** chip: the dashed \"+ Filter\" in the view bar. button: the page header's Filters button, tinted while filters are in use. */\n as?: 'chip' | 'button'\n /** The footer's status; \"{count} fields\" by default. */\n status?: string\n label?: string\n buttonLabel?: string\n searchPlaceholder?: string\n inUseLabel?: string\n addLabel?: string\n closeLabel?: string\n /** `{count}` is the number of fields. */\n fieldsLabel?: string\n /** `{query}` is what was typed. */\n noMatchLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<FilterMenuProps>(), {\n inUse: () => [],\n as: 'chip',\n status: undefined,\n label: 'Filter',\n buttonLabel: 'Filters',\n searchPlaceholder: 'Filter by…',\n inUseLabel: 'In use',\n addLabel: 'Add',\n closeLabel: 'Close',\n fieldsLabel: '{count} fields',\n noMatchLabel: 'No field matches “{query}”.'\n})\n\nconst emit = defineEmits<{ pick: [name: string] }>()\n\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\nconst query = ref('')\n// Only the keyboard's highlight gets the focus ring; the pointer's is just a tint.\nconst keyboard = ref(false)\n\nconst groups = computed(() => {\n const q = query.value.trim().toLowerCase()\n const shown = props.fields.filter((f) => !q || f.label.toLowerCase().includes(q))\n return [...new Set(shown.map((f) => f.group ?? ''))].map((name) => ({\n name,\n fields: shown.filter((f) => (f.group ?? '') === name)\n }))\n})\n\nfunction pick(name: unknown) {\n if (typeof name !== 'string') return\n open.value = false\n query.value = ''\n emit('pick', name)\n}\n\nfunction onOpen(isOpen: boolean) {\n if (!isOpen) query.value = ''\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(event.key)) keyboard.value = true\n}\n</script>\n\n<!-- The field list behind \"+ Filter\": search, fields grouped with their type, and which are already filtering. -->\n<template>\n <PopoverRoot v-model:open=\"open\" @update:open=\"onOpen\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :variant=\"inUse.length ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M2.5 3.5h11l-4.25 5v4l-2.5 1v-5z\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-dashed border-sui-line-strong px-2 text-13 font-medium whitespace-nowrap text-sui-ink-muted outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-ink-muted hover:text-sui-ink-body focus-visible:sui-ring data-[state=open]:border-solid data-[state=open]:border-sui-accent-solid data-[state=open]:text-sui-accent data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <FilterGlyph name=\"plus\" />\n {{ label }}\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n @keydown=\"onKeydown\"\n @pointermove=\"keyboard = false\"\n >\n <ListboxRoot highlight-on-hover @update:model-value=\"pick\">\n <FilterFrame\n :close-label=\"closeLabel\"\n :enter-label=\"addLabel\"\n :status=\"status ?? fieldsLabel.replace('{count}', String(fields.length))\"\n >\n <div class=\"flex h-11 items-center gap-2 border-b border-sui-line-subtle px-3.5 text-sui-ink-muted\">\n <FilterGlyph class=\"size-4\" name=\"search\" />\n <ListboxFilter\n v-model=\"query\"\n :aria-label=\"searchPlaceholder\"\n auto-focus\n class=\"h-full min-w-0 flex-1 border-none bg-transparent p-0 text-sm text-sui-ink shadow-none outline-hidden placeholder:text-sui-ink-faint focus:border-none focus:shadow-none focus:ring-0 focus:outline-hidden\"\n :placeholder=\"searchPlaceholder\"\n />\n </div>\n <ListboxContent\n :aria-label=\"searchPlaceholder\"\n class=\"group/list max-h-64 overflow-auto px-1.5 pt-1 pb-1.5 outline-hidden\"\n :data-keyboard=\"keyboard || undefined\"\n >\n <ListboxGroup v-for=\"group in groups\" :key=\"group.name\">\n <ListboxGroupLabel\n v-if=\"group.name\"\n class=\"m-0 px-2 pt-2.5 pb-1 text-11 font-semibold tracking-caps text-sui-ink-muted uppercase\"\n >\n {{ group.name }}\n </ListboxGroupLabel>\n <ListboxItem\n v-for=\"field in group.fields\"\n :key=\"field.name\"\n class=\"flex min-h-8 cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-13.5 text-sui-ink outline-hidden select-none data-highlighted:bg-sui-sunken group-data-keyboard/list:data-highlighted:sui-ring-inset\"\n :value=\"field.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md bg-sui-sunken text-sui-ink-body\"\n >\n <FilterGlyph :name=\"field.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ field.label }}</span>\n <span\n v-if=\"inUse.includes(field.name)\"\n class=\"inline-flex items-center gap-1.5 text-xs font-medium text-sui-accent\"\n >\n <span class=\"size-1.5 rounded-full bg-sui-accent-solid\" />\n {{ inUseLabel }}\n </span>\n </ListboxItem>\n </ListboxGroup>\n <p v-if=\"!groups.length\" class=\"m-0 px-2 py-3 text-13 text-sui-ink-body\">\n {{ noMatchLabel.replace('{query}', query) }}\n </p>\n </ListboxContent>\n </FilterFrame>\n </ListboxRoot>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SortMenu.js","names":["_sfc_main","SortMenu_vue_vue_type_script_setup_true_lang_default","SortMenu_default"],"sources":["../../../src/components/Filters/SortMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\n\nimport { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger, RadioGroupItem, RadioGroupRoot } from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport CheckIcon from '../internal/CheckIcon.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport SortArrow from './SortArrow.vue'\nimport { sortDirections } from './defaults'\nimport type { FilterField, FilterFieldType, ViewSort } from './types'\n\nexport interface SortMenuProps {\n /** The sortable fields. */\n options: FilterField[]\n /** chip: the sort in the view bar, which shows only while there is one. button: the page header's Sort button. */\n as?: 'chip' | 'button'\n /** Boards can't sort: disable the button, with a Tooltip saying why. */\n disabled?: boolean\n status?: string\n /** The two directions' words for each field type, ascending first. */\n directionLabels?: Partial<Record<FilterFieldType, [string, string]>>\n title?: string\n buttonLabel?: string\n clearLabel?: string\n directionLabel?: string\n doneLabel?: string\n closeLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SortMenuProps>(), {\n as: 'chip',\n status: undefined,\n directionLabels: () => ({}),\n title: 'Sort by',\n buttonLabel: 'Sort',\n clearLabel: 'Clear sort',\n directionLabel: 'Direction',\n doneLabel: 'Done',\n closeLabel: 'Close'\n})\n\nconst sort = defineModel<ViewSort | null>({ default: null })\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\n\nconst current = computed(() => (sort.value ? props.options.find((o) => o.name === sort.value!.name) : undefined))\nconst words = (type: FilterFieldType) => props.directionLabels[type] ?? sortDirections[type]\nconst dirLabel = computed(() => (current.value ? words(current.value.type)[sort.value!.dir === 'desc' ? 1 : 0] : ''))\n\nfunction pickField(name: string) {\n sort.value = { name, dir: sort.value?.name === name ? sort.value.dir : 'asc' }\n}\n\nfunction clear() {\n sort.value = null\n open.value = false\n}\n\nconst row =\n 'flex min-h-9 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-left text-13.5 outline-hidden transition-colors duration-100 focus-visible:sui-ring-inset'\n</script>\n\n<!-- A view's sort: the header's Sort button or the view bar's chip (\"Name, A → Z\") open a panel of fields and a direction. -->\n<template>\n <PopoverRoot v-if=\"as === 'button' || current\" v-model:open=\"open\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :disabled=\"disabled\" :variant=\"current ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M5 13V3M2.5 5.5 5 3l2.5 2.5M11 3v10M8.5 10.5 11 13l2.5-2.5\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-sui-accent-line bg-sui-accent-wash pr-1.5 pl-2 text-13 whitespace-nowrap text-sui-accent outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-accent-bright focus-visible:sui-ring data-[state=open]:border-sui-accent-solid data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <SortArrow :dir=\"sort!.dir\" />\n <span\n ><span class=\"font-medium\">{{ current!.label }},</span>{{ ' ' }}{{ dirLabel }}</span\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 shrink-0 fill-none stroke-current opacity-70\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n >\n <FilterFrame :close-label=\"closeLabel\" :enter-label=\"doneLabel\" :status=\"status\" @enter=\"open = false\">\n <div class=\"flex h-11 items-center gap-1.5 pr-1.5 pl-3.5 text-sui-ink-muted\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M5 13V3M2.5 5.5 5 3l2.5 2.5M11 3v10M8.5 10.5 11 13l2.5-2.5\" />\n </svg>\n <span class=\"text-sm font-semibold text-sui-ink\">{{ title }}</span>\n <button\n v-if=\"current\"\n class=\"ml-auto inline-flex h-7 items-center rounded-lg px-2 text-12.5 font-medium text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-sunken hover:text-sui-ink focus-visible:sui-ring-inset\"\n type=\"button\"\n @click=\"clear\"\n >\n {{ clearLabel }}\n </button>\n </div>\n <RadioGroupRoot\n :aria-label=\"title\"\n class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\"\n :model-value=\"sort?.name\"\n @update:model-value=\"pickField($event as string)\"\n >\n <RadioGroupItem\n v-for=\"option in options\"\n :key=\"option.name\"\n :class=\"[\n row,\n option.name === sort?.name\n ? 'bg-sui-accent-wash font-semibold text-sui-accent'\n : 'text-sui-ink hover:bg-sui-sunken'\n ]\"\n :value=\"option.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md\"\n :class=\"\n option.name === sort?.name ? 'bg-sui-surface text-sui-accent' : 'bg-sui-sunken text-sui-ink-body'\n \"\n >\n <FilterGlyph :name=\"option.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ option.label }}</span>\n <CheckIcon v-if=\"option.name === sort?.name\" />\n </RadioGroupItem>\n </RadioGroupRoot>\n <RadioGroupRoot\n v-if=\"current\"\n :aria-label=\"directionLabel\"\n class=\"mx-3 mb-3 grid grid-cols-2 gap-0.5 rounded-lg bg-sui-sunken p-0.75\"\n :model-value=\"sort!.dir\"\n orientation=\"horizontal\"\n @update:model-value=\"sort = { name: sort!.name, dir: $event as ViewSort['dir'] }\"\n >\n <RadioGroupItem\n v-for=\"(dir, i) in ['asc', 'desc'] as const\"\n :key=\"dir\"\n class=\"flex h-9 items-center justify-center gap-1.5 rounded-md text-13 font-medium outline-hidden transition-colors duration-150 focus-visible:sui-ring-inset\"\n :class=\"\n sort!.dir === dir\n ? 'bg-sui-surface text-sui-ink shadow-(--sui-shadow-raised) ring-1 ring-sui-line-subtle'\n : 'text-sui-ink-body hover:text-sui-ink'\n \"\n :value=\"dir\"\n >\n <SortArrow :dir=\"dir\" />\n {{ words(current.type)[i] }}\n </RadioGroupItem>\n </RadioGroupRoot>\n </FilterFrame>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"SortMenu.js","names":["_sfc_main","SortMenu_vue_vue_type_script_setup_true_lang_default","SortMenu_default"],"sources":["../../../src/components/Filters/SortMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\n\nimport { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger, RadioGroupItem, RadioGroupRoot } from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport CheckIcon from '../internal/CheckIcon.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport SortArrow from './SortArrow.vue'\nimport { sortDirections } from './defaults'\nimport type { FilterField, FilterFieldType, ViewSort } from './types'\n\nexport interface SortMenuProps {\n /** The sortable fields. */\n options: FilterField[]\n /** chip: the sort in the view bar, which shows only while there is one. button: the page header's Sort button. */\n as?: 'chip' | 'button'\n /** Boards can't sort: disable the button, with a Tooltip saying why. */\n disabled?: boolean\n status?: string\n /** The two directions' words for each field type, ascending first. */\n directionLabels?: Partial<Record<FilterFieldType, [string, string]>>\n title?: string\n buttonLabel?: string\n clearLabel?: string\n directionLabel?: string\n doneLabel?: string\n closeLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SortMenuProps>(), {\n as: 'chip',\n status: undefined,\n directionLabels: () => ({}),\n title: 'Sort by',\n buttonLabel: 'Sort',\n clearLabel: 'Clear sort',\n directionLabel: 'Direction',\n doneLabel: 'Done',\n closeLabel: 'Close'\n})\n\nconst sort = defineModel<ViewSort | null>({ default: null })\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\n\nconst current = computed(() => (sort.value ? props.options.find((o) => o.name === sort.value!.name) : undefined))\nconst words = (type: FilterFieldType) => props.directionLabels[type] ?? sortDirections[type]\nconst dirLabel = computed(() => (current.value ? words(current.value.type)[sort.value!.dir === 'desc' ? 1 : 0] : ''))\n\nfunction pickField(name: string) {\n sort.value = { name, dir: sort.value?.name === name ? sort.value.dir : 'asc' }\n}\n\nfunction clear() {\n sort.value = null\n open.value = false\n}\n\nconst row =\n 'flex min-h-9 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-left text-13.5 outline-hidden transition-colors duration-100 focus-visible:sui-ring-inset'\n</script>\n\n<!-- A view's sort: the header's Sort button or the view bar's chip (\"Name, A → Z\") open a panel of fields and a direction. -->\n<template>\n <PopoverRoot v-if=\"as === 'button' || current\" v-model:open=\"open\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :disabled=\"disabled\" :variant=\"current ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M5 13V3M2.5 5.5 5 3l2.5 2.5M11 3v10M8.5 10.5 11 13l2.5-2.5\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-sui-accent-line bg-sui-accent-wash pr-1.5 pl-2 text-13 whitespace-nowrap text-sui-accent outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-accent-bright focus-visible:sui-ring data-[state=open]:border-sui-accent-solid data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <SortArrow :dir=\"sort!.dir\" />\n <span\n ><span class=\"font-medium\">{{ current!.label }},</span>{{ ' ' }}{{ dirLabel }}</span\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 shrink-0 fill-none stroke-current opacity-70\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n >\n <FilterFrame :close-label=\"closeLabel\" :enter-label=\"doneLabel\" :status=\"status\" @enter=\"open = false\">\n <div class=\"flex h-11 items-center gap-1.5 pr-1.5 pl-3.5 text-sui-ink-muted\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M5 13V3M2.5 5.5 5 3l2.5 2.5M11 3v10M8.5 10.5 11 13l2.5-2.5\" />\n </svg>\n <span class=\"text-sm font-semibold text-sui-ink\">{{ title }}</span>\n <button\n v-if=\"current\"\n class=\"ml-auto inline-flex h-7 items-center rounded-lg px-2 text-12.5 font-medium text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-sunken hover:text-sui-ink focus-visible:sui-ring-inset\"\n type=\"button\"\n @click=\"clear\"\n >\n {{ clearLabel }}\n </button>\n </div>\n <RadioGroupRoot\n :aria-label=\"title\"\n class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\"\n :model-value=\"sort?.name\"\n @update:model-value=\"pickField($event as string)\"\n >\n <RadioGroupItem\n v-for=\"option in options\"\n :key=\"option.name\"\n :class=\"[\n row,\n option.name === sort?.name\n ? 'bg-sui-accent-wash font-semibold text-sui-accent'\n : 'text-sui-ink hover:bg-sui-sunken'\n ]\"\n :value=\"option.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md\"\n :class=\"\n option.name === sort?.name ? 'bg-sui-surface text-sui-accent' : 'bg-sui-sunken text-sui-ink-body'\n \"\n >\n <FilterGlyph :name=\"option.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ option.label }}</span>\n <CheckIcon v-if=\"option.name === sort?.name\" />\n </RadioGroupItem>\n </RadioGroupRoot>\n <RadioGroupRoot\n v-if=\"current\"\n :aria-label=\"directionLabel\"\n class=\"mx-3 mb-3 grid grid-cols-2 gap-0.5 rounded-lg bg-sui-sunken p-0.75\"\n :model-value=\"sort!.dir\"\n orientation=\"horizontal\"\n @update:model-value=\"sort = { name: sort!.name, dir: $event as ViewSort['dir'] }\"\n >\n <RadioGroupItem\n v-for=\"(dir, i) in ['asc', 'desc'] as const\"\n :key=\"dir\"\n class=\"flex h-9 items-center justify-center gap-1.5 rounded-md text-13 font-medium outline-hidden transition-colors duration-150 focus-visible:sui-ring-inset\"\n :class=\"\n sort!.dir === dir\n ? 'bg-sui-surface text-sui-ink shadow-(--sui-shadow-raised) ring-1 ring-sui-line-subtle'\n : 'text-sui-ink-body hover:text-sui-ink'\n \"\n :value=\"dir\"\n >\n <SortArrow :dir=\"dir\" />\n {{ words(current.type)[i] }}\n </RadioGroupItem>\n </RadioGroupRoot>\n </FilterFrame>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
@@ -83,7 +83,7 @@ var j = { class: "font-medium" }, M = { class: "flex h-11 items-center gap-1.5 p
83
83
  }, 16)), p(x(E), null, {
84
84
  default: w(() => [p(x(T), {
85
85
  align: "start",
86
- class: "z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in",
86
+ class: "z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in",
87
87
  "side-offset": 8
88
88
  }, {
89
89
  default: w(() => [p(n, {
@@ -1 +1 @@
1
- {"version":3,"file":"SortMenu.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_unref","_withCtx","_createVNode","Button","_mergeProps","_createElementVNode","_createTextVNode","_toDisplayString","SortArrow","FilterFrame","_createElementBlock","_createCommentVNode","_Fragment","_renderList","_normalizeClass","FilterGlyph","CheckIcon","Button_default","CheckIcon_default","FilterFrame_default","FilterGlyph_default","SortArrow_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","row","SortMenu_vue_vue_type_script_setup_true_lang_default","\"modelValue\"","\"modelModifiers\"","\"open\"","\"openModifiers\"","props","__props","sort","useModel","open","attrs","useAttrs","current","computed","o","words","type","sortDirections","dirLabel","pickField","name","clear","openBlock","createBlock","unref","PopoverRoot","_cache","$event","withCtx","PopoverTrigger","createVNode","mergeProps","createElementVNode","createTextVNode","toDisplayString","PopoverPortal","PopoverContent","createElementBlock","createCommentVNode","RadioGroupRoot","Fragment","renderList","RadioGroupItem","option","normalizeClass","dir","i"],"sources":["../../../src/components/Filters/SortMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\n\nimport { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger, RadioGroupItem, RadioGroupRoot } from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport CheckIcon from '../internal/CheckIcon.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport SortArrow from './SortArrow.vue'\nimport { sortDirections } from './defaults'\nimport type { FilterField, FilterFieldType, ViewSort } from './types'\n\nexport interface SortMenuProps {\n /** The sortable fields. */\n options: FilterField[]\n /** chip: the sort in the view bar, which shows only while there is one. button: the page header's Sort button. */\n as?: 'chip' | 'button'\n /** Boards can't sort: disable the button, with a Tooltip saying why. */\n disabled?: boolean\n status?: string\n /** The two directions' words for each field type, ascending first. */\n directionLabels?: Partial<Record<FilterFieldType, [string, string]>>\n title?: string\n buttonLabel?: string\n clearLabel?: string\n directionLabel?: string\n doneLabel?: string\n closeLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SortMenuProps>(), {\n as: 'chip',\n status: undefined,\n directionLabels: () => ({}),\n title: 'Sort by',\n buttonLabel: 'Sort',\n clearLabel: 'Clear sort',\n directionLabel: 'Direction',\n doneLabel: 'Done',\n closeLabel: 'Close'\n})\n\nconst sort = defineModel<ViewSort | null>({ default: null })\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\n\nconst current = computed(() => (sort.value ? props.options.find((o) => o.name === sort.value!.name) : undefined))\nconst words = (type: FilterFieldType) => props.directionLabels[type] ?? sortDirections[type]\nconst dirLabel = computed(() => (current.value ? words(current.value.type)[sort.value!.dir === 'desc' ? 1 : 0] : ''))\n\nfunction pickField(name: string) {\n sort.value = { name, dir: sort.value?.name === name ? sort.value.dir : 'asc' }\n}\n\nfunction clear() {\n sort.value = null\n open.value = false\n}\n\nconst row =\n 'flex min-h-9 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-left text-13.5 outline-hidden transition-colors duration-100 focus-visible:sui-ring-inset'\n</script>\n\n<!-- A view's sort: the header's Sort button or the view bar's chip (\"Name, A → Z\") open a panel of fields and a direction. -->\n<template>\n <PopoverRoot v-if=\"as === 'button' || current\" v-model:open=\"open\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :disabled=\"disabled\" :variant=\"current ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M5 13V3M2.5 5.5 5 3l2.5 2.5M11 3v10M8.5 10.5 11 13l2.5-2.5\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-sui-accent-line bg-sui-accent-wash pr-1.5 pl-2 text-13 whitespace-nowrap text-sui-accent outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-accent-bright focus-visible:sui-ring data-[state=open]:border-sui-accent-solid data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <SortArrow :dir=\"sort!.dir\" />\n <span\n ><span class=\"font-medium\">{{ current!.label }},</span>{{ ' ' }}{{ dirLabel }}</span\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 shrink-0 fill-none stroke-current opacity-70\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1000] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n >\n <FilterFrame :close-label=\"closeLabel\" :enter-label=\"doneLabel\" :status=\"status\" @enter=\"open = false\">\n <div class=\"flex h-11 items-center gap-1.5 pr-1.5 pl-3.5 text-sui-ink-muted\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M5 13V3M2.5 5.5 5 3l2.5 2.5M11 3v10M8.5 10.5 11 13l2.5-2.5\" />\n </svg>\n <span class=\"text-sm font-semibold text-sui-ink\">{{ title }}</span>\n <button\n v-if=\"current\"\n class=\"ml-auto inline-flex h-7 items-center rounded-lg px-2 text-12.5 font-medium text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-sunken hover:text-sui-ink focus-visible:sui-ring-inset\"\n type=\"button\"\n @click=\"clear\"\n >\n {{ clearLabel }}\n </button>\n </div>\n <RadioGroupRoot\n :aria-label=\"title\"\n class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\"\n :model-value=\"sort?.name\"\n @update:model-value=\"pickField($event as string)\"\n >\n <RadioGroupItem\n v-for=\"option in options\"\n :key=\"option.name\"\n :class=\"[\n row,\n option.name === sort?.name\n ? 'bg-sui-accent-wash font-semibold text-sui-accent'\n : 'text-sui-ink hover:bg-sui-sunken'\n ]\"\n :value=\"option.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md\"\n :class=\"\n option.name === sort?.name ? 'bg-sui-surface text-sui-accent' : 'bg-sui-sunken text-sui-ink-body'\n \"\n >\n <FilterGlyph :name=\"option.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ option.label }}</span>\n <CheckIcon v-if=\"option.name === sort?.name\" />\n </RadioGroupItem>\n </RadioGroupRoot>\n <RadioGroupRoot\n v-if=\"current\"\n :aria-label=\"directionLabel\"\n class=\"mx-3 mb-3 grid grid-cols-2 gap-0.5 rounded-lg bg-sui-sunken p-0.75\"\n :model-value=\"sort!.dir\"\n orientation=\"horizontal\"\n @update:model-value=\"sort = { name: sort!.name, dir: $event as ViewSort['dir'] }\"\n >\n <RadioGroupItem\n v-for=\"(dir, i) in ['asc', 'desc'] as const\"\n :key=\"dir\"\n class=\"flex h-9 items-center justify-center gap-1.5 rounded-md text-13 font-medium outline-hidden transition-colors duration-150 focus-visible:sui-ring-inset\"\n :class=\"\n sort!.dir === dir\n ? 'bg-sui-surface text-sui-ink shadow-(--sui-shadow-raised) ring-1 ring-sui-line-subtle'\n : 'text-sui-ink-body hover:text-sui-ink'\n \"\n :value=\"dir\"\n >\n <SortArrow :dir=\"dir\" />\n {{ words(current.type)[i] }}\n </RadioGroupItem>\n </RadioGroupRoot>\n </FilterFrame>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"SortMenu.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_unref","_withCtx","_createVNode","Button","_mergeProps","_createElementVNode","_createTextVNode","_toDisplayString","SortArrow","FilterFrame","_createElementBlock","_createCommentVNode","_Fragment","_renderList","_normalizeClass","FilterGlyph","CheckIcon","Button_default","CheckIcon_default","FilterFrame_default","FilterGlyph_default","SortArrow_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","row","SortMenu_vue_vue_type_script_setup_true_lang_default","\"modelValue\"","\"modelModifiers\"","\"open\"","\"openModifiers\"","props","__props","sort","useModel","open","attrs","useAttrs","current","computed","o","words","type","sortDirections","dirLabel","pickField","name","clear","openBlock","createBlock","unref","PopoverRoot","_cache","$event","withCtx","PopoverTrigger","createVNode","mergeProps","createElementVNode","createTextVNode","toDisplayString","PopoverPortal","PopoverContent","createElementBlock","createCommentVNode","RadioGroupRoot","Fragment","renderList","RadioGroupItem","option","normalizeClass","dir","i"],"sources":["../../../src/components/Filters/SortMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\n\nimport { PopoverContent, PopoverPortal, PopoverRoot, PopoverTrigger, RadioGroupItem, RadioGroupRoot } from 'reka-ui'\n\nimport Button from '../Button/Button.vue'\nimport CheckIcon from '../internal/CheckIcon.vue'\nimport FilterFrame from './FilterFrame.vue'\nimport FilterGlyph from './FilterGlyph.vue'\nimport SortArrow from './SortArrow.vue'\nimport { sortDirections } from './defaults'\nimport type { FilterField, FilterFieldType, ViewSort } from './types'\n\nexport interface SortMenuProps {\n /** The sortable fields. */\n options: FilterField[]\n /** chip: the sort in the view bar, which shows only while there is one. button: the page header's Sort button. */\n as?: 'chip' | 'button'\n /** Boards can't sort: disable the button, with a Tooltip saying why. */\n disabled?: boolean\n status?: string\n /** The two directions' words for each field type, ascending first. */\n directionLabels?: Partial<Record<FilterFieldType, [string, string]>>\n title?: string\n buttonLabel?: string\n clearLabel?: string\n directionLabel?: string\n doneLabel?: string\n closeLabel?: string\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<SortMenuProps>(), {\n as: 'chip',\n status: undefined,\n directionLabels: () => ({}),\n title: 'Sort by',\n buttonLabel: 'Sort',\n clearLabel: 'Clear sort',\n directionLabel: 'Direction',\n doneLabel: 'Done',\n closeLabel: 'Close'\n})\n\nconst sort = defineModel<ViewSort | null>({ default: null })\nconst open = defineModel<boolean>('open', { default: false })\n\nconst attrs = useAttrs()\n\nconst current = computed(() => (sort.value ? props.options.find((o) => o.name === sort.value!.name) : undefined))\nconst words = (type: FilterFieldType) => props.directionLabels[type] ?? sortDirections[type]\nconst dirLabel = computed(() => (current.value ? words(current.value.type)[sort.value!.dir === 'desc' ? 1 : 0] : ''))\n\nfunction pickField(name: string) {\n sort.value = { name, dir: sort.value?.name === name ? sort.value.dir : 'asc' }\n}\n\nfunction clear() {\n sort.value = null\n open.value = false\n}\n\nconst row =\n 'flex min-h-9 w-full cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1 text-left text-13.5 outline-hidden transition-colors duration-100 focus-visible:sui-ring-inset'\n</script>\n\n<!-- A view's sort: the header's Sort button or the view bar's chip (\"Name, A → Z\") open a panel of fields and a direction. -->\n<template>\n <PopoverRoot v-if=\"as === 'button' || current\" v-model:open=\"open\">\n <PopoverTrigger v-if=\"as === 'button'\" as-child>\n <Button v-bind=\"attrs\" :disabled=\"disabled\" :variant=\"current ? 'tinted' : 'secondary'\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M5 13V3M2.5 5.5 5 3l2.5 2.5M11 3v10M8.5 10.5 11 13l2.5-2.5\" />\n </svg>\n {{ buttonLabel }}\n </Button>\n </PopoverTrigger>\n <PopoverTrigger\n v-else\n v-bind=\"attrs\"\n class=\"inline-flex h-7.5 items-center gap-1.5 rounded-lg border border-sui-accent-line bg-sui-accent-wash pr-1.5 pl-2 text-13 whitespace-nowrap text-sui-accent outline-hidden transition-[border-color,box-shadow] duration-150 hover:border-sui-accent-bright focus-visible:sui-ring data-[state=open]:border-sui-accent-solid data-[state=open]:shadow-[0_0_0_3px_rgb(var(--sui-focus-ring))]\"\n >\n <SortArrow :dir=\"sort!.dir\" />\n <span\n ><span class=\"font-medium\">{{ current!.label }},</span>{{ ' ' }}{{ dirLabel }}</span\n >\n <svg\n aria-hidden=\"true\"\n class=\"size-3.5 shrink-0 fill-none stroke-current opacity-70\"\n stroke-linecap=\"round\"\n stroke-width=\"2.2\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M6 9l6 6 6-6\" />\n </svg>\n </PopoverTrigger>\n <PopoverPortal>\n <PopoverContent\n align=\"start\"\n class=\"z-[1100] w-85 max-w-[calc(100vw-2rem)] origin-(--reka-popover-content-transform-origin) rounded-xl border border-sui-line bg-sui-surface text-sui-ink shadow-lg data-[state=open]:animate-sui-overlay-in\"\n :side-offset=\"8\"\n >\n <FilterFrame :close-label=\"closeLabel\" :enter-label=\"doneLabel\" :status=\"status\" @enter=\"open = false\">\n <div class=\"flex h-11 items-center gap-1.5 pr-1.5 pl-3.5 text-sui-ink-muted\">\n <svg\n aria-hidden=\"true\"\n class=\"size-4 fill-none stroke-current\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.5\"\n viewBox=\"0 0 16 16\"\n >\n <path d=\"M5 13V3M2.5 5.5 5 3l2.5 2.5M11 3v10M8.5 10.5 11 13l2.5-2.5\" />\n </svg>\n <span class=\"text-sm font-semibold text-sui-ink\">{{ title }}</span>\n <button\n v-if=\"current\"\n class=\"ml-auto inline-flex h-7 items-center rounded-lg px-2 text-12.5 font-medium text-sui-ink-muted outline-hidden transition-colors duration-150 hover:bg-sui-sunken hover:text-sui-ink focus-visible:sui-ring-inset\"\n type=\"button\"\n @click=\"clear\"\n >\n {{ clearLabel }}\n </button>\n </div>\n <RadioGroupRoot\n :aria-label=\"title\"\n class=\"max-h-64 overflow-auto px-1.5 pt-1 pb-1.5\"\n :model-value=\"sort?.name\"\n @update:model-value=\"pickField($event as string)\"\n >\n <RadioGroupItem\n v-for=\"option in options\"\n :key=\"option.name\"\n :class=\"[\n row,\n option.name === sort?.name\n ? 'bg-sui-accent-wash font-semibold text-sui-accent'\n : 'text-sui-ink hover:bg-sui-sunken'\n ]\"\n :value=\"option.name\"\n >\n <span\n class=\"flex size-6 shrink-0 items-center justify-center rounded-md\"\n :class=\"\n option.name === sort?.name ? 'bg-sui-surface text-sui-accent' : 'bg-sui-sunken text-sui-ink-body'\n \"\n >\n <FilterGlyph :name=\"option.type\" />\n </span>\n <span class=\"min-w-0 flex-1 truncate\">{{ option.label }}</span>\n <CheckIcon v-if=\"option.name === sort?.name\" />\n </RadioGroupItem>\n </RadioGroupRoot>\n <RadioGroupRoot\n v-if=\"current\"\n :aria-label=\"directionLabel\"\n class=\"mx-3 mb-3 grid grid-cols-2 gap-0.5 rounded-lg bg-sui-sunken p-0.75\"\n :model-value=\"sort!.dir\"\n orientation=\"horizontal\"\n @update:model-value=\"sort = { name: sort!.name, dir: $event as ViewSort['dir'] }\"\n >\n <RadioGroupItem\n v-for=\"(dir, i) in ['asc', 'desc'] as const\"\n :key=\"dir\"\n class=\"flex h-9 items-center justify-center gap-1.5 rounded-md text-13 font-medium outline-hidden transition-colors duration-150 focus-visible:sui-ring-inset\"\n :class=\"\n sort!.dir === dir\n ? 'bg-sui-surface text-sui-ink shadow-(--sui-shadow-raised) ring-1 ring-sui-line-subtle'\n : 'text-sui-ink-body hover:text-sui-ink'\n \"\n :value=\"dir\"\n >\n <SortArrow :dir=\"dir\" />\n {{ words(current.type)[i] }}\n </RadioGroupItem>\n </RadioGroupRoot>\n </FilterFrame>\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":";;;;;;;;;A,mNA+DM6B,IACJ,+K;;;;;;;;;;;;;;;;;;;;;;;;;;EA/BF,IAAMM,IAAQC,GAYRC,IAAOrC,EAA4BoC,GAAA,YAAkB,GACrDG,IAAOvC,EAAoBoC,GAAC,MAA0B,GAEtDI,IAAQC,EAAS,GAEjBC,IAAUC,QAAgBN,EAAK,QAAQF,EAAM,QAAQ,MAAM,MAAMS,EAAE,SAASP,EAAK,MAAO,IAAI,IAAI,KAAA,CAAU,GAC1GQ,KAAS,MAA0BV,EAAM,gBAAgBW,MAASC,EAAeD,IACjFE,IAAWL,QAAgBD,EAAQ,QAAQG,EAAMH,EAAQ,MAAM,IAAI,CAAC,CAAC,IAAK,MAAO,QAAQ,WAAkB,EAAG;EAEpH,SAASO,EAAU,GAAc;GAC/B,EAAK,QAAQ;IAAE;IAAM,KAAKZ,EAAK,OAAO,SAASa,IAAOb,EAAK,MAAM,MAAM;GAAM;EAC/E;EAEA,SAASc,IAAQ;GAEf,AADA,EAAK,QAAQ,MACb,EAAK,QAAQ;EACf;E,iBAQqBf,EAAA,OAAE,YAAiBM,EAAA,SAAtCzC,EAAA,GAAAC,EAsHcC,EAAAoD,CAAA,GAAA;;GAtHyC,MAAMhB,EAAA;GAAA,iBAAA,AAAAiB,EAAA,QAAA,MAAA,EAAI,QAAAC;;GAC/D,SAAArD,QAciB,CAdKgC,EAAA,OAAE,YAAxBnC,EAAA,GAAAC,EAciBC,EAAAwD,CAAA,GAAA;;IAdsB,YAAA;;IACrC,SAAAvD,QAYS,CAZTC,EAYSC,GAZTC,EAAgBJ,EAYPqC,CAAA,GAZY;KAAG,UAAUJ,EAAA;KAAW,SAASM,EAAA,QAAO,WAAA;;KAC3D,SAAAtC,QASM,CATN,AAAAoD,EAAA,OAAAhD,EASM,OAAA;MARJ,eAAY;MACZ,OAAM;MACN,kBAAe;MACf,mBAAgB;MAChB,gBAAa;MACb,SAAQ;K,IAERA,EAAuE,QAAA,EAAjE,GAAE,6DAA4D,CAAA,C,QAChEC,EAAA,MACNC,EAAG0B,EAAA,WAAW,GAAA,CAAA,C;;;;G,OAGlBnC,EAAA,GAAAC,EAkBiBC,EAAAwD,CAAA,GAlBjBpD,EAkBiB,EAAA,KAAA,EAAA,GAhBPJ,EAAAqC,CAAA,GAAK,EACb,OAAM,4XAA2X,CAAA,GAAA;IAEjY,SAAApC,QAA8B;KAA9BC,EAA8BM,GAAA,EAAlB,KAAK0B,EAAA,MAAM,I;KACvB7B,EAEC,QAAA,MAAA,CADEA,EAAsD,QAAtDiB,GAAsDf,EAAzBgC,EAAA,MAAS,KAAK,IAAG,KAAC,CAAA,GAAUjC,EAAAC,EAAA,GAAG,IAAAA,EAAMsC,EAAA,KAAQ,GAAA,CAAA,C;KAE7E,AAAAQ,EAAA,OAAAhD,EAQM,OAAA;MAPJ,eAAY;MACZ,OAAM;MACN,kBAAe;MACf,gBAAa;MACb,SAAQ;K,IAERA,EAAyB,QAAA,EAAnB,GAAE,eAAc,CAAA,C;;;G,SAG1BH,EAkFgBF,EAAA8D,CAAA,GAAA,MAAA;IAjFd,SAAA7D,QAgFiB,CAhFjBC,EAgFiBF,EAAA+D,CAAA,GAAA;KA/Ef,OAAM;KACN,OAAM;KACL,eAAa;;KAEd,SAAA9D,QA0Ec,CA1EdC,EA0EcO,GAAA;MA1EA,eAAawB,EAAA;MAAa,eAAaA,EAAA;MAAY,QAAQA,EAAA;MAAS,SAAK,AAAAoB,EAAA,QAAA,MAAE,EAAA,QAAI;;MAC3F,SAAApD,QAoBM;OApBNI,EAoBM,OApBNkB,GAoBM;QAnBJ,AAAA8B,EAAA,OAAAhD,EASM,OAAA;SARJ,eAAY;SACZ,OAAM;SACN,kBAAe;SACf,mBAAgB;SAChB,gBAAa;SACb,SAAQ;Q,IAERA,EAAuE,QAAA,EAAjE,GAAE,6DAA4D,CAAA,C;QAEtEA,EAAmE,QAAnEmB,GAAmEjB,EAAf0B,EAAA,KAAK,GAAA,CAAA;QAEjDM,EAAA,SADRzC,EAAA,GAAAY,EAOS,UAAA;;SALP,OAAM;SACN,MAAK;SACJ,SAAOsC;QAEL,GAAAzC,EAAA0B,EAAA,UAAU,GAAA,CAAA,K;;OAGjB/B,EA4BiBF,EAAAkE,CAAA,GAAA;QA3Bd,cAAYjC,EAAA;QACb,OAAM;QACL,eAAaC,EAAA,OAAM;QACnB,uBAAkB,AAAAmB,EAAA,QAAA,MAAEP,EAAUQ,CAAM;;QAGnC,SAAArD,QAAyB,EAD3BH,EAAA,EAAA,GAAAY,EAqBiBE,GAAA,MAAAC,EApBEoB,EAAA,UAAV,OADTnC,EAAA,GAAAC,EAqBiBC,EAAAqE,CAAA,GAAA;SAnBd,KAAKC,EAAO;SACZ,OAAKxD,EAAA,CAAoBY,GAAqB4C,EAAO,SAASpC,EAAA,OAAM,O;SAMpE,OAAOoC,EAAO;;SAEf,SAAArE,QAOO;UAPPI,EAOO,QAAA,EANL,OAAKS,EAAA,CAAC,+DACqBwD,EAAO,SAASpC,EAAA,OAAM,OAAI,mCAAA,iC,OAIrDhC,EAAmCa,GAAA,EAArB,MAAMuD,EAAO,K;UAE7BjE,EAA+D,QAA/DoB,GAA+DlB,EAAtB+D,EAAO,KAAK,GAAA,CAAA;UACpCA,EAAO,SAASpC,EAAA,OAAM,QAAvCpC,EAAA,GAAAC,EAA+CiB,GAAA,EAAA,KAAA,EAAA,CAAA,K;;;;;;OAI3CuB,EAAA,SADRzC,EAAA,GAAAC,EAsBiBC,EAAAkE,CAAA,GAAA;;QApBd,cAAYjC,EAAA;QACb,OAAM;QACL,eAAaC,EAAA,MAAM;QACpB,aAAY;QACX,uBAAkB,AAAAmB,EAAA,QAAA,MAAE,EAAA,QAAI;SAAA,MAAWnB,EAAA,MAAM;SAAI,KAAOoB;QAAM;;QAGzD,SAAArD,QAA4C,EAD9CH,EAAA,GAAAY,EAaiBE,GAAA,MAAAC,EAZI,CAAA,OAAA,MAAA,IAAX,GAAK,MADfX,EAaiBF,EAAAqE,CAAA,GAAA;SAXd,KAAKG;SACN,OAAK1D,EAAA,CAAC,0JACmBoB,EAAA,MAAM,QAAQsC,I;SAKtC,OAAOA;;SAER,SAAAvE,QAAwB,CAAxBC,EAAwBM,GAAA,EAAP,OAAG,GAAA,MAAA,GAAA,CAAA,KAAA,CAAA,GAAIF,EAAA,MACxBC,EAAGmC,EAAMH,EAAA,MAAQ,IAAI,CAAA,CAAEkC,EAAC,GAAA,CAAA,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"Input.js","names":["_sfc_main","Input_vue_vue_type_script_setup_true_lang_default","Input_default"],"sources":["../../../src/components/Input/Input.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useFieldControl } from '../FormField/context'\n\nexport interface InputProps {\n /** Marks the field as failing validation: a danger border and `aria-invalid`. */\n invalid?: boolean\n disabled?: boolean\n}\n\nconst props = defineProps<InputProps>()\n\nconst model = defineModel<string | null>()\n\nconst { attrs: fieldAttrs, invalid: isInvalid } = useFieldControl(\n () => model.value,\n () => props.invalid\n)\n</script>\n\n<!-- Attributes (id, type, placeholder, readonly, autocomplete...) land on the input itself. -->\n<template>\n <input\n v-bind=\"fieldAttrs\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n class=\"m-0 h-9 w-full appearance-none rounded-lg border bg-sui-surface px-3 font-sans text-sm leading-none text-sui-ink transition-colors duration-200 placeholder:text-sui-ink-faint\"\n :class=\"[\n isInvalid ? 'border-sui-danger-mid' : 'border-sui-line-control hover:border-sui-ink-muted',\n disabled\n ? 'pointer-events-none cursor-default opacity-60 select-none'\n : 'focus:border-sui-accent focus:ring-0 focus-visible:sui-ring-field'\n ]\"\n :disabled=\"disabled\"\n :value=\"model ?? ''\"\n @input=\"model = ($event.target as HTMLInputElement).value\"\n />\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"Input.js","names":["_sfc_main","Input_vue_vue_type_script_setup_true_lang_default","Input_default"],"sources":["../../../src/components/Input/Input.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useFieldControl } from '../FormField/context'\n\nexport interface InputProps {\n /** Marks the field as failing validation: a danger border and `aria-invalid`. */\n invalid?: boolean\n disabled?: boolean\n}\n\nconst props = defineProps<InputProps>()\n\nconst model = defineModel<string | null>()\n\nconst { attrs: fieldAttrs, invalid: isInvalid } = useFieldControl(\n () => model.value,\n () => props.invalid\n)\n</script>\n\n<!-- Attributes (id, type, placeholder, readonly, autocomplete...) land on the input itself. -->\n<template>\n <input\n v-bind=\"fieldAttrs\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n class=\"m-0 h-9 w-full appearance-none rounded-lg border bg-sui-surface px-3 font-sans text-sm leading-none text-sui-ink transition-[border-color,box-shadow] duration-200 placeholder:text-sui-ink-faint\"\n :class=\"[\n isInvalid ? 'border-sui-danger-mid' : 'border-sui-line-strong hover:border-sui-ink-muted',\n disabled\n ? 'pointer-events-none cursor-default opacity-60 select-none'\n : 'focus:border-sui-accent focus:ring-0 focus-visible:sui-ring-field'\n ]\"\n :disabled=\"disabled\"\n :value=\"model ?? ''\"\n @input=\"model = ($event.target as HTMLInputElement).value\"\n />\n</template>\n"],"mappings":""}
@@ -19,7 +19,7 @@ var c = [
19
19
  let r = n, l = s(n, "modelValue"), { attrs: u, invalid: d } = e(() => l.value, () => r.invalid);
20
20
  return (e, r) => (a(), t("input", i(o(u), {
21
21
  "aria-invalid": o(d) ? "true" : void 0,
22
- class: ["m-0 h-9 w-full appearance-none rounded-lg border bg-sui-surface px-3 font-sans text-sm leading-none text-sui-ink transition-colors duration-200 placeholder:text-sui-ink-faint", [o(d) ? "border-sui-danger-mid" : "border-sui-line-control hover:border-sui-ink-muted", n.disabled ? "pointer-events-none cursor-default opacity-60 select-none" : "focus:border-sui-accent focus:ring-0 focus-visible:sui-ring-field"]],
22
+ class: ["m-0 h-9 w-full appearance-none rounded-lg border bg-sui-surface px-3 font-sans text-sm leading-none text-sui-ink transition-[border-color,box-shadow] duration-200 placeholder:text-sui-ink-faint", [o(d) ? "border-sui-danger-mid" : "border-sui-line-strong hover:border-sui-ink-muted", n.disabled ? "pointer-events-none cursor-default opacity-60 select-none" : "focus:border-sui-accent focus:ring-0 focus-visible:sui-ring-field"]],
23
23
  disabled: n.disabled,
24
24
  value: l.value ?? "",
25
25
  onInput: r[0] ||= (e) => l.value = e.target.value
@@ -1 +1 @@
1
- {"version":3,"file":"Input.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_mergeProps","_unref","_hoisted_1","Input_vue_vue_type_script_setup_true_lang_default","\"modelValue\"","\"modelModifiers\"","props","__props","model","useModel","fieldAttrs","isInvalid","useFieldControl","openBlock","createElementBlock","mergeProps","unref","_cache","$event"],"sources":["../../../src/components/Input/Input.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useFieldControl } from '../FormField/context'\n\nexport interface InputProps {\n /** Marks the field as failing validation: a danger border and `aria-invalid`. */\n invalid?: boolean\n disabled?: boolean\n}\n\nconst props = defineProps<InputProps>()\n\nconst model = defineModel<string | null>()\n\nconst { attrs: fieldAttrs, invalid: isInvalid } = useFieldControl(\n () => model.value,\n () => props.invalid\n)\n</script>\n\n<!-- Attributes (id, type, placeholder, readonly, autocomplete...) land on the input itself. -->\n<template>\n <input\n v-bind=\"fieldAttrs\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n class=\"m-0 h-9 w-full appearance-none rounded-lg border bg-sui-surface px-3 font-sans text-sm leading-none text-sui-ink transition-colors duration-200 placeholder:text-sui-ink-faint\"\n :class=\"[\n isInvalid ? 'border-sui-danger-mid' : 'border-sui-line-control hover:border-sui-ink-muted',\n disabled\n ? 'pointer-events-none cursor-default opacity-60 select-none'\n : 'focus:border-sui-accent focus:ring-0 focus-visible:sui-ring-field'\n ]\"\n :disabled=\"disabled\"\n :value=\"model ?? ''\"\n @input=\"model = ($event.target as HTMLInputElement).value\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;EASA,IAAMS,IAAQC,GAERC,IAAQX,EAA0BU,GAAA,YAAC,GAEnC,EAAE,OAAOG,GAAY,SAASC,MAAcC,QAC1CJ,EAAM,aACNF,EAAM,OACd;E,kBAKER,EAAA,GAAAC,EAaE,SAbFC,EACUC,EAYRS,CAAA,GAZkB;GACjB,gBAAcT,EAAAU,CAAA,IAAS,SAAY,KAAA;GACpC,OAAK,CAAC,kLAAgL,CACtKV,EAAAU,CAAA,IAAS,0BAAA,sDAAyFJ,EAAA,W;GAMjH,UAAUA,EAAA;GACV,OAAOC,EAAA,SAAK;GACZ,SAAK,AAAAS,EAAA,QAAA,MAAE,EAAA,QAASC,EAAO,OAA4B"}
1
+ {"version":3,"file":"Input.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createElementBlock","_mergeProps","_unref","_hoisted_1","Input_vue_vue_type_script_setup_true_lang_default","\"modelValue\"","\"modelModifiers\"","props","__props","model","useModel","fieldAttrs","isInvalid","useFieldControl","openBlock","createElementBlock","mergeProps","unref","_cache","$event"],"sources":["../../../src/components/Input/Input.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { useFieldControl } from '../FormField/context'\n\nexport interface InputProps {\n /** Marks the field as failing validation: a danger border and `aria-invalid`. */\n invalid?: boolean\n disabled?: boolean\n}\n\nconst props = defineProps<InputProps>()\n\nconst model = defineModel<string | null>()\n\nconst { attrs: fieldAttrs, invalid: isInvalid } = useFieldControl(\n () => model.value,\n () => props.invalid\n)\n</script>\n\n<!-- Attributes (id, type, placeholder, readonly, autocomplete...) land on the input itself. -->\n<template>\n <input\n v-bind=\"fieldAttrs\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n class=\"m-0 h-9 w-full appearance-none rounded-lg border bg-sui-surface px-3 font-sans text-sm leading-none text-sui-ink transition-[border-color,box-shadow] duration-200 placeholder:text-sui-ink-faint\"\n :class=\"[\n isInvalid ? 'border-sui-danger-mid' : 'border-sui-line-strong hover:border-sui-ink-muted',\n disabled\n ? 'pointer-events-none cursor-default opacity-60 select-none'\n : 'focus:border-sui-accent focus:ring-0 focus-visible:sui-ring-field'\n ]\"\n :disabled=\"disabled\"\n :value=\"model ?? ''\"\n @input=\"model = ($event.target as HTMLInputElement).value\"\n />\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;EASA,IAAMS,IAAQC,GAERC,IAAQX,EAA0BU,GAAA,YAAC,GAEnC,EAAE,OAAOG,GAAY,SAASC,MAAcC,QAC1CJ,EAAM,aACNF,EAAM,OACd;E,kBAKER,EAAA,GAAAC,EAaE,SAbFC,EACUC,EAYRS,CAAA,GAZkB;GACjB,gBAAcT,EAAAU,CAAA,IAAS,SAAY,KAAA;GACpC,OAAK,CAAC,qMAAmM,CACzLV,EAAAU,CAAA,IAAS,0BAAA,qDAAwFJ,EAAA,W;GAMhH,UAAUA,EAAA;GACV,OAAOC,EAAA,SAAK;GACZ,SAAK,AAAAS,EAAA,QAAA,MAAE,EAAA,QAASC,EAAO,OAA4B"}
@@ -1 +1 @@
1
- {"version":3,"file":"Popover.js","names":["_sfc_main","Popover_vue_vue_type_script_setup_true_lang_default","Popover_default"],"sources":["../../../src/components/Popover/Popover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onBeforeUnmount, ref, useAttrs, watch } from 'vue'\n\nimport { PopoverAnchor, PopoverContent, PopoverPortal, PopoverRoot } from 'reka-ui'\n\nexport interface PopoverProps {\n /** The gap to the anchor, in px; negative overlaps it. */\n offset?: number\n /** Shifts it along the anchor's edge, in px. */\n alignOffset?: number\n closeOnEscape?: boolean\n}\n\n// Root is Reka's renderless PopoverRoot: class and attributes belong on the panel.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<PopoverProps>(), { offset: 4, alignOffset: 0, closeOnEscape: true })\n\nconst emit = defineEmits<{ show: []; hide: [] }>()\n\nconst attrs = useAttrs()\n\nconst open = ref(false)\nconst anchor = ref<HTMLElement>()\n// What was clicked to open it; clicks on it toggle the popover rather than counting as outside.\nconst opener = ref<HTMLElement>()\nconst label = ref<string>()\n\n/** Opens below the event's element, or below `target` when given. */\nfunction show(event: Event, target?: HTMLElement) {\n opener.value = event.currentTarget as HTMLElement\n anchor.value = target ?? opener.value\n // A dialog needs a name: an aria-label given to the popover, or else the name of the element it opened from.\n label.value =\n (attrs['aria-label'] as string | undefined) ??\n opener.value?.getAttribute('aria-label') ??\n opener.value?.textContent?.trim()\n open.value = true\n}\n\nfunction hide() {\n open.value = false\n}\n\nfunction toggle(event: Event, target?: HTMLElement) {\n if (open.value) hide()\n else show(event, target)\n}\n\ndefineExpose({ show, hide, toggle })\n\nfunction isOnAnchor(target: EventTarget | null) {\n return target instanceof Node && [anchor.value, opener.value].some((el) => el?.contains(target))\n}\n\nfunction onPointerDownOutside(event: CustomEvent<{ originalEvent: PointerEvent }>) {\n if (isOnAnchor(event.detail.originalEvent.target)) event.preventDefault()\n}\n\nfunction onEscape(event: KeyboardEvent) {\n if (!props.closeOnEscape) return event.preventDefault()\n anchor.value?.focus()\n}\n\n// Only an [autofocus] element inside takes focus on open; otherwise it stays where it was.\nfunction onOpenAutoFocus(event: Event) {\n event.preventDefault()\n ;(event.target as HTMLElement | null)?.querySelector<HTMLElement>('[autofocus]')?.focus()\n}\n\n// It closes when the page moves under it: a scrolling ancestor of the anchor, or a resized window.\nfunction onScroll(event: Event) {\n if (event.target instanceof Node && event.target.contains(anchor.value ?? null)) hide()\n}\n\nwatch(open, (isOpen) => {\n if (isOpen) {\n window.addEventListener('scroll', onScroll, true)\n window.addEventListener('resize', hide)\n emit('show')\n } else {\n window.removeEventListener('scroll', onScroll, true)\n window.removeEventListener('resize', hide)\n emit('hide')\n }\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('scroll', onScroll, true)\n window.removeEventListener('resize', hide)\n})\n</script>\n\n<template>\n <PopoverRoot v-model:open=\"open\">\n <PopoverAnchor :reference=\"anchor\" />\n <PopoverPortal>\n <PopoverContent\n v-bind=\"$attrs\"\n align=\"start\"\n :align-offset=\"alignOffset\"\n :aria-label=\"label\"\n class=\"z-[1000] block w-64 origin-center rounded-lg border border-sui-line-subtle bg-sui-surface text-sui-ink shadow-xl data-[state=closed]:animate-sui-overlay-out data-[state=open]:animate-sui-overlay-in\"\n side=\"bottom\"\n :side-offset=\"offset\"\n trap-focus\n @close-auto-focus.prevent\n @escape-key-down=\"onEscape\"\n @focus-outside.prevent\n @open-auto-focus=\"onOpenAutoFocus\"\n @pointer-down-outside=\"onPointerDownOutside\"\n >\n <slot :hide=\"hide\" />\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"Popover.js","names":["_sfc_main","Popover_vue_vue_type_script_setup_true_lang_default","Popover_default"],"sources":["../../../src/components/Popover/Popover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onBeforeUnmount, ref, useAttrs, watch } from 'vue'\n\nimport { PopoverAnchor, PopoverContent, PopoverPortal, PopoverRoot } from 'reka-ui'\n\nexport interface PopoverProps {\n /** The gap to the anchor, in px; negative overlaps it. */\n offset?: number\n /** Shifts it along the anchor's edge, in px. */\n alignOffset?: number\n closeOnEscape?: boolean\n /** The panel's width, e.g. `20rem`. */\n width?: string\n}\n\n// Root is Reka's renderless PopoverRoot: class and attributes belong on the panel.\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<PopoverProps>(), {\n offset: 4,\n alignOffset: 0,\n closeOnEscape: true,\n width: '16rem'\n})\n\nconst emit = defineEmits<{ show: []; hide: [] }>()\n\nconst attrs = useAttrs()\n\nconst open = ref(false)\nconst anchor = ref<HTMLElement>()\n// What was clicked to open it; clicks on it toggle the popover rather than counting as outside.\nconst opener = ref<HTMLElement>()\nconst label = ref<string>()\n// A press outside closes it and leaves focus to what was pressed.\nlet pressedOutside = false\n\n/** Opens below the event's element, or below `target` when given. */\nfunction show(event: Event, target?: HTMLElement) {\n opener.value = event.currentTarget as HTMLElement\n anchor.value = target ?? opener.value\n // A dialog needs a name: an aria-label given to the popover, or else the name of the element it opened from.\n label.value =\n (attrs['aria-label'] as string | undefined) ??\n opener.value?.getAttribute('aria-label') ??\n opener.value?.textContent?.trim()\n pressedOutside = false\n open.value = true\n}\n\nfunction hide() {\n open.value = false\n}\n\nfunction toggle(event: Event, target?: HTMLElement) {\n if (open.value) hide()\n else show(event, target)\n}\n\ndefineExpose({ show, hide, toggle })\n\nfunction isOnAnchor(target: EventTarget | null) {\n return target instanceof Node && [anchor.value, opener.value].some((el) => el?.contains(target))\n}\n\nfunction onPointerDownOutside(event: CustomEvent<{ originalEvent: PointerEvent }>) {\n if (isOnAnchor(event.detail.originalEvent.target)) event.preventDefault()\n else pressedOutside = true\n}\n\nfunction onEscape(event: KeyboardEvent) {\n if (!props.closeOnEscape) event.preventDefault()\n}\n\n// Otherwise focus left in the panel goes back to the anchor.\nfunction onCloseAutoFocus(event: Event) {\n event.preventDefault()\n const active = document.activeElement\n const inPanel = !active || active === document.body || (event.target as HTMLElement).contains(active)\n if (inPanel && !pressedOutside) anchor.value?.focus()\n}\n\n// Focus goes to an [autofocus] element inside, or else the panel, so Tab moves through it and Escape works at once.\n// The event comes from Reka's positioning wrapper around the panel.\nfunction onOpenAutoFocus(event: Event) {\n event.preventDefault()\n const wrapper = event.target as HTMLElement | null\n const panel = wrapper?.querySelector<HTMLElement>('[role=\"dialog\"]')\n ;(panel?.querySelector<HTMLElement>('[autofocus]') ?? panel)?.focus()\n}\n\n// It closes when the page moves under it: a scrolling ancestor of the anchor, or a resized window.\nfunction onScroll(event: Event) {\n if (event.target instanceof Node && event.target.contains(anchor.value ?? null)) hide()\n}\n\nwatch(open, (isOpen) => {\n if (isOpen) {\n window.addEventListener('scroll', onScroll, true)\n window.addEventListener('resize', hide)\n emit('show')\n } else {\n window.removeEventListener('scroll', onScroll, true)\n window.removeEventListener('resize', hide)\n emit('hide')\n }\n})\n\nonBeforeUnmount(() => {\n window.removeEventListener('scroll', onScroll, true)\n window.removeEventListener('resize', hide)\n})\n</script>\n\n<template>\n <PopoverRoot v-model:open=\"open\">\n <PopoverAnchor :reference=\"anchor\" />\n <PopoverPortal>\n <PopoverContent\n v-bind=\"$attrs\"\n align=\"start\"\n :align-offset=\"alignOffset\"\n :aria-label=\"label\"\n class=\"z-[1100] block origin-center rounded-lg border border-sui-line-subtle bg-sui-surface text-sui-ink shadow-xl data-[state=closed]:animate-sui-overlay-out data-[state=open]:animate-sui-overlay-in\"\n side=\"bottom\"\n :side-offset=\"offset\"\n :style=\"{ width }\"\n @close-auto-focus=\"onCloseAutoFocus\"\n @escape-key-down=\"onEscape\"\n @focus-outside.prevent\n @open-auto-focus=\"onOpenAutoFocus\"\n @pointer-down-outside=\"onPointerDownOutside\"\n >\n <slot :hide=\"hide\" />\n </PopoverContent>\n </PopoverPortal>\n </PopoverRoot>\n</template>\n"],"mappings":""}
@@ -4,6 +4,8 @@ export interface PopoverProps {
4
4
  /** Shifts it along the anchor's edge, in px. */
5
5
  alignOffset?: number;
6
6
  closeOnEscape?: boolean;
7
+ /** The panel's width, e.g. `20rem`. */
8
+ width?: string;
7
9
  }
8
10
  /** Opens below the event's element, or below `target` when given. */
9
11
  declare function show(event: Event, target?: HTMLElement): void;
@@ -26,6 +28,7 @@ declare const __VLS_base: import("vue").DefineComponent<PopoverProps, {
26
28
  onShow?: (() => any) | undefined;
27
29
  onHide?: (() => any) | undefined;
28
30
  }>, {
31
+ width: string;
29
32
  alignOffset: number;
30
33
  offset: number;
31
34
  closeOnEscape: boolean;