@treeui/vue 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/TAccordion.cjs.map +1 -1
- package/dist/components/TAccordion.js.map +1 -1
- package/dist/components/TAccordion.vue_vue_type_script_setup_true_lang.cjs +1 -1
- package/dist/components/TAccordion.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
- package/dist/components/TAccordion.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/components/TAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/TAccordionItem.cjs.map +1 -1
- package/dist/components/TAccordionItem.js.map +1 -1
- package/dist/components/TAccordionItem.vue_vue_type_script_setup_true_lang.cjs +1 -1
- package/dist/components/TAccordionItem.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
- package/dist/components/TAccordionItem.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/TAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/TDropdown.cjs.map +1 -1
- package/dist/components/TDropdown.js.map +1 -1
- package/dist/components/TDropdown.vue.d.ts +4 -0
- package/dist/components/TDropdown.vue.d.ts.map +1 -1
- package/dist/components/TDropdown.vue_vue_type_script_setup_true_lang.cjs +1 -1
- package/dist/components/TDropdown.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
- package/dist/components/TDropdown.vue_vue_type_script_setup_true_lang.js +22 -18
- package/dist/components/TDropdown.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/TFlag.cjs +2 -0
- package/dist/components/TFlag.cjs.map +1 -0
- package/dist/components/TFlag.js +7 -0
- package/dist/components/TFlag.js.map +1 -0
- package/dist/components/TFlag.vue.d.ts +20 -0
- package/dist/components/TFlag.vue.d.ts.map +1 -0
- package/dist/components/TFlag.vue_vue_type_script_setup_true_lang.cjs +2 -0
- package/dist/components/TFlag.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
- package/dist/components/TFlag.vue_vue_type_script_setup_true_lang.js +58 -0
- package/dist/components/TFlag.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/TIcon.vue.d.ts +1 -1
- package/dist/components/TLanguageSelect.cjs +2 -0
- package/dist/components/TLanguageSelect.cjs.map +1 -0
- package/dist/components/TLanguageSelect.js +7 -0
- package/dist/components/TLanguageSelect.js.map +1 -0
- package/dist/components/TLanguageSelect.vue.d.ts +103 -0
- package/dist/components/TLanguageSelect.vue.d.ts.map +1 -0
- package/dist/components/TLanguageSelect.vue_vue_type_script_setup_true_lang.cjs +2 -0
- package/dist/components/TLanguageSelect.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
- package/dist/components/TLanguageSelect.vue_vue_type_script_setup_true_lang.js +299 -0
- package/dist/components/TLanguageSelect.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/TPopover.cjs.map +1 -1
- package/dist/components/TPopover.js.map +1 -1
- package/dist/components/TPopover.vue.d.ts +4 -2
- package/dist/components/TPopover.vue.d.ts.map +1 -1
- package/dist/components/TPopover.vue_vue_type_script_setup_true_lang.cjs +1 -1
- package/dist/components/TPopover.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
- package/dist/components/TPopover.vue_vue_type_script_setup_true_lang.js +10 -5
- package/dist/components/TPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/accordion.cjs.map +1 -1
- package/dist/components/accordion.d.ts +4 -4
- package/dist/components/accordion.d.ts.map +1 -1
- package/dist/components/accordion.js.map +1 -1
- package/dist/components/index.d.ts +4 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +80 -78
- package/dist/plugin.cjs +1 -1
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +146 -142
- package/dist/plugin.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TLanguageSelect.vue_vue_type_script_setup_true_lang.cjs","names":["$slots"],"sources":["../../src/components/TLanguageSelect.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TFieldWidth, TSize } from '../types/contracts';\nimport TFlag from './TFlag.vue';\nimport TIcon from './TIcon.vue';\nimport TSpinner from './TSpinner.vue';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\n/**\n * `field` is a form control: it reads as the value of a labelled question, so the\n * flag leads and the trigger fills its container.\n *\n * `switcher` is a page-level control, typically in a navbar, where nothing nearby\n * says what it changes. The translate icon states the purpose up front and the\n * current flag closes the row, so the whole thing reads as \"page language, now\n * set to this\" without an external label.\n */\nexport type TLanguageSelectVariant = 'field' | 'switcher';\n\nexport interface TLanguageOption {\n label: string;\n /** Opaque application key — typically a BCP-47 tag. Never parsed or validated. */\n value: string;\n /** ISO 3166-1 alpha-2 code for the flag. Omit to render the option without one. */\n code?: string;\n /** Secondary line, e.g. the language's endonym. */\n description?: string;\n disabled?: boolean;\n}\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string;\n options?: TLanguageOption[];\n open?: boolean;\n defaultOpen?: boolean;\n size?: TSize;\n variant?: TLanguageSelectVariant;\n /** Hide the language name, leaving icon + flag. `switcher` only. */\n iconOnly?: boolean;\n /** Inline-size cap. Fluid (`full`) by default. */\n width?: TFieldWidth;\n disabled?: boolean;\n loading?: boolean;\n invalid?: boolean;\n placeholder?: string;\n /** Forwarded to every nested TFlag. Set once here to self-host flag assets. */\n flagBaseUrl?: string;\n emptyText?: string;\n }>(),\n {\n modelValue: '',\n options: () => [],\n open: undefined,\n defaultOpen: false,\n size: 'md',\n variant: 'field',\n iconOnly: false,\n width: 'full',\n disabled: false,\n loading: false,\n invalid: false,\n placeholder: '',\n flagBaseUrl: undefined,\n emptyText: 'No languages available.',\n },\n);\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n prefix?: () => unknown;\n option?: (props: { option: TLanguageOption; selected: boolean; focused: boolean }) => unknown;\n empty?: () => unknown;\n}>();\n\nconst attrs = useAttrs();\nconst listboxId = createId('t-language-select');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLButtonElement | null>(null);\nconst listboxRef = ref<HTMLElement | null>(null);\nconst optionRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\nconst dropUp = ref(false);\n\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs;\n return rest;\n});\n\nconst { value: isOpen, setValue } = useControllableOpen(\n toRef(props, 'open'),\n props.defaultOpen,\n (value) => {\n emit('update:open', value);\n emit('open-change', value);\n },\n);\n\nconst isSwitcher = computed(() => props.variant === 'switcher');\n\nconst rootClasses = computed(() => [\n 't-language-select',\n `t-language-select--${props.size}`,\n `t-language-select--${props.variant}`,\n // A switcher sizes to its content, so the field width scale does not apply.\n !isSwitcher.value && props.width !== 'full' ? `t-field-width--${props.width}` : null,\n {\n 't-language-select--icon-only': isSwitcher.value && props.iconOnly,\n 't-language-select--drop-up': dropUp.value,\n 'is-disabled': props.disabled,\n 'is-invalid': props.invalid,\n 'is-loading': props.loading,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\n// Nearest ancestor that can clip the listbox (scroll container or hidden overflow).\nconst findClippingAncestor = (element: HTMLElement): HTMLElement | null => {\n let parent = element.parentElement;\n while (parent && parent !== document.body) {\n const { overflowY } = window.getComputedStyle(parent);\n if (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'hidden') {\n return parent;\n }\n parent = parent.parentElement;\n }\n return null;\n};\n\n// Flip the listbox above the trigger when its rendered position overflows the\n// nearest clipping ancestor (e.g. a modal body) or the viewport, and there is\n// more room above the trigger than below it. Measuring the rendered rect keeps\n// the decision in sync with the CSS offset (--tree-space-2) automatically.\nconst updateDropDirection = () => {\n const trigger = triggerRef.value;\n const listbox = listboxRef.value;\n if (!trigger || !listbox) {\n dropUp.value = false;\n return;\n }\n const triggerRect = trigger.getBoundingClientRect();\n const listboxRect = listbox.getBoundingClientRect();\n const boundary = findClippingAncestor(trigger)?.getBoundingClientRect();\n const bottomLimit = Math.min(boundary?.bottom ?? Infinity, window.innerHeight);\n const topLimit = Math.max(boundary?.top ?? 0, 0);\n const spaceBelow = bottomLimit - triggerRect.bottom;\n const spaceAbove = triggerRect.top - topLimit;\n dropUp.value = listboxRect.bottom > bottomLimit && spaceAbove > spaceBelow;\n};\n\nconst rootStyle = computed(() => attrs.style);\n\nconst selectedOption = computed(() =>\n props.options.find((o) => o.value === props.modelValue),\n);\n\nconst selectedLabel = computed(() => selectedOption.value?.label ?? '');\n\n// iconOnly leans on the flag to carry the current value. With no flag to show it\n// would leave the trigger stating nothing at all, so the name comes back.\nconst showValue = computed(\n () => !(isSwitcher.value && props.iconOnly) || !selectedOption.value?.code,\n);\n\nconst enabledOptions = computed(() =>\n props.options.filter((o) => !o.disabled),\n);\n\n// Runs for every open, however it was triggered. The listbox can also be opened\n// through `open` / `defaultOpen` without going near openDropdown(), so this lives\n// on the isOpen watcher rather than inside the click handler.\nconst onOpened = () => {\n const selectedIdx = props.options.findIndex((o) => o.value === props.modelValue);\n focusedIndex.value = selectedIdx >= 0 ? selectedIdx : 0;\n // Render downward first so the measurement always starts from the default position.\n dropUp.value = false;\n nextTick(() => {\n updateDropDirection();\n focusOption(focusedIndex.value);\n });\n};\n\nconst openDropdown = () => {\n if (props.disabled) return;\n setValue(true);\n};\n\nconst closeDropdown = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => triggerRef.value?.focus());\n }\n};\n\nconst toggleDropdown = () => {\n if (isOpen.value) {\n closeDropdown();\n } else {\n openDropdown();\n }\n};\n\nconst selectOption = (opt: TLanguageOption) => {\n if (opt.disabled) return;\n emit('update:modelValue', opt.value);\n closeDropdown(true);\n};\n\nconst focusOption = (index: number) => {\n const opt = props.options[index];\n if (!opt) return;\n const el = optionRefs.value.get(opt.value);\n el?.focus();\n};\n\nconst setOptionRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n optionRefs.value.set(value, el);\n } else {\n optionRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.options.length) {\n if (!props.options[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusOption(nextIndex);\n return;\n }\n nextIndex += direction;\n }\n};\n\nconst onTriggerKeydown = (event: KeyboardEvent) => {\n if (props.disabled) return;\n\n if (isEscapeKey(event) && isOpen.value) {\n event.preventDefault();\n closeDropdown();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openDropdown();\n }\n};\n\nconst onOptionKeydown = (event: KeyboardEvent, opt: TLanguageOption, _index: number) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeDropdown(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectOption(opt);\n return;\n }\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n moveFocus(1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n moveFocus(-1);\n break;\n case 'Home':\n event.preventDefault();\n focusedIndex.value = enabledOptions.value.length > 0\n ? props.options.indexOf(enabledOptions.value[0])\n : 0;\n focusOption(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledOptions.value.length > 0\n ? props.options.indexOf(enabledOptions.value[enabledOptions.value.length - 1])\n : props.options.length - 1;\n focusOption(focusedIndex.value);\n break;\n default:\n break;\n }\n};\n\nconst onDocumentPointerDown = (event: PointerEvent) => {\n if (!isOpen.value) return;\n const target = event.target;\n if (!(target instanceof Node)) return;\n if (rootRef.value?.contains(target)) return;\n closeDropdown();\n};\n\nconst hasSelection = computed(() => props.modelValue !== '');\n\n// immediate, so a listbox that is already open on mount (`defaultOpen`, or a\n// controlled `open` that starts true) still dismisses on outside click and still\n// measures its drop direction.\nwatch(isOpen, (value) => {\n if (value) {\n document.addEventListener('pointerdown', onDocumentPointerDown);\n onOpened();\n } else {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n }\n}, { immediate: true });\n\n// Options can shrink underneath an open listbox. Leaving focusedIndex past the\n// end would strand moveFocus(), which only ever walks outward from it.\nwatch(\n () => props.options.length,\n (length) => {\n if (isOpen.value && focusedIndex.value >= length) {\n focusedIndex.value = length - 1;\n }\n },\n);\n\nonBeforeUnmount(() => {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n});\n</script>\n\n<template>\n <div\n ref=\"rootRef\"\n :class=\"rootClasses\"\n :style=\"rootStyle\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n >\n <button\n ref=\"triggerRef\"\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-language-select__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? listboxId : undefined\"\n aria-haspopup=\"listbox\"\n :aria-expanded=\"isOpen\"\n :aria-invalid=\"invalid || undefined\"\n :aria-busy=\"loading || undefined\"\n @click=\"toggleDropdown\"\n @keydown=\"onTriggerKeydown\"\n >\n <span\n v-if=\"$slots.prefix\"\n class=\"t-language-select__slot t-language-select__slot--prefix\"\n >\n <slot name=\"prefix\" />\n </span>\n <!--\n The switcher leads with the translate icon so the control announces what\n it changes; the field leads with the flag, since a form label already\n does that job.\n -->\n <!-- Sized in CSS from the icon token scale, not TIcon's pixel `size` prop. -->\n <TIcon\n v-if=\"isSwitcher\"\n name=\"languages\"\n class=\"t-language-select__translate\"\n />\n <TFlag\n v-else-if=\"selectedOption?.code\"\n :code=\"selectedOption.code\"\n :base-url=\"flagBaseUrl\"\n :size=\"size\"\n />\n <span\n v-if=\"showValue\"\n class=\"t-language-select__value\"\n :data-placeholder=\"!hasSelection ? true : undefined\"\n >\n {{ selectedLabel || placeholder }}\n </span>\n <TFlag\n v-if=\"isSwitcher && selectedOption?.code\"\n :code=\"selectedOption.code\"\n :base-url=\"flagBaseUrl\"\n :size=\"size\"\n />\n <TSpinner\n v-if=\"loading\"\n size=\"sm\"\n label=\"Loading\"\n />\n <svg\n v-else\n class=\"t-language-select__chevron\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"4 6 8 10 12 6\" />\n </svg>\n </button>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"listboxId\"\n ref=\"listboxRef\"\n role=\"listbox\"\n class=\"t-language-select__listbox\"\n :aria-label=\"typeof triggerAttrs['aria-label'] === 'string' ? triggerAttrs['aria-label'] : undefined\"\n >\n <li\n v-if=\"options.length === 0\"\n class=\"t-language-select__empty\"\n role=\"presentation\"\n >\n <slot name=\"empty\">\n {{ emptyText }}\n </slot>\n </li>\n <li\n v-for=\"(opt, index) in options\"\n :key=\"opt.value\"\n :ref=\"(el) => setOptionRef(el as Element | null, opt.value)\"\n role=\"option\"\n class=\"t-language-select__option\"\n :class=\"{\n 'is-selected': opt.value === modelValue,\n 'is-disabled': opt.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-selected=\"opt.value === modelValue\"\n :aria-disabled=\"opt.disabled || undefined\"\n :tabindex=\"opt.disabled ? -1 : 0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt, index)\"\n >\n <slot\n name=\"option\"\n :option=\"opt\"\n :selected=\"opt.value === modelValue\"\n :focused=\"index === focusedIndex\"\n >\n <TFlag\n v-if=\"opt.code\"\n :code=\"opt.code\"\n :base-url=\"flagBaseUrl\"\n :size=\"size\"\n />\n <span class=\"t-language-select__option-text\">\n <span class=\"t-language-select__option-label\">{{ opt.label }}</span>\n <span\n v-if=\"opt.description\"\n class=\"t-language-select__description\"\n >\n {{ opt.description }}\n </span>\n </span>\n </slot>\n <svg\n v-if=\"opt.value === modelValue\"\n class=\"t-language-select__check\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"3.5 8.5 6.5 11.5 12.5 4.5\" />\n </svg>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":"qlDAmCA,IAAM,EAAQ,EAsCR,EAAO,EAYP,GAAA,EAAA,EAAA,SAAA,CAAiB,EACjB,GAAA,EAAA,EAAA,SAAA,CAAqB,mBAAmB,EACxC,GAAA,EAAA,EAAA,IAAA,CAAkC,IAAI,EACtC,GAAA,EAAA,EAAA,IAAA,CAA2C,IAAI,EAC/C,GAAA,EAAA,EAAA,IAAA,CAAqC,IAAI,EACzC,GAAA,EAAA,EAAA,IAAA,CAA2C,IAAI,GAAK,EACpD,GAAA,EAAA,EAAA,IAAA,CAAmB,EAAE,EACrB,GAAA,EAAA,EAAA,IAAA,CAAa,EAAK,EAElB,GAAA,EAAA,EAAA,SAAA,KAA8B,CAClC,GAAM,CAAE,MAAO,EAAQ,MAAO,EAAQ,GAAG,GAAS,EAClD,OAAO,CACT,CAAC,EAEK,CAAE,MAAO,EAAQ,YAAa,EAAA,qBAAA,EAAA,EAAA,MAAA,CAC5B,EAAO,MAAM,EACnB,EAAM,YACL,GAAU,CACT,EAAK,cAAe,CAAK,EACzB,EAAK,cAAe,CAAK,CAC3B,CACF,EAEM,GAAA,EAAA,EAAA,SAAA,KAA4B,EAAM,UAAY,UAAU,EAExD,GAAA,EAAA,EAAA,SAAA,KAA6B,CACjC,oBACA,sBAAsB,EAAM,OAC5B,sBAAsB,EAAM,UAE5B,CAAC,EAAW,OAAS,EAAM,QAAU,OAAS,kBAAkB,EAAM,QAAU,KAChF,CACE,+BAAgC,EAAW,OAAS,EAAM,SAC1D,6BAA8B,EAAO,MACrC,cAAe,EAAM,SACrB,aAAc,EAAM,QACpB,aAAc,EAAM,QACpB,UAAW,EAAO,KACpB,EACA,EAAM,KACR,CAAC,EAGK,EAAwB,GAA6C,CACzE,IAAI,EAAS,EAAQ,cACrB,KAAO,GAAU,IAAW,SAAS,MAAM,CACzC,GAAM,CAAE,aAAc,OAAO,iBAAiB,CAAM,EACpD,GAAI,IAAc,QAAU,IAAc,UAAY,IAAc,SAClE,OAAO,EAET,EAAS,EAAO,aAClB,CACA,OAAO,IACT,EAMM,MAA4B,CAChC,IAAM,EAAU,EAAW,MACrB,EAAU,EAAW,MAC3B,GAAI,CAAC,GAAW,CAAC,EAAS,CACxB,EAAO,MAAQ,GACf,MACF,CACA,IAAM,EAAc,EAAQ,sBAAsB,EAC5C,EAAc,EAAQ,sBAAsB,EAC5C,EAAW,EAAqB,CAAO,CAAC,EAAE,sBAAsB,EAChE,EAAc,KAAK,IAAI,GAAU,QAAU,IAAU,OAAO,WAAW,EACvE,EAAW,KAAK,IAAI,GAAU,KAAO,EAAG,CAAC,EACzC,EAAa,EAAc,EAAY,OACvC,EAAa,EAAY,IAAM,EACrC,EAAO,MAAQ,EAAY,OAAS,GAAe,EAAa,CAClE,EAEM,GAAA,EAAA,EAAA,SAAA,KAA2B,EAAM,KAAK,EAEtC,GAAA,EAAA,EAAA,SAAA,KACJ,EAAM,QAAQ,KAAM,GAAM,EAAE,QAAU,EAAM,UAAU,CACxD,EAEM,GAAA,EAAA,EAAA,SAAA,KAA+B,EAAe,OAAO,OAAS,EAAE,EAIhE,GAAA,EAAA,EAAA,SAAA,KACE,EAAE,EAAW,OAAS,EAAM,WAAa,CAAC,EAAe,OAAO,IACxE,EAEM,GAAA,EAAA,EAAA,SAAA,KACJ,EAAM,QAAQ,OAAQ,GAAM,CAAC,EAAE,QAAQ,CACzC,EAKM,MAAiB,CACrB,IAAM,EAAc,EAAM,QAAQ,UAAW,GAAM,EAAE,QAAU,EAAM,UAAU,EAC/E,EAAa,MAAQ,GAAe,EAAI,EAAc,EAEtD,EAAO,MAAQ,IACf,EAAA,EAAA,SAAA,KAAe,CACb,EAAoB,EACpB,EAAY,EAAa,KAAK,CAChC,CAAC,CACH,EAEM,MAAqB,CACrB,EAAM,UACV,EAAS,EAAI,CACf,EAEM,GAAiB,EAAe,KAAU,CAC9C,EAAS,EAAK,EACd,EAAa,MAAQ,GACjB,IACF,EAAA,EAAA,SAAA,KAAe,EAAW,OAAO,MAAM,CAAC,CAE5C,EAEM,MAAuB,CACvB,EAAO,MACT,EAAc,EAEd,EAAa,CAEjB,EAEM,EAAgB,GAAyB,CACzC,EAAI,WACR,EAAK,oBAAqB,EAAI,KAAK,EACnC,EAAc,EAAI,EACpB,EAEM,EAAe,GAAkB,CACrC,IAAM,EAAM,EAAM,QAAQ,GACrB,GAEL,EADsB,MAAM,IAAI,EAAI,KACpC,CAAA,EAAI,MAAM,CACZ,EAEM,GAAgB,EAAoB,IAAkB,CACtD,aAAc,YAChB,EAAW,MAAM,IAAI,EAAO,CAAE,EAE9B,EAAW,MAAM,OAAO,CAAK,CAEjC,EAEM,EAAa,GAAsB,CACvC,IAAI,EAAY,EAAa,MAAQ,EACrC,KAAO,GAAa,GAAK,EAAY,EAAM,QAAQ,QAAQ,CACzD,GAAI,CAAC,EAAM,QAAQ,EAAU,CAAC,SAAU,CACtC,EAAa,MAAQ,EACrB,EAAY,CAAS,EACrB,MACF,CACA,GAAa,CACf,CACF,EAEM,EAAoB,GAAyB,CAC7C,MAAM,SAEV,KAAA,EAAA,EAAA,YAAA,CAAgB,CAAK,GAAK,EAAO,MAAO,CACtC,EAAM,eAAe,EACrB,EAAc,EACd,MACF,GAEA,EAAA,EAAA,gBAAA,CAAoB,CAAK,GAAK,EAAM,MAAQ,aAAe,EAAM,MAAQ,aACvE,EAAM,eAAe,EACrB,EAAa,EAJf,CAMF,EAEM,GAAmB,EAAsB,EAAsB,IAAmB,CACtF,IAAA,EAAA,EAAA,YAAA,CAAgB,CAAK,EAAG,CACtB,EAAM,eAAe,EACrB,EAAc,EAAI,EAClB,MACF,CAEA,IAAA,EAAA,EAAA,gBAAA,CAAoB,CAAK,EAAG,CAC1B,EAAM,eAAe,EACrB,EAAa,CAAG,EAChB,MACF,CAEA,OAAQ,EAAM,IAAd,CACE,IAAK,YACH,EAAM,eAAe,EACrB,EAAU,CAAC,EACX,MACF,IAAK,UACH,EAAM,eAAe,EACrB,EAAU,EAAE,EACZ,MACF,IAAK,OACH,EAAM,eAAe,EACrB,EAAa,MAAQ,EAAe,MAAM,OAAS,EAC/C,EAAM,QAAQ,QAAQ,EAAe,MAAM,EAAE,EAC7C,EACJ,EAAY,EAAa,KAAK,EAC9B,MACF,IAAK,MACH,EAAM,eAAe,EACrB,EAAa,MAAQ,EAAe,MAAM,OAAS,EAC/C,EAAM,QAAQ,QAAQ,EAAe,MAAM,EAAe,MAAM,OAAS,EAAE,EAC3E,EAAM,QAAQ,OAAS,EAC3B,EAAY,EAAa,KAAK,EAC9B,MACF,QACE,KACJ,CACF,EAEM,EAAyB,GAAwB,CACrD,GAAI,CAAC,EAAO,MAAO,OACnB,IAAM,EAAS,EAAM,OACf,aAAkB,OACpB,EAAQ,OAAO,SAAS,CAAM,GAClC,EAAc,EAChB,EAEM,GAAA,EAAA,EAAA,SAAA,KAA8B,EAAM,aAAe,EAAE,SAK3D,EAAA,EAAA,MAAA,CAAM,EAAS,GAAU,CACnB,GACF,SAAS,iBAAiB,cAAe,CAAqB,EAC9D,EAAS,GAET,SAAS,oBAAoB,cAAe,CAAqB,CAErE,EAAG,CAAE,UAAW,EAAK,CAAC,GAItB,EAAA,EAAA,MAAA,KACQ,EAAM,QAAQ,OACnB,GAAW,CACN,EAAO,OAAS,EAAa,OAAS,IACxC,EAAa,MAAQ,EAAS,EAElC,CACF,GAEA,EAAA,EAAA,gBAAA,KAAsB,CACpB,SAAS,oBAAoB,cAAe,CAAqB,CACnE,CAAC,qDAwJO,MAAA,SAnJA,UAAJ,IAAI,EACH,OAAA,EAAA,EAAA,eAAA,CAAO,EAAA,KAAW,EAClB,OAAA,EAAA,EAAA,eAAA,CAAO,EAAA,KAAS,EAChB,cAAA,EAAA,EAAA,MAAA,CAAY,CAAA,EAAM,OAAA,oCAsEV,UAAA,EAAA,EAAA,WAAA,CAAA,SAnEH,aAAJ,IAAI,GACI,EAAA,MAAY,CACpB,KAAK,SACL,MAAM,6BACL,SAAU,EAAA,SACV,iBAAA,EAAA,EAAA,MAAA,CAAe,CAAA,GAAA,EAAA,EAAA,MAAA,CAAS,CAAA,EAAY,IAAA,GACrC,gBAAc,UACb,iBAAA,EAAA,EAAA,MAAA,CAAe,CAAA,EACf,eAAc,EAAA,SAAW,IAAA,GACzB,YAAW,EAAA,SAAW,IAAA,GACtB,QAAO,EACP,UAAS,KAGFA,EAAAA,OAAO,SAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAIR,OALP,EAKO,EAAA,EAAA,EAAA,WAAA,CADiB,EAAA,OAAA,QAAA,CAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,EAShB,EAAA,QAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,CAGN,EAAA,QAAA,OAFA,KAAK,YACL,MAAM,kCAGK,EAAA,OAAgB,OAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,CAI3B,EAAA,QAAA,OAHC,KAAM,EAAA,MAAe,KACrB,WAAU,EAAA,YACV,KAAM,EAAA,0EAGD,EAAA,QAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAKD,OAAA,OAJL,MAAM,2BACL,mBAAgB,CAAG,EAAA,OAAsB,IAAA,0BAEvC,EAAA,OAAiB,EAAA,WAAW,EAAA,EAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,EAGzB,EAAA,OAAc,EAAA,OAAgB,OAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,CAIpC,EAAA,QAAA,OAHC,KAAM,EAAA,MAAe,KACrB,WAAU,EAAA,YACV,KAAM,EAAA,0EAGD,EAAA,UAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,CAGN,EAAA,QAAA,OAFA,KAAK,KACL,MAAM,yDAcF,MAZN,EAYM,CAAA,GAAA,AAAA,EAAA,KAAA,EAAA,EAAA,EAAA,mBAAA,CAD+B,WAAA,CAAzB,OAAO,eAAe,EAAA,KAAA,EAAA,CAAA,CAAA,CAAA,4BA2EvB,EAAA,WAAA,CAxED,KAAK,QAAQ,EAAA,2BAuElB,EAAA,EAAA,EAAA,MAAA,CArEG,CAAA,GAAM,CAAK,EAAA,WAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAqEd,KAAA,OApEF,IAAA,EAAA,EAAA,MAAA,CAAI,CAAA,UACD,aAAJ,IAAI,EACJ,KAAK,UACL,MAAM,6BACL,aAAU,OAAS,EAAA,MAAY,eAAA,SAA8B,EAAA,MAAY,cAAiB,IAAA,KAGnF,EAAA,QAAQ,SAAM,IAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAOjB,KARL,EAQK,EAAA,EAAA,EAAA,WAAA,CADI,EAAA,OAAA,QAAA,CAAA,MAAA,EAAA,EAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,gBAAA,CADF,EAAA,SAAS,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,IAAA,EAAA,EAAA,UAAA,CAAA,EAAA,GAAA,EAAA,EAAA,mBAAA,CAuDX,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CAnDoB,EAAA,SAAf,EAAK,gDAmDV,KAAA,CAlDF,IAAK,EAAI,iBACT,IAAM,GAAO,EAAa,EAAsB,EAAI,KAAK,EAC1D,KAAK,SACL,OAAA,EAAA,EAAA,eAAA,CAAK,CAAC,4BAA2B,eACI,EAAI,QAAU,EAAA,yBAAuC,EAAI,sBAAoC,IAAU,EAAA,SAK3I,gBAAe,EAAI,QAAU,EAAA,WAC7B,gBAAe,EAAI,UAAY,IAAA,GAC/B,SAAU,EAAI,SAAQ,GAAA,EACtB,QAAK,GAAE,EAAa,CAAG,EACvB,UAAO,GAAE,EAAgB,EAAQ,EAAK,CAAK,qBAuBrC,EAAA,OAAA,SAAA,CAnBJ,OAAQ,EACR,SAAU,EAAI,QAAU,EAAA,WACxB,QAAS,IAAU,EAAA,WAiBf,CAdG,EAAI,OAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,YAAA,CAIV,EAAA,QAAA,OAHC,KAAM,EAAI,KACV,WAAU,EAAA,YACV,KAAM,EAAA,mGAUF,OARP,EAQO,EAAA,EAAA,EAAA,mBAAA,CAP+D,OAApE,GAAA,EAAA,EAAA,gBAAA,CAAiD,EAAI,KAAK,EAAA,CAAA,EAElD,EAAI,cAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAIL,OALP,GAAA,EAAA,EAAA,gBAAA,CAIK,EAAI,WAAW,EAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,CAAA,CAAA,CAAA,CAAA,EAKhB,EAAI,QAAU,EAAA,aAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAWhB,MAZN,EAYM,CAAA,GAAA,AAAA,EAAA,KAAA,EAAA,EAAA,EAAA,mBAAA,CAD2C,WAAA,CAArC,OAAO,2BAA2B,EAAA,KAAA,EAAA,CAAA,CAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,CAAA,EAAA,GAAA,CAAA"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import e from "./TSpinner.js";
|
|
2
|
+
import { useControllableOpen as t } from "../composables/useControllableOpen.js";
|
|
3
|
+
import n from "./TFlag.js";
|
|
4
|
+
import r from "./TIcon.js";
|
|
5
|
+
import { Fragment as i, Transition as a, computed as o, createBlock as s, createCommentVNode as c, createElementBlock as l, createElementVNode as u, createTextVNode as ee, createVNode as d, defineComponent as f, mergeProps as p, nextTick as m, normalizeClass as h, normalizeStyle as te, onBeforeUnmount as g, openBlock as _, ref as v, renderList as y, renderSlot as b, toDisplayString as x, toRef as ne, unref as S, useAttrs as C, watch as w, withCtx as T } from "vue";
|
|
6
|
+
import { createId as E, isActivationKey as D, isEscapeKey as O } from "@treeui/utils";
|
|
7
|
+
//#region src/components/TLanguageSelect.vue?vue&type=script&setup=true&lang.ts
|
|
8
|
+
var k = ["data-state"], re = [
|
|
9
|
+
"disabled",
|
|
10
|
+
"aria-controls",
|
|
11
|
+
"aria-expanded",
|
|
12
|
+
"aria-invalid",
|
|
13
|
+
"aria-busy"
|
|
14
|
+
], ie = {
|
|
15
|
+
key: 0,
|
|
16
|
+
class: "t-language-select__slot t-language-select__slot--prefix"
|
|
17
|
+
}, ae = ["data-placeholder"], oe = {
|
|
18
|
+
key: 6,
|
|
19
|
+
class: "t-language-select__chevron",
|
|
20
|
+
viewBox: "0 0 16 16",
|
|
21
|
+
fill: "none",
|
|
22
|
+
stroke: "currentColor",
|
|
23
|
+
"stroke-width": "2",
|
|
24
|
+
"stroke-linecap": "round",
|
|
25
|
+
"stroke-linejoin": "round",
|
|
26
|
+
"aria-hidden": "true"
|
|
27
|
+
}, se = ["id", "aria-label"], ce = {
|
|
28
|
+
key: 0,
|
|
29
|
+
class: "t-language-select__empty",
|
|
30
|
+
role: "presentation"
|
|
31
|
+
}, le = [
|
|
32
|
+
"aria-selected",
|
|
33
|
+
"aria-disabled",
|
|
34
|
+
"tabindex",
|
|
35
|
+
"onClick",
|
|
36
|
+
"onKeydown"
|
|
37
|
+
], ue = { class: "t-language-select__option-text" }, de = { class: "t-language-select__option-label" }, fe = {
|
|
38
|
+
key: 0,
|
|
39
|
+
class: "t-language-select__description"
|
|
40
|
+
}, pe = {
|
|
41
|
+
key: 0,
|
|
42
|
+
class: "t-language-select__check",
|
|
43
|
+
viewBox: "0 0 16 16",
|
|
44
|
+
fill: "none",
|
|
45
|
+
stroke: "currentColor",
|
|
46
|
+
"stroke-width": "2",
|
|
47
|
+
"stroke-linecap": "round",
|
|
48
|
+
"stroke-linejoin": "round",
|
|
49
|
+
"aria-hidden": "true"
|
|
50
|
+
}, A = /*@__PURE__*/ f({
|
|
51
|
+
inheritAttrs: !1,
|
|
52
|
+
__name: "TLanguageSelect",
|
|
53
|
+
props: {
|
|
54
|
+
modelValue: { default: "" },
|
|
55
|
+
options: { default: () => [] },
|
|
56
|
+
open: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
default: void 0
|
|
59
|
+
},
|
|
60
|
+
defaultOpen: {
|
|
61
|
+
type: Boolean,
|
|
62
|
+
default: !1
|
|
63
|
+
},
|
|
64
|
+
size: { default: "md" },
|
|
65
|
+
variant: { default: "field" },
|
|
66
|
+
iconOnly: {
|
|
67
|
+
type: Boolean,
|
|
68
|
+
default: !1
|
|
69
|
+
},
|
|
70
|
+
width: { default: "full" },
|
|
71
|
+
disabled: {
|
|
72
|
+
type: Boolean,
|
|
73
|
+
default: !1
|
|
74
|
+
},
|
|
75
|
+
loading: {
|
|
76
|
+
type: Boolean,
|
|
77
|
+
default: !1
|
|
78
|
+
},
|
|
79
|
+
invalid: {
|
|
80
|
+
type: Boolean,
|
|
81
|
+
default: !1
|
|
82
|
+
},
|
|
83
|
+
placeholder: { default: "" },
|
|
84
|
+
flagBaseUrl: { default: void 0 },
|
|
85
|
+
emptyText: { default: "No languages available." }
|
|
86
|
+
},
|
|
87
|
+
emits: [
|
|
88
|
+
"update:modelValue",
|
|
89
|
+
"update:open",
|
|
90
|
+
"open-change"
|
|
91
|
+
],
|
|
92
|
+
setup(f, { emit: A }) {
|
|
93
|
+
let j = f, M = A, N = C(), P = E("t-language-select"), F = v(null), I = v(null), L = v(null), R = v(/* @__PURE__ */ new Map()), z = v(-1), B = v(!1), V = o(() => {
|
|
94
|
+
let { class: e, style: t, ...n } = N;
|
|
95
|
+
return n;
|
|
96
|
+
}), { value: H, setValue: U } = t(ne(j, "open"), j.defaultOpen, (e) => {
|
|
97
|
+
M("update:open", e), M("open-change", e);
|
|
98
|
+
}), W = o(() => j.variant === "switcher"), me = o(() => [
|
|
99
|
+
"t-language-select",
|
|
100
|
+
`t-language-select--${j.size}`,
|
|
101
|
+
`t-language-select--${j.variant}`,
|
|
102
|
+
!W.value && j.width !== "full" ? `t-field-width--${j.width}` : null,
|
|
103
|
+
{
|
|
104
|
+
"t-language-select--icon-only": W.value && j.iconOnly,
|
|
105
|
+
"t-language-select--drop-up": B.value,
|
|
106
|
+
"is-disabled": j.disabled,
|
|
107
|
+
"is-invalid": j.invalid,
|
|
108
|
+
"is-loading": j.loading,
|
|
109
|
+
"is-open": H.value
|
|
110
|
+
},
|
|
111
|
+
N.class
|
|
112
|
+
]), he = (e) => {
|
|
113
|
+
let t = e.parentElement;
|
|
114
|
+
for (; t && t !== document.body;) {
|
|
115
|
+
let { overflowY: e } = window.getComputedStyle(t);
|
|
116
|
+
if (e === "auto" || e === "scroll" || e === "hidden") return t;
|
|
117
|
+
t = t.parentElement;
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}, ge = () => {
|
|
121
|
+
let e = I.value, t = L.value;
|
|
122
|
+
if (!e || !t) {
|
|
123
|
+
B.value = !1;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
let n = e.getBoundingClientRect(), r = t.getBoundingClientRect(), i = he(e)?.getBoundingClientRect(), a = Math.min(i?.bottom ?? Infinity, window.innerHeight), o = Math.max(i?.top ?? 0, 0), s = a - n.bottom, c = n.top - o;
|
|
127
|
+
B.value = r.bottom > a && c > s;
|
|
128
|
+
}, _e = o(() => N.style), G = o(() => j.options.find((e) => e.value === j.modelValue)), ve = o(() => G.value?.label ?? ""), ye = o(() => !(W.value && j.iconOnly) || !G.value?.code), K = o(() => j.options.filter((e) => !e.disabled)), be = () => {
|
|
129
|
+
let e = j.options.findIndex((e) => e.value === j.modelValue);
|
|
130
|
+
z.value = e >= 0 ? e : 0, B.value = !1, m(() => {
|
|
131
|
+
ge(), Z(z.value);
|
|
132
|
+
});
|
|
133
|
+
}, q = () => {
|
|
134
|
+
j.disabled || U(!0);
|
|
135
|
+
}, J = (e = !1) => {
|
|
136
|
+
U(!1), z.value = -1, e && m(() => I.value?.focus());
|
|
137
|
+
}, Y = () => {
|
|
138
|
+
H.value ? J() : q();
|
|
139
|
+
}, X = (e) => {
|
|
140
|
+
e.disabled || (M("update:modelValue", e.value), J(!0));
|
|
141
|
+
}, Z = (e) => {
|
|
142
|
+
let t = j.options[e];
|
|
143
|
+
t && R.value.get(t.value)?.focus();
|
|
144
|
+
}, xe = (e, t) => {
|
|
145
|
+
e instanceof HTMLElement ? R.value.set(t, e) : R.value.delete(t);
|
|
146
|
+
}, Q = (e) => {
|
|
147
|
+
let t = z.value + e;
|
|
148
|
+
for (; t >= 0 && t < j.options.length;) {
|
|
149
|
+
if (!j.options[t].disabled) {
|
|
150
|
+
z.value = t, Z(t);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
t += e;
|
|
154
|
+
}
|
|
155
|
+
}, Se = (e) => {
|
|
156
|
+
if (!j.disabled) {
|
|
157
|
+
if (O(e) && H.value) {
|
|
158
|
+
e.preventDefault(), J();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
(D(e) || e.key === "ArrowDown" || e.key === "ArrowUp") && (e.preventDefault(), q());
|
|
162
|
+
}
|
|
163
|
+
}, Ce = (e, t, n) => {
|
|
164
|
+
if (O(e)) {
|
|
165
|
+
e.preventDefault(), J(!0);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (D(e)) {
|
|
169
|
+
e.preventDefault(), X(t);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
switch (e.key) {
|
|
173
|
+
case "ArrowDown":
|
|
174
|
+
e.preventDefault(), Q(1);
|
|
175
|
+
break;
|
|
176
|
+
case "ArrowUp":
|
|
177
|
+
e.preventDefault(), Q(-1);
|
|
178
|
+
break;
|
|
179
|
+
case "Home":
|
|
180
|
+
e.preventDefault(), z.value = K.value.length > 0 ? j.options.indexOf(K.value[0]) : 0, Z(z.value);
|
|
181
|
+
break;
|
|
182
|
+
case "End":
|
|
183
|
+
e.preventDefault(), z.value = K.value.length > 0 ? j.options.indexOf(K.value[K.value.length - 1]) : j.options.length - 1, Z(z.value);
|
|
184
|
+
break;
|
|
185
|
+
default: break;
|
|
186
|
+
}
|
|
187
|
+
}, $ = (e) => {
|
|
188
|
+
if (!H.value) return;
|
|
189
|
+
let t = e.target;
|
|
190
|
+
t instanceof Node && (F.value?.contains(t) || J());
|
|
191
|
+
}, we = o(() => j.modelValue !== "");
|
|
192
|
+
return w(H, (e) => {
|
|
193
|
+
e ? (document.addEventListener("pointerdown", $), be()) : document.removeEventListener("pointerdown", $);
|
|
194
|
+
}, { immediate: !0 }), w(() => j.options.length, (e) => {
|
|
195
|
+
H.value && z.value >= e && (z.value = e - 1);
|
|
196
|
+
}), g(() => {
|
|
197
|
+
document.removeEventListener("pointerdown", $);
|
|
198
|
+
}), (t, o) => (_(), l("div", {
|
|
199
|
+
ref_key: "rootRef",
|
|
200
|
+
ref: F,
|
|
201
|
+
class: h(me.value),
|
|
202
|
+
style: te(_e.value),
|
|
203
|
+
"data-state": S(H) ? "open" : "closed"
|
|
204
|
+
}, [u("button", p({
|
|
205
|
+
ref_key: "triggerRef",
|
|
206
|
+
ref: I
|
|
207
|
+
}, V.value, {
|
|
208
|
+
type: "button",
|
|
209
|
+
class: "t-language-select__trigger",
|
|
210
|
+
disabled: f.disabled,
|
|
211
|
+
"aria-controls": S(H) ? S(P) : void 0,
|
|
212
|
+
"aria-haspopup": "listbox",
|
|
213
|
+
"aria-expanded": S(H),
|
|
214
|
+
"aria-invalid": f.invalid || void 0,
|
|
215
|
+
"aria-busy": f.loading || void 0,
|
|
216
|
+
onClick: Y,
|
|
217
|
+
onKeydown: Se
|
|
218
|
+
}), [
|
|
219
|
+
t.$slots.prefix ? (_(), l("span", ie, [b(t.$slots, "prefix")])) : c("", !0),
|
|
220
|
+
W.value ? (_(), s(r, {
|
|
221
|
+
key: 1,
|
|
222
|
+
name: "languages",
|
|
223
|
+
class: "t-language-select__translate"
|
|
224
|
+
})) : G.value?.code ? (_(), s(n, {
|
|
225
|
+
key: 2,
|
|
226
|
+
code: G.value.code,
|
|
227
|
+
"base-url": f.flagBaseUrl,
|
|
228
|
+
size: f.size
|
|
229
|
+
}, null, 8, [
|
|
230
|
+
"code",
|
|
231
|
+
"base-url",
|
|
232
|
+
"size"
|
|
233
|
+
])) : c("", !0),
|
|
234
|
+
ye.value ? (_(), l("span", {
|
|
235
|
+
key: 3,
|
|
236
|
+
class: "t-language-select__value",
|
|
237
|
+
"data-placeholder": !we.value || void 0
|
|
238
|
+
}, x(ve.value || f.placeholder), 9, ae)) : c("", !0),
|
|
239
|
+
W.value && G.value?.code ? (_(), s(n, {
|
|
240
|
+
key: 4,
|
|
241
|
+
code: G.value.code,
|
|
242
|
+
"base-url": f.flagBaseUrl,
|
|
243
|
+
size: f.size
|
|
244
|
+
}, null, 8, [
|
|
245
|
+
"code",
|
|
246
|
+
"base-url",
|
|
247
|
+
"size"
|
|
248
|
+
])) : c("", !0),
|
|
249
|
+
f.loading ? (_(), s(e, {
|
|
250
|
+
key: 5,
|
|
251
|
+
size: "sm",
|
|
252
|
+
label: "Loading"
|
|
253
|
+
})) : (_(), l("svg", oe, [...o[0] ||= [u("polyline", { points: "4 6 8 10 12 6" }, null, -1)]]))
|
|
254
|
+
], 16, re), d(a, { name: "t-fade" }, {
|
|
255
|
+
default: T(() => [S(H) && !f.disabled ? (_(), l("ul", {
|
|
256
|
+
key: 0,
|
|
257
|
+
id: S(P),
|
|
258
|
+
ref_key: "listboxRef",
|
|
259
|
+
ref: L,
|
|
260
|
+
role: "listbox",
|
|
261
|
+
class: "t-language-select__listbox",
|
|
262
|
+
"aria-label": typeof V.value["aria-label"] == "string" ? V.value["aria-label"] : void 0
|
|
263
|
+
}, [f.options.length === 0 ? (_(), l("li", ce, [b(t.$slots, "empty", {}, () => [ee(x(f.emptyText), 1)])])) : c("", !0), (_(!0), l(i, null, y(f.options, (e, r) => (_(), l("li", {
|
|
264
|
+
key: e.value,
|
|
265
|
+
ref_for: !0,
|
|
266
|
+
ref: (t) => xe(t, e.value),
|
|
267
|
+
role: "option",
|
|
268
|
+
class: h(["t-language-select__option", {
|
|
269
|
+
"is-selected": e.value === f.modelValue,
|
|
270
|
+
"is-disabled": e.disabled,
|
|
271
|
+
"is-focused": r === z.value
|
|
272
|
+
}]),
|
|
273
|
+
"aria-selected": e.value === f.modelValue,
|
|
274
|
+
"aria-disabled": e.disabled || void 0,
|
|
275
|
+
tabindex: e.disabled ? -1 : 0,
|
|
276
|
+
onClick: (t) => X(e),
|
|
277
|
+
onKeydown: (t) => Ce(t, e, r)
|
|
278
|
+
}, [b(t.$slots, "option", {
|
|
279
|
+
option: e,
|
|
280
|
+
selected: e.value === f.modelValue,
|
|
281
|
+
focused: r === z.value
|
|
282
|
+
}, () => [e.code ? (_(), s(n, {
|
|
283
|
+
key: 0,
|
|
284
|
+
code: e.code,
|
|
285
|
+
"base-url": f.flagBaseUrl,
|
|
286
|
+
size: f.size
|
|
287
|
+
}, null, 8, [
|
|
288
|
+
"code",
|
|
289
|
+
"base-url",
|
|
290
|
+
"size"
|
|
291
|
+
])) : c("", !0), u("span", ue, [u("span", de, x(e.label), 1), e.description ? (_(), l("span", fe, x(e.description), 1)) : c("", !0)])]), e.value === f.modelValue ? (_(), l("svg", pe, [...o[1] ||= [u("polyline", { points: "3.5 8.5 6.5 11.5 12.5 4.5" }, null, -1)]])) : c("", !0)], 42, le))), 128))], 8, se)) : c("", !0)]),
|
|
292
|
+
_: 3
|
|
293
|
+
})], 14, k));
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
//#endregion
|
|
297
|
+
export { A as default };
|
|
298
|
+
|
|
299
|
+
//# sourceMappingURL=TLanguageSelect.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TLanguageSelect.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../src/components/TLanguageSelect.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TFieldWidth, TSize } from '../types/contracts';\nimport TFlag from './TFlag.vue';\nimport TIcon from './TIcon.vue';\nimport TSpinner from './TSpinner.vue';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\n/**\n * `field` is a form control: it reads as the value of a labelled question, so the\n * flag leads and the trigger fills its container.\n *\n * `switcher` is a page-level control, typically in a navbar, where nothing nearby\n * says what it changes. The translate icon states the purpose up front and the\n * current flag closes the row, so the whole thing reads as \"page language, now\n * set to this\" without an external label.\n */\nexport type TLanguageSelectVariant = 'field' | 'switcher';\n\nexport interface TLanguageOption {\n label: string;\n /** Opaque application key — typically a BCP-47 tag. Never parsed or validated. */\n value: string;\n /** ISO 3166-1 alpha-2 code for the flag. Omit to render the option without one. */\n code?: string;\n /** Secondary line, e.g. the language's endonym. */\n description?: string;\n disabled?: boolean;\n}\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string;\n options?: TLanguageOption[];\n open?: boolean;\n defaultOpen?: boolean;\n size?: TSize;\n variant?: TLanguageSelectVariant;\n /** Hide the language name, leaving icon + flag. `switcher` only. */\n iconOnly?: boolean;\n /** Inline-size cap. Fluid (`full`) by default. */\n width?: TFieldWidth;\n disabled?: boolean;\n loading?: boolean;\n invalid?: boolean;\n placeholder?: string;\n /** Forwarded to every nested TFlag. Set once here to self-host flag assets. */\n flagBaseUrl?: string;\n emptyText?: string;\n }>(),\n {\n modelValue: '',\n options: () => [],\n open: undefined,\n defaultOpen: false,\n size: 'md',\n variant: 'field',\n iconOnly: false,\n width: 'full',\n disabled: false,\n loading: false,\n invalid: false,\n placeholder: '',\n flagBaseUrl: undefined,\n emptyText: 'No languages available.',\n },\n);\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n prefix?: () => unknown;\n option?: (props: { option: TLanguageOption; selected: boolean; focused: boolean }) => unknown;\n empty?: () => unknown;\n}>();\n\nconst attrs = useAttrs();\nconst listboxId = createId('t-language-select');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLButtonElement | null>(null);\nconst listboxRef = ref<HTMLElement | null>(null);\nconst optionRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\nconst dropUp = ref(false);\n\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs;\n return rest;\n});\n\nconst { value: isOpen, setValue } = useControllableOpen(\n toRef(props, 'open'),\n props.defaultOpen,\n (value) => {\n emit('update:open', value);\n emit('open-change', value);\n },\n);\n\nconst isSwitcher = computed(() => props.variant === 'switcher');\n\nconst rootClasses = computed(() => [\n 't-language-select',\n `t-language-select--${props.size}`,\n `t-language-select--${props.variant}`,\n // A switcher sizes to its content, so the field width scale does not apply.\n !isSwitcher.value && props.width !== 'full' ? `t-field-width--${props.width}` : null,\n {\n 't-language-select--icon-only': isSwitcher.value && props.iconOnly,\n 't-language-select--drop-up': dropUp.value,\n 'is-disabled': props.disabled,\n 'is-invalid': props.invalid,\n 'is-loading': props.loading,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\n// Nearest ancestor that can clip the listbox (scroll container or hidden overflow).\nconst findClippingAncestor = (element: HTMLElement): HTMLElement | null => {\n let parent = element.parentElement;\n while (parent && parent !== document.body) {\n const { overflowY } = window.getComputedStyle(parent);\n if (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'hidden') {\n return parent;\n }\n parent = parent.parentElement;\n }\n return null;\n};\n\n// Flip the listbox above the trigger when its rendered position overflows the\n// nearest clipping ancestor (e.g. a modal body) or the viewport, and there is\n// more room above the trigger than below it. Measuring the rendered rect keeps\n// the decision in sync with the CSS offset (--tree-space-2) automatically.\nconst updateDropDirection = () => {\n const trigger = triggerRef.value;\n const listbox = listboxRef.value;\n if (!trigger || !listbox) {\n dropUp.value = false;\n return;\n }\n const triggerRect = trigger.getBoundingClientRect();\n const listboxRect = listbox.getBoundingClientRect();\n const boundary = findClippingAncestor(trigger)?.getBoundingClientRect();\n const bottomLimit = Math.min(boundary?.bottom ?? Infinity, window.innerHeight);\n const topLimit = Math.max(boundary?.top ?? 0, 0);\n const spaceBelow = bottomLimit - triggerRect.bottom;\n const spaceAbove = triggerRect.top - topLimit;\n dropUp.value = listboxRect.bottom > bottomLimit && spaceAbove > spaceBelow;\n};\n\nconst rootStyle = computed(() => attrs.style);\n\nconst selectedOption = computed(() =>\n props.options.find((o) => o.value === props.modelValue),\n);\n\nconst selectedLabel = computed(() => selectedOption.value?.label ?? '');\n\n// iconOnly leans on the flag to carry the current value. With no flag to show it\n// would leave the trigger stating nothing at all, so the name comes back.\nconst showValue = computed(\n () => !(isSwitcher.value && props.iconOnly) || !selectedOption.value?.code,\n);\n\nconst enabledOptions = computed(() =>\n props.options.filter((o) => !o.disabled),\n);\n\n// Runs for every open, however it was triggered. The listbox can also be opened\n// through `open` / `defaultOpen` without going near openDropdown(), so this lives\n// on the isOpen watcher rather than inside the click handler.\nconst onOpened = () => {\n const selectedIdx = props.options.findIndex((o) => o.value === props.modelValue);\n focusedIndex.value = selectedIdx >= 0 ? selectedIdx : 0;\n // Render downward first so the measurement always starts from the default position.\n dropUp.value = false;\n nextTick(() => {\n updateDropDirection();\n focusOption(focusedIndex.value);\n });\n};\n\nconst openDropdown = () => {\n if (props.disabled) return;\n setValue(true);\n};\n\nconst closeDropdown = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => triggerRef.value?.focus());\n }\n};\n\nconst toggleDropdown = () => {\n if (isOpen.value) {\n closeDropdown();\n } else {\n openDropdown();\n }\n};\n\nconst selectOption = (opt: TLanguageOption) => {\n if (opt.disabled) return;\n emit('update:modelValue', opt.value);\n closeDropdown(true);\n};\n\nconst focusOption = (index: number) => {\n const opt = props.options[index];\n if (!opt) return;\n const el = optionRefs.value.get(opt.value);\n el?.focus();\n};\n\nconst setOptionRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n optionRefs.value.set(value, el);\n } else {\n optionRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.options.length) {\n if (!props.options[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusOption(nextIndex);\n return;\n }\n nextIndex += direction;\n }\n};\n\nconst onTriggerKeydown = (event: KeyboardEvent) => {\n if (props.disabled) return;\n\n if (isEscapeKey(event) && isOpen.value) {\n event.preventDefault();\n closeDropdown();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openDropdown();\n }\n};\n\nconst onOptionKeydown = (event: KeyboardEvent, opt: TLanguageOption, _index: number) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeDropdown(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectOption(opt);\n return;\n }\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n moveFocus(1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n moveFocus(-1);\n break;\n case 'Home':\n event.preventDefault();\n focusedIndex.value = enabledOptions.value.length > 0\n ? props.options.indexOf(enabledOptions.value[0])\n : 0;\n focusOption(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledOptions.value.length > 0\n ? props.options.indexOf(enabledOptions.value[enabledOptions.value.length - 1])\n : props.options.length - 1;\n focusOption(focusedIndex.value);\n break;\n default:\n break;\n }\n};\n\nconst onDocumentPointerDown = (event: PointerEvent) => {\n if (!isOpen.value) return;\n const target = event.target;\n if (!(target instanceof Node)) return;\n if (rootRef.value?.contains(target)) return;\n closeDropdown();\n};\n\nconst hasSelection = computed(() => props.modelValue !== '');\n\n// immediate, so a listbox that is already open on mount (`defaultOpen`, or a\n// controlled `open` that starts true) still dismisses on outside click and still\n// measures its drop direction.\nwatch(isOpen, (value) => {\n if (value) {\n document.addEventListener('pointerdown', onDocumentPointerDown);\n onOpened();\n } else {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n }\n}, { immediate: true });\n\n// Options can shrink underneath an open listbox. Leaving focusedIndex past the\n// end would strand moveFocus(), which only ever walks outward from it.\nwatch(\n () => props.options.length,\n (length) => {\n if (isOpen.value && focusedIndex.value >= length) {\n focusedIndex.value = length - 1;\n }\n },\n);\n\nonBeforeUnmount(() => {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n});\n</script>\n\n<template>\n <div\n ref=\"rootRef\"\n :class=\"rootClasses\"\n :style=\"rootStyle\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n >\n <button\n ref=\"triggerRef\"\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-language-select__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? listboxId : undefined\"\n aria-haspopup=\"listbox\"\n :aria-expanded=\"isOpen\"\n :aria-invalid=\"invalid || undefined\"\n :aria-busy=\"loading || undefined\"\n @click=\"toggleDropdown\"\n @keydown=\"onTriggerKeydown\"\n >\n <span\n v-if=\"$slots.prefix\"\n class=\"t-language-select__slot t-language-select__slot--prefix\"\n >\n <slot name=\"prefix\" />\n </span>\n <!--\n The switcher leads with the translate icon so the control announces what\n it changes; the field leads with the flag, since a form label already\n does that job.\n -->\n <!-- Sized in CSS from the icon token scale, not TIcon's pixel `size` prop. -->\n <TIcon\n v-if=\"isSwitcher\"\n name=\"languages\"\n class=\"t-language-select__translate\"\n />\n <TFlag\n v-else-if=\"selectedOption?.code\"\n :code=\"selectedOption.code\"\n :base-url=\"flagBaseUrl\"\n :size=\"size\"\n />\n <span\n v-if=\"showValue\"\n class=\"t-language-select__value\"\n :data-placeholder=\"!hasSelection ? true : undefined\"\n >\n {{ selectedLabel || placeholder }}\n </span>\n <TFlag\n v-if=\"isSwitcher && selectedOption?.code\"\n :code=\"selectedOption.code\"\n :base-url=\"flagBaseUrl\"\n :size=\"size\"\n />\n <TSpinner\n v-if=\"loading\"\n size=\"sm\"\n label=\"Loading\"\n />\n <svg\n v-else\n class=\"t-language-select__chevron\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"4 6 8 10 12 6\" />\n </svg>\n </button>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"listboxId\"\n ref=\"listboxRef\"\n role=\"listbox\"\n class=\"t-language-select__listbox\"\n :aria-label=\"typeof triggerAttrs['aria-label'] === 'string' ? triggerAttrs['aria-label'] : undefined\"\n >\n <li\n v-if=\"options.length === 0\"\n class=\"t-language-select__empty\"\n role=\"presentation\"\n >\n <slot name=\"empty\">\n {{ emptyText }}\n </slot>\n </li>\n <li\n v-for=\"(opt, index) in options\"\n :key=\"opt.value\"\n :ref=\"(el) => setOptionRef(el as Element | null, opt.value)\"\n role=\"option\"\n class=\"t-language-select__option\"\n :class=\"{\n 'is-selected': opt.value === modelValue,\n 'is-disabled': opt.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-selected=\"opt.value === modelValue\"\n :aria-disabled=\"opt.disabled || undefined\"\n :tabindex=\"opt.disabled ? -1 : 0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt, index)\"\n >\n <slot\n name=\"option\"\n :option=\"opt\"\n :selected=\"opt.value === modelValue\"\n :focused=\"index === focusedIndex\"\n >\n <TFlag\n v-if=\"opt.code\"\n :code=\"opt.code\"\n :base-url=\"flagBaseUrl\"\n :size=\"size\"\n />\n <span class=\"t-language-select__option-text\">\n <span class=\"t-language-select__option-label\">{{ opt.label }}</span>\n <span\n v-if=\"opt.description\"\n class=\"t-language-select__description\"\n >\n {{ opt.description }}\n </span>\n </span>\n </slot>\n <svg\n v-if=\"opt.value === modelValue\"\n class=\"t-language-select__check\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"3.5 8.5 6.5 11.5 12.5 4.5\" />\n </svg>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TPopover.cjs","names":[],"sources":["../../src/components/TPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { createId, focusFirst, isEscapeKey } from '@treeui/utils';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TTooltipSide } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst props = withDefaults(\n defineProps<{\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n side?: TTooltipSide;\n align?: 'start' | 'center' | 'end';\n id?: string;\n }>(),\n {\n open: undefined,\n defaultOpen: false,\n disabled: false,\n side: 'bottom',\n align: 'center',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean }): unknown;\n default(): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst contentId = props.id ?? createId('t-popover');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<
|
|
1
|
+
{"version":3,"file":"TPopover.cjs","names":[],"sources":["../../src/components/TPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { createId, focusFirst, isEscapeKey } from '@treeui/utils';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TTooltipSide } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst props = withDefaults(\n defineProps<{\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n side?: TTooltipSide;\n align?: 'start' | 'center' | 'end';\n id?: string;\n }>(),\n {\n open: undefined,\n defaultOpen: false,\n disabled: false,\n side: 'bottom',\n align: 'center',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean; contentId: string }): unknown;\n default(): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst contentId = props.id ?? createId('t-popover');\nconst rootRef = ref<HTMLElement | null>(null);\n// Bound to the anchor wrapper, not the fallback button: the fallback does not\n// render when a consumer supplies a `trigger` slot, so a ref on it would be\n// null exactly when focus restoration matters most. focusFirst() resolves the\n// real trigger either way. Mirrors TDropdown's trigger-wrapper ref.\nconst triggerRef = ref<HTMLElement | null>(null);\nconst contentRef = ref<HTMLElement | null>(null);\n\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs;\n return rest;\n});\n\nconst { value: isOpen, setValue } = useControllableOpen(\n toRef(props, 'open'),\n props.defaultOpen,\n (value) => {\n emit('update:open', value);\n emit('open-change', value);\n },\n);\n\nconst rootClasses = computed(() => [\n 't-popover',\n {\n 'is-open': isOpen.value,\n 'is-disabled': props.disabled,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst contentClasses = computed(() => [\n 't-popover__content',\n `t-popover__content--${props.side}`,\n `t-popover__content--align-${props.align}`,\n]);\n\nconst openPopover = () => {\n if (props.disabled) return;\n setValue(true);\n nextTick(() => {\n if (contentRef.value) {\n if (!focusFirst(contentRef.value)) {\n contentRef.value.focus();\n }\n }\n });\n};\n\nconst closePopover = (restoreFocus = false) => {\n setValue(false);\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst togglePopover = () => {\n if (isOpen.value) {\n closePopover();\n } else {\n openPopover();\n }\n};\n\nconst onTriggerKeydown = (event: KeyboardEvent) => {\n if (props.disabled) return;\n\n if (isEscapeKey(event) && isOpen.value) {\n event.preventDefault();\n closePopover();\n }\n};\n\nconst onContentKeydown = (event: KeyboardEvent) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closePopover(true);\n }\n};\n\nconst onDocumentPointerDown = (event: PointerEvent) => {\n if (!isOpen.value) return;\n const target = event.target;\n if (!(target instanceof Node)) return;\n if (rootRef.value?.contains(target)) return;\n closePopover();\n};\n\nwatch(isOpen, (value) => {\n if (value) {\n document.addEventListener('pointerdown', onDocumentPointerDown);\n } else {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n }\n});\n\nonBeforeUnmount(() => {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n});\n</script>\n\n<template>\n <div\n ref=\"rootRef\"\n :class=\"rootClasses\"\n :style=\"rootStyle\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n >\n <div\n ref=\"triggerRef\"\n class=\"t-popover__anchor\"\n @click=\"togglePopover\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n :content-id=\"contentId\"\n >\n <button\n type=\"button\"\n class=\"t-popover__trigger\"\n :disabled=\"disabled\"\n :aria-expanded=\"isOpen\"\n :aria-controls=\"isOpen ? contentId : undefined\"\n aria-haspopup=\"dialog\"\n v-bind=\"triggerAttrs\"\n />\n </slot>\n </div>\n <transition name=\"t-popover-fade\">\n <div\n v-if=\"isOpen && !disabled\"\n :id=\"contentId\"\n ref=\"contentRef\"\n role=\"dialog\"\n :class=\"contentClasses\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n tabindex=\"-1\"\n @keydown=\"onContentKeydown\"\n >\n <slot />\n </div>\n </transition>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TPopover.js","names":[],"sources":["../../src/components/TPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { createId, focusFirst, isEscapeKey } from '@treeui/utils';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TTooltipSide } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst props = withDefaults(\n defineProps<{\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n side?: TTooltipSide;\n align?: 'start' | 'center' | 'end';\n id?: string;\n }>(),\n {\n open: undefined,\n defaultOpen: false,\n disabled: false,\n side: 'bottom',\n align: 'center',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean }): unknown;\n default(): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst contentId = props.id ?? createId('t-popover');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<
|
|
1
|
+
{"version":3,"file":"TPopover.js","names":[],"sources":["../../src/components/TPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { createId, focusFirst, isEscapeKey } from '@treeui/utils';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TTooltipSide } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst props = withDefaults(\n defineProps<{\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n side?: TTooltipSide;\n align?: 'start' | 'center' | 'end';\n id?: string;\n }>(),\n {\n open: undefined,\n defaultOpen: false,\n disabled: false,\n side: 'bottom',\n align: 'center',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean; contentId: string }): unknown;\n default(): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst contentId = props.id ?? createId('t-popover');\nconst rootRef = ref<HTMLElement | null>(null);\n// Bound to the anchor wrapper, not the fallback button: the fallback does not\n// render when a consumer supplies a `trigger` slot, so a ref on it would be\n// null exactly when focus restoration matters most. focusFirst() resolves the\n// real trigger either way. Mirrors TDropdown's trigger-wrapper ref.\nconst triggerRef = ref<HTMLElement | null>(null);\nconst contentRef = ref<HTMLElement | null>(null);\n\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs;\n return rest;\n});\n\nconst { value: isOpen, setValue } = useControllableOpen(\n toRef(props, 'open'),\n props.defaultOpen,\n (value) => {\n emit('update:open', value);\n emit('open-change', value);\n },\n);\n\nconst rootClasses = computed(() => [\n 't-popover',\n {\n 'is-open': isOpen.value,\n 'is-disabled': props.disabled,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst contentClasses = computed(() => [\n 't-popover__content',\n `t-popover__content--${props.side}`,\n `t-popover__content--align-${props.align}`,\n]);\n\nconst openPopover = () => {\n if (props.disabled) return;\n setValue(true);\n nextTick(() => {\n if (contentRef.value) {\n if (!focusFirst(contentRef.value)) {\n contentRef.value.focus();\n }\n }\n });\n};\n\nconst closePopover = (restoreFocus = false) => {\n setValue(false);\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst togglePopover = () => {\n if (isOpen.value) {\n closePopover();\n } else {\n openPopover();\n }\n};\n\nconst onTriggerKeydown = (event: KeyboardEvent) => {\n if (props.disabled) return;\n\n if (isEscapeKey(event) && isOpen.value) {\n event.preventDefault();\n closePopover();\n }\n};\n\nconst onContentKeydown = (event: KeyboardEvent) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closePopover(true);\n }\n};\n\nconst onDocumentPointerDown = (event: PointerEvent) => {\n if (!isOpen.value) return;\n const target = event.target;\n if (!(target instanceof Node)) return;\n if (rootRef.value?.contains(target)) return;\n closePopover();\n};\n\nwatch(isOpen, (value) => {\n if (value) {\n document.addEventListener('pointerdown', onDocumentPointerDown);\n } else {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n }\n});\n\nonBeforeUnmount(() => {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n});\n</script>\n\n<template>\n <div\n ref=\"rootRef\"\n :class=\"rootClasses\"\n :style=\"rootStyle\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n >\n <div\n ref=\"triggerRef\"\n class=\"t-popover__anchor\"\n @click=\"togglePopover\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n :content-id=\"contentId\"\n >\n <button\n type=\"button\"\n class=\"t-popover__trigger\"\n :disabled=\"disabled\"\n :aria-expanded=\"isOpen\"\n :aria-controls=\"isOpen ? contentId : undefined\"\n aria-haspopup=\"dialog\"\n v-bind=\"triggerAttrs\"\n />\n </slot>\n </div>\n <transition name=\"t-popover-fade\">\n <div\n v-if=\"isOpen && !disabled\"\n :id=\"contentId\"\n ref=\"contentRef\"\n role=\"dialog\"\n :class=\"contentClasses\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n tabindex=\"-1\"\n @keydown=\"onContentKeydown\"\n >\n <slot />\n </div>\n </transition>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -12,17 +12,19 @@ declare function __VLS_template(): {
|
|
|
12
12
|
slots: Readonly<{
|
|
13
13
|
trigger(props: {
|
|
14
14
|
isOpen: boolean;
|
|
15
|
+
contentId: string;
|
|
15
16
|
}): unknown;
|
|
16
17
|
default(): unknown;
|
|
17
18
|
}> & {
|
|
18
19
|
trigger(props: {
|
|
19
20
|
isOpen: boolean;
|
|
21
|
+
contentId: string;
|
|
20
22
|
}): unknown;
|
|
21
23
|
default(): unknown;
|
|
22
24
|
};
|
|
23
25
|
refs: {
|
|
24
26
|
rootRef: HTMLDivElement;
|
|
25
|
-
triggerRef:
|
|
27
|
+
triggerRef: HTMLDivElement;
|
|
26
28
|
contentRef: HTMLDivElement;
|
|
27
29
|
};
|
|
28
30
|
rootEl: any;
|
|
@@ -43,7 +45,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}
|
|
|
43
45
|
side: TTooltipSide;
|
|
44
46
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
45
47
|
rootRef: HTMLDivElement;
|
|
46
|
-
triggerRef:
|
|
48
|
+
triggerRef: HTMLDivElement;
|
|
47
49
|
contentRef: HTMLDivElement;
|
|
48
50
|
}, any>;
|
|
49
51
|
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TPopover.vue.d.ts","sourceRoot":"","sources":["../../src/components/TPopover.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TPopover.vue.d.ts","sourceRoot":"","sources":["../../src/components/TPopover.vue"],"names":[],"mappings":"AAoMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMvD,KAAK,WAAW,GAAG;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AA4IJ,iBAAS,cAAc;WA0ET,OAAO,IAA6B;;uBAlMjC;YAAE,MAAM,EAAE,OAAO,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO;mBACpD,OAAO;;uBADH;YAAE,MAAM,EAAE,OAAO,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO;mBACpD,OAAO;;;;;;;;EAsMnB;AAsBD,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAC9D,QAAA,MAAM,eAAe;;;;;;;cAtPN,OAAO;QAGb,MAAM;WADH,OAAO,GAAG,QAAQ,GAAG,KAAK;UAJ3B,OAAO;iBACA,OAAO;UAEd,YAAY;;;;;OA8PrB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAAnG,wBAAoG;AAapG,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../composables/useControllableOpen.cjs");let t=require("vue"),n=require("@treeui/utils");var r=[`data-state`],i=[`disabled`,`aria-expanded`,`aria-controls`],a=[`id`,`data-state`],o=(0,t.defineComponent)({inheritAttrs:!1,__name:`TPopover`,props:{open:{type:Boolean,default:void 0},defaultOpen:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},side:{default:`bottom`},align:{default:`center`},id:{default:void 0}},emits:[`update:open`,`open-change`],setup(o,{emit:s}){let c=o,l=s,u=(0,t.useAttrs)(),d=c.id??(0,n.createId)(`t-popover`),f=(0,t.ref)(null),p=(0,t.ref)(null),m=(0,t.ref)(null),h=(0,t.computed)(()=>{let{class:e,style:t,...n}=u;return n}),{value:g,setValue:_}=e.useControllableOpen((0,t.toRef)(c,`open`),c.defaultOpen,e=>{l(`update:open`,e),l(`open-change`,e)}),v=(0,t.computed)(()=>[`t-popover`,{"is-open":g.value,"is-disabled":c.disabled},u.class]),y=(0,t.computed)(()=>u.style),b=(0,t.computed)(()=>[`t-popover__content`,`t-popover__content--${c.side}`,`t-popover__content--align-${c.align}`]),x=()=>{c.disabled||(_(!0),(0,t.nextTick)(()=>{m.value&&((0,n.focusFirst)(m.value)||m.value.focus())}))},S=(e=!1)=>{_(!1),e&&(0,t.nextTick)(()=>p.value
|
|
1
|
+
const e=require("../composables/useControllableOpen.cjs");let t=require("vue"),n=require("@treeui/utils");var r=[`data-state`],i=[`disabled`,`aria-expanded`,`aria-controls`],a=[`id`,`data-state`],o=(0,t.defineComponent)({inheritAttrs:!1,__name:`TPopover`,props:{open:{type:Boolean,default:void 0},defaultOpen:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},side:{default:`bottom`},align:{default:`center`},id:{default:void 0}},emits:[`update:open`,`open-change`],setup(o,{emit:s}){let c=o,l=s,u=(0,t.useAttrs)(),d=c.id??(0,n.createId)(`t-popover`),f=(0,t.ref)(null),p=(0,t.ref)(null),m=(0,t.ref)(null),h=(0,t.computed)(()=>{let{class:e,style:t,...n}=u;return n}),{value:g,setValue:_}=e.useControllableOpen((0,t.toRef)(c,`open`),c.defaultOpen,e=>{l(`update:open`,e),l(`open-change`,e)}),v=(0,t.computed)(()=>[`t-popover`,{"is-open":g.value,"is-disabled":c.disabled},u.class]),y=(0,t.computed)(()=>u.style),b=(0,t.computed)(()=>[`t-popover__content`,`t-popover__content--${c.side}`,`t-popover__content--align-${c.align}`]),x=()=>{c.disabled||(_(!0),(0,t.nextTick)(()=>{m.value&&((0,n.focusFirst)(m.value)||m.value.focus())}))},S=(e=!1)=>{_(!1),e&&(0,t.nextTick)(()=>{p.value&&(0,n.focusFirst)(p.value)})},C=()=>{g.value?S():x()},w=e=>{c.disabled||(0,n.isEscapeKey)(e)&&g.value&&(e.preventDefault(),S())},T=e=>{(0,n.isEscapeKey)(e)&&(e.preventDefault(),S(!0))},E=e=>{if(!g.value)return;let t=e.target;t instanceof Node&&(f.value?.contains(t)||S())};return(0,t.watch)(g,e=>{e?document.addEventListener(`pointerdown`,E):document.removeEventListener(`pointerdown`,E)}),(0,t.onBeforeUnmount)(()=>{document.removeEventListener(`pointerdown`,E)}),(e,n)=>((0,t.openBlock)(),(0,t.createElementBlock)(`div`,{ref_key:`rootRef`,ref:f,class:(0,t.normalizeClass)(v.value),style:(0,t.normalizeStyle)(y.value),"data-state":(0,t.unref)(g)?`open`:`closed`},[(0,t.createElementVNode)(`div`,{ref_key:`triggerRef`,ref:p,class:`t-popover__anchor`,onClick:C,onKeydown:w},[(0,t.renderSlot)(e.$slots,`trigger`,{isOpen:(0,t.unref)(g),contentId:(0,t.unref)(d)},()=>[(0,t.createElementVNode)(`button`,(0,t.mergeProps)({type:`button`,class:`t-popover__trigger`,disabled:o.disabled,"aria-expanded":(0,t.unref)(g),"aria-controls":(0,t.unref)(g)?(0,t.unref)(d):void 0,"aria-haspopup":`dialog`},h.value),null,16,i)])],544),(0,t.createVNode)(t.Transition,{name:`t-popover-fade`},{default:(0,t.withCtx)(()=>[(0,t.unref)(g)&&!o.disabled?((0,t.openBlock)(),(0,t.createElementBlock)(`div`,{key:0,id:(0,t.unref)(d),ref_key:`contentRef`,ref:m,role:`dialog`,class:(0,t.normalizeClass)(b.value),"data-state":(0,t.unref)(g)?`open`:`closed`,tabindex:`-1`,onKeydown:T},[(0,t.renderSlot)(e.$slots,`default`)],42,a)):(0,t.createCommentVNode)(``,!0)]),_:3})],14,r))}});exports.default=o;
|
|
2
2
|
//# sourceMappingURL=TPopover.vue_vue_type_script_setup_true_lang.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TPopover.vue_vue_type_script_setup_true_lang.cjs","names":[],"sources":["../../src/components/TPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { createId, focusFirst, isEscapeKey } from '@treeui/utils';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TTooltipSide } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst props = withDefaults(\n defineProps<{\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n side?: TTooltipSide;\n align?: 'start' | 'center' | 'end';\n id?: string;\n }>(),\n {\n open: undefined,\n defaultOpen: false,\n disabled: false,\n side: 'bottom',\n align: 'center',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean }): unknown;\n default(): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst contentId = props.id ?? createId('t-popover');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<
|
|
1
|
+
{"version":3,"file":"TPopover.vue_vue_type_script_setup_true_lang.cjs","names":[],"sources":["../../src/components/TPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { createId, focusFirst, isEscapeKey } from '@treeui/utils';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TTooltipSide } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst props = withDefaults(\n defineProps<{\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n side?: TTooltipSide;\n align?: 'start' | 'center' | 'end';\n id?: string;\n }>(),\n {\n open: undefined,\n defaultOpen: false,\n disabled: false,\n side: 'bottom',\n align: 'center',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean; contentId: string }): unknown;\n default(): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst contentId = props.id ?? createId('t-popover');\nconst rootRef = ref<HTMLElement | null>(null);\n// Bound to the anchor wrapper, not the fallback button: the fallback does not\n// render when a consumer supplies a `trigger` slot, so a ref on it would be\n// null exactly when focus restoration matters most. focusFirst() resolves the\n// real trigger either way. Mirrors TDropdown's trigger-wrapper ref.\nconst triggerRef = ref<HTMLElement | null>(null);\nconst contentRef = ref<HTMLElement | null>(null);\n\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs;\n return rest;\n});\n\nconst { value: isOpen, setValue } = useControllableOpen(\n toRef(props, 'open'),\n props.defaultOpen,\n (value) => {\n emit('update:open', value);\n emit('open-change', value);\n },\n);\n\nconst rootClasses = computed(() => [\n 't-popover',\n {\n 'is-open': isOpen.value,\n 'is-disabled': props.disabled,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst contentClasses = computed(() => [\n 't-popover__content',\n `t-popover__content--${props.side}`,\n `t-popover__content--align-${props.align}`,\n]);\n\nconst openPopover = () => {\n if (props.disabled) return;\n setValue(true);\n nextTick(() => {\n if (contentRef.value) {\n if (!focusFirst(contentRef.value)) {\n contentRef.value.focus();\n }\n }\n });\n};\n\nconst closePopover = (restoreFocus = false) => {\n setValue(false);\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst togglePopover = () => {\n if (isOpen.value) {\n closePopover();\n } else {\n openPopover();\n }\n};\n\nconst onTriggerKeydown = (event: KeyboardEvent) => {\n if (props.disabled) return;\n\n if (isEscapeKey(event) && isOpen.value) {\n event.preventDefault();\n closePopover();\n }\n};\n\nconst onContentKeydown = (event: KeyboardEvent) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closePopover(true);\n }\n};\n\nconst onDocumentPointerDown = (event: PointerEvent) => {\n if (!isOpen.value) return;\n const target = event.target;\n if (!(target instanceof Node)) return;\n if (rootRef.value?.contains(target)) return;\n closePopover();\n};\n\nwatch(isOpen, (value) => {\n if (value) {\n document.addEventListener('pointerdown', onDocumentPointerDown);\n } else {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n }\n});\n\nonBeforeUnmount(() => {\n document.removeEventListener('pointerdown', onDocumentPointerDown);\n});\n</script>\n\n<template>\n <div\n ref=\"rootRef\"\n :class=\"rootClasses\"\n :style=\"rootStyle\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n >\n <div\n ref=\"triggerRef\"\n class=\"t-popover__anchor\"\n @click=\"togglePopover\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n :content-id=\"contentId\"\n >\n <button\n type=\"button\"\n class=\"t-popover__trigger\"\n :disabled=\"disabled\"\n :aria-expanded=\"isOpen\"\n :aria-controls=\"isOpen ? contentId : undefined\"\n aria-haspopup=\"dialog\"\n v-bind=\"triggerAttrs\"\n />\n </slot>\n </div>\n <transition name=\"t-popover-fade\">\n <div\n v-if=\"isOpen && !disabled\"\n :id=\"contentId\"\n ref=\"contentRef\"\n role=\"dialog\"\n :class=\"contentClasses\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n tabindex=\"-1\"\n @keydown=\"onContentKeydown\"\n >\n <slot />\n </div>\n </transition>\n </div>\n</template>\n"],"mappings":"8eAUA,IAAM,EAAQ,EAmBR,EAAO,EAUP,GAAA,EAAA,EAAA,SAAA,CAAiB,EACjB,EAAY,EAAM,KAAA,EAAA,EAAA,SAAA,CAAe,WAAW,EAC5C,GAAA,EAAA,EAAA,IAAA,CAAkC,IAAI,EAKtC,GAAA,EAAA,EAAA,IAAA,CAAqC,IAAI,EACzC,GAAA,EAAA,EAAA,IAAA,CAAqC,IAAI,EAEzC,GAAA,EAAA,EAAA,SAAA,KAA8B,CAClC,GAAM,CAAE,MAAO,EAAQ,MAAO,EAAQ,GAAG,GAAS,EAClD,OAAO,CACT,CAAC,EAEK,CAAE,MAAO,EAAQ,YAAa,EAAA,qBAAA,EAAA,EAAA,MAAA,CAC5B,EAAO,MAAM,EACnB,EAAM,YACL,GAAU,CACT,EAAK,cAAe,CAAK,EACzB,EAAK,cAAe,CAAK,CAC3B,CACF,EAEM,GAAA,EAAA,EAAA,SAAA,KAA6B,CACjC,YACA,CACE,UAAW,EAAO,MAClB,cAAe,EAAM,QACvB,EACA,EAAM,KACR,CAAC,EAEK,GAAA,EAAA,EAAA,SAAA,KAA2B,EAAM,KAAK,EAEtC,GAAA,EAAA,EAAA,SAAA,KAAgC,CACpC,qBACA,uBAAuB,EAAM,OAC7B,6BAA6B,EAAM,OACrC,CAAC,EAEK,MAAoB,CACpB,EAAM,WACV,EAAS,EAAI,GACb,EAAA,EAAA,SAAA,KAAe,CACT,EAAW,SACT,EAAA,EAAA,WAAA,CAAY,EAAW,KAAK,GAC9B,EAAW,MAAM,MAAM,EAG7B,CAAC,EACH,EAEM,GAAgB,EAAe,KAAU,CAC7C,EAAS,EAAK,EACV,IACF,EAAA,EAAA,SAAA,KAAe,CACT,EAAW,QAAO,EAAA,EAAA,WAAA,CAAW,EAAW,KAAK,CACnD,CAAC,CAEL,EAEM,MAAsB,CACtB,EAAO,MACT,EAAa,EAEb,EAAY,CAEhB,EAEM,EAAoB,GAAyB,CAC7C,EAAM,WAEV,EAAA,EAAA,YAAA,CAAgB,CAAK,GAAK,EAAO,QAC/B,EAAM,eAAe,EACrB,EAAa,EAEjB,EAEM,EAAoB,GAAyB,EACjD,EAAA,EAAA,YAAA,CAAgB,CAAK,IACnB,EAAM,eAAe,EACrB,EAAa,EAAI,EAErB,EAEM,EAAyB,GAAwB,CACrD,GAAI,CAAC,EAAO,MAAO,OACnB,IAAM,EAAS,EAAM,OACf,aAAkB,OACpB,EAAQ,OAAO,SAAS,CAAM,GAClC,EAAa,EACf,SAEA,EAAA,EAAA,MAAA,CAAM,EAAS,GAAU,CACnB,EACF,SAAS,iBAAiB,cAAe,CAAqB,EAE9D,SAAS,oBAAoB,cAAe,CAAqB,CAErE,CAAC,GAED,EAAA,EAAA,gBAAA,KAAsB,CACpB,SAAS,oBAAoB,cAAe,CAAqB,CACnE,CAAC,qDA8CO,MAAA,SAzCA,UAAJ,IAAI,EACH,OAAA,EAAA,EAAA,eAAA,CAAO,EAAA,KAAW,EAClB,OAAA,EAAA,EAAA,eAAA,CAAO,EAAA,KAAS,EAChB,cAAA,EAAA,EAAA,MAAA,CAAY,CAAA,EAAM,OAAA,oCAuBb,MAAA,SApBA,aAAJ,IAAI,EACJ,MAAM,oBACL,QAAO,EACP,UAAS,qBAgBH,EAAA,OAAA,UAAA,CAZJ,QAAA,EAAA,EAAA,MAAA,CAAS,CAAA,EACT,WAAA,EAAA,EAAA,MAAA,CAAY,CAAA,OAWR,EAAA,EAAA,EAAA,mBAAA,CADH,UAAA,EAAA,EAAA,WAAA,CAAA,CAPA,KAAK,SACL,MAAM,qBACL,SAAU,EAAA,SACV,iBAAA,EAAA,EAAA,MAAA,CAAe,CAAA,EACf,iBAAA,EAAA,EAAA,MAAA,CAAe,CAAA,GAAA,EAAA,EAAA,MAAA,CAAS,CAAA,EAAY,IAAA,GACrC,gBAAc,UACN,EAAA,KAAY,EAAA,KAAA,GAAA,CAAA,CAAA,CAAA,CAAA,EAAA,GAAA,GAAA,EAAA,EAAA,YAAA,CAiBb,EAAA,WAAA,CAbD,KAAK,gBAAgB,EAAA,2BAYzB,EAAA,EAAA,EAAA,MAAA,CAVE,CAAA,GAAM,CAAK,EAAA,WAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAUb,MAAA,OATH,IAAA,EAAA,EAAA,MAAA,CAAI,CAAA,UACD,aAAJ,IAAI,EACJ,KAAK,SACJ,OAAA,EAAA,EAAA,eAAA,CAAO,EAAA,KAAc,EACrB,cAAA,EAAA,EAAA,MAAA,CAAY,CAAA,EAAM,OAAA,SACnB,SAAS,KACR,UAAS,qBAEF,EAAA,OAAA,SAAA,CAAA,EAAA,GAAA,CAAA,IAAA,EAAA,EAAA,mBAAA,CAAA,GAAA,EAAA,CAAA,CAAA"}
|
|
@@ -49,7 +49,9 @@ var w = ["data-state"], T = [
|
|
|
49
49
|
P.value && (S(P.value) || P.value.focus());
|
|
50
50
|
}));
|
|
51
51
|
}, H = (e = !1) => {
|
|
52
|
-
L(!1), e && l(() =>
|
|
52
|
+
L(!1), e && l(() => {
|
|
53
|
+
N.value && S(N.value);
|
|
54
|
+
});
|
|
53
55
|
}, U = () => {
|
|
54
56
|
I.value ? H() : V();
|
|
55
57
|
}, W = (e) => {
|
|
@@ -72,19 +74,22 @@ var w = ["data-state"], T = [
|
|
|
72
74
|
style: d(z.value),
|
|
73
75
|
"data-state": _(I) ? "open" : "closed"
|
|
74
76
|
}, [a("div", {
|
|
77
|
+
ref_key: "triggerRef",
|
|
78
|
+
ref: N,
|
|
75
79
|
class: "t-popover__anchor",
|
|
76
80
|
onClick: U,
|
|
77
81
|
onKeydown: W
|
|
78
|
-
}, [h(e.$slots, "trigger", {
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
}, [h(e.$slots, "trigger", {
|
|
83
|
+
isOpen: _(I),
|
|
84
|
+
contentId: _(j)
|
|
85
|
+
}, () => [a("button", c({
|
|
81
86
|
type: "button",
|
|
82
87
|
class: "t-popover__trigger",
|
|
83
88
|
disabled: s.disabled,
|
|
84
89
|
"aria-expanded": _(I),
|
|
85
90
|
"aria-controls": _(I) ? _(j) : void 0,
|
|
86
91
|
"aria-haspopup": "dialog"
|
|
87
|
-
}, F.value), null, 16, T)])],
|
|
92
|
+
}, F.value), null, 16, T)])], 544), o(t, { name: "t-popover-fade" }, {
|
|
88
93
|
default: b(() => [_(I) && !s.disabled ? (p(), i("div", {
|
|
89
94
|
key: 0,
|
|
90
95
|
id: _(j),
|