@treeui/vue 0.16.0 → 0.18.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 (143) hide show
  1. package/dist/components/TAccordion.cjs.map +1 -1
  2. package/dist/components/TAccordion.js.map +1 -1
  3. package/dist/components/TAccordion.vue_vue_type_script_setup_true_lang.cjs +1 -1
  4. package/dist/components/TAccordion.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  5. package/dist/components/TAccordion.vue_vue_type_script_setup_true_lang.js +3 -3
  6. package/dist/components/TAccordion.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/components/TAccordionItem.cjs.map +1 -1
  8. package/dist/components/TAccordionItem.js.map +1 -1
  9. package/dist/components/TAccordionItem.vue_vue_type_script_setup_true_lang.cjs +1 -1
  10. package/dist/components/TAccordionItem.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  11. package/dist/components/TAccordionItem.vue_vue_type_script_setup_true_lang.js +1 -1
  12. package/dist/components/TAccordionItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/TAppShell.cjs.map +1 -1
  14. package/dist/components/TAppShell.js.map +1 -1
  15. package/dist/components/TAppShell.vue_vue_type_script_setup_true_lang.cjs +1 -1
  16. package/dist/components/TAppShell.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  17. package/dist/components/TAppShell.vue_vue_type_script_setup_true_lang.js +1 -1
  18. package/dist/components/TAppShell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/TDatePicker.cjs.map +1 -1
  20. package/dist/components/TDatePicker.js.map +1 -1
  21. package/dist/components/TDatePicker.vue_vue_type_script_setup_true_lang.cjs +1 -1
  22. package/dist/components/TDatePicker.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  23. package/dist/components/TDatePicker.vue_vue_type_script_setup_true_lang.js +1 -1
  24. package/dist/components/TDatePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  25. package/dist/components/TDateTimePicker.cjs.map +1 -1
  26. package/dist/components/TDateTimePicker.js.map +1 -1
  27. package/dist/components/TDateTimePicker.vue_vue_type_script_setup_true_lang.cjs +1 -1
  28. package/dist/components/TDateTimePicker.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  29. package/dist/components/TDateTimePicker.vue_vue_type_script_setup_true_lang.js +1 -1
  30. package/dist/components/TDateTimePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
  31. package/dist/components/TDrawer.cjs.map +1 -1
  32. package/dist/components/TDrawer.js.map +1 -1
  33. package/dist/components/TDrawer.vue_vue_type_script_setup_true_lang.cjs +1 -1
  34. package/dist/components/TDrawer.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  35. package/dist/components/TDrawer.vue_vue_type_script_setup_true_lang.js +1 -1
  36. package/dist/components/TDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  37. package/dist/components/TDropdown.cjs.map +1 -1
  38. package/dist/components/TDropdown.js.map +1 -1
  39. package/dist/components/TDropdown.vue.d.ts +4 -0
  40. package/dist/components/TDropdown.vue.d.ts.map +1 -1
  41. package/dist/components/TDropdown.vue_vue_type_script_setup_true_lang.cjs +1 -1
  42. package/dist/components/TDropdown.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  43. package/dist/components/TDropdown.vue_vue_type_script_setup_true_lang.js +22 -18
  44. package/dist/components/TDropdown.vue_vue_type_script_setup_true_lang.js.map +1 -1
  45. package/dist/components/TFlag.cjs +2 -0
  46. package/dist/components/TFlag.cjs.map +1 -0
  47. package/dist/components/TFlag.js +7 -0
  48. package/dist/components/TFlag.js.map +1 -0
  49. package/dist/components/TFlag.vue.d.ts +20 -0
  50. package/dist/components/TFlag.vue.d.ts.map +1 -0
  51. package/dist/components/TFlag.vue_vue_type_script_setup_true_lang.cjs +2 -0
  52. package/dist/components/TFlag.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  53. package/dist/components/TFlag.vue_vue_type_script_setup_true_lang.js +58 -0
  54. package/dist/components/TFlag.vue_vue_type_script_setup_true_lang.js.map +1 -0
  55. package/dist/components/TIcon.cjs.map +1 -1
  56. package/dist/components/TIcon.js.map +1 -1
  57. package/dist/components/TIcon.vue.d.ts +1 -1
  58. package/dist/components/TIcon.vue.d.ts.map +1 -1
  59. package/dist/components/TIcon.vue_vue_type_script_setup_true_lang.cjs +1 -1
  60. package/dist/components/TIcon.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  61. package/dist/components/TIcon.vue_vue_type_script_setup_true_lang.js +18 -17
  62. package/dist/components/TIcon.vue_vue_type_script_setup_true_lang.js.map +1 -1
  63. package/dist/components/TLanguageSelect.cjs +2 -0
  64. package/dist/components/TLanguageSelect.cjs.map +1 -0
  65. package/dist/components/TLanguageSelect.js +7 -0
  66. package/dist/components/TLanguageSelect.js.map +1 -0
  67. package/dist/components/TLanguageSelect.vue.d.ts +103 -0
  68. package/dist/components/TLanguageSelect.vue.d.ts.map +1 -0
  69. package/dist/components/TLanguageSelect.vue_vue_type_script_setup_true_lang.cjs +2 -0
  70. package/dist/components/TLanguageSelect.vue_vue_type_script_setup_true_lang.cjs.map +1 -0
  71. package/dist/components/TLanguageSelect.vue_vue_type_script_setup_true_lang.js +299 -0
  72. package/dist/components/TLanguageSelect.vue_vue_type_script_setup_true_lang.js.map +1 -0
  73. package/dist/components/TModal.cjs.map +1 -1
  74. package/dist/components/TModal.js.map +1 -1
  75. package/dist/components/TModal.vue_vue_type_script_setup_true_lang.cjs +1 -1
  76. package/dist/components/TModal.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  77. package/dist/components/TModal.vue_vue_type_script_setup_true_lang.js +1 -1
  78. package/dist/components/TModal.vue_vue_type_script_setup_true_lang.js.map +1 -1
  79. package/dist/components/TMultiSelect.cjs.map +1 -1
  80. package/dist/components/TMultiSelect.js.map +1 -1
  81. package/dist/components/TMultiSelect.vue_vue_type_script_setup_true_lang.cjs +1 -1
  82. package/dist/components/TMultiSelect.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  83. package/dist/components/TMultiSelect.vue_vue_type_script_setup_true_lang.js +1 -1
  84. package/dist/components/TMultiSelect.vue_vue_type_script_setup_true_lang.js.map +1 -1
  85. package/dist/components/TNavMenu.cjs.map +1 -1
  86. package/dist/components/TNavMenu.js.map +1 -1
  87. package/dist/components/TNavMenu.vue.d.ts +7 -2
  88. package/dist/components/TNavMenu.vue.d.ts.map +1 -1
  89. package/dist/components/TNavMenu.vue_vue_type_script_setup_true_lang.cjs +1 -1
  90. package/dist/components/TNavMenu.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  91. package/dist/components/TNavMenu.vue_vue_type_script_setup_true_lang.js +50 -49
  92. package/dist/components/TNavMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
  93. package/dist/components/TPopover.cjs.map +1 -1
  94. package/dist/components/TPopover.js.map +1 -1
  95. package/dist/components/TPopover.vue.d.ts +4 -2
  96. package/dist/components/TPopover.vue.d.ts.map +1 -1
  97. package/dist/components/TPopover.vue_vue_type_script_setup_true_lang.cjs +1 -1
  98. package/dist/components/TPopover.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  99. package/dist/components/TPopover.vue_vue_type_script_setup_true_lang.js +10 -5
  100. package/dist/components/TPopover.vue_vue_type_script_setup_true_lang.js.map +1 -1
  101. package/dist/components/TPricingCard.vue.d.ts +1 -1
  102. package/dist/components/TPricingCard.vue.d.ts.map +1 -1
  103. package/dist/components/TSidebar.cjs.map +1 -1
  104. package/dist/components/TSidebar.js.map +1 -1
  105. package/dist/components/TSidebar.vue_vue_type_script_setup_true_lang.cjs +1 -1
  106. package/dist/components/TSidebar.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  107. package/dist/components/TSidebar.vue_vue_type_script_setup_true_lang.js +1 -1
  108. package/dist/components/TSidebar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  109. package/dist/components/TSteps.cjs.map +1 -1
  110. package/dist/components/TSteps.js.map +1 -1
  111. package/dist/components/TSteps.vue_vue_type_script_setup_true_lang.cjs +1 -1
  112. package/dist/components/TSteps.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  113. package/dist/components/TSteps.vue_vue_type_script_setup_true_lang.js +1 -1
  114. package/dist/components/TSteps.vue_vue_type_script_setup_true_lang.js.map +1 -1
  115. package/dist/components/TToast.cjs.map +1 -1
  116. package/dist/components/TToast.js.map +1 -1
  117. package/dist/components/TToast.vue.d.ts.map +1 -1
  118. package/dist/components/TToast.vue_vue_type_script_setup_true_lang.cjs +1 -1
  119. package/dist/components/TToast.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  120. package/dist/components/TToast.vue_vue_type_script_setup_true_lang.js +6 -6
  121. package/dist/components/TToast.vue_vue_type_script_setup_true_lang.js.map +1 -1
  122. package/dist/components/TTreeViewItem.cjs.map +1 -1
  123. package/dist/components/TTreeViewItem.js.map +1 -1
  124. package/dist/components/TTreeViewItem.vue_vue_type_script_setup_true_lang.cjs +1 -1
  125. package/dist/components/TTreeViewItem.vue_vue_type_script_setup_true_lang.cjs.map +1 -1
  126. package/dist/components/TTreeViewItem.vue_vue_type_script_setup_true_lang.js +1 -1
  127. package/dist/components/TTreeViewItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
  128. package/dist/components/accordion.cjs.map +1 -1
  129. package/dist/components/accordion.d.ts +4 -4
  130. package/dist/components/accordion.d.ts.map +1 -1
  131. package/dist/components/accordion.js.map +1 -1
  132. package/dist/components/index.d.ts +5 -1
  133. package/dist/components/index.d.ts.map +1 -1
  134. package/dist/components/index.js +77 -0
  135. package/dist/index.cjs +1 -1
  136. package/dist/index.js +81 -78
  137. package/dist/plugin.cjs +1 -1
  138. package/dist/plugin.cjs.map +1 -1
  139. package/dist/plugin.d.ts.map +1 -1
  140. package/dist/plugin.js +146 -142
  141. package/dist/plugin.js.map +1 -1
  142. package/dist/style.css +1 -1
  143. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"TDrawer.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../src/components/TDrawer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n createId,\n focusFirst,\n focusLast,\n getFocusableElements,\n isEscapeKey,\n} from '@treeui/utils';\nimport { getTreeIcon, treeIconDefaults } from '@treeui/icons';\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n ref,\n toRef,\n useAttrs,\n watch,\n} from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TDrawerSide, TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst CloseIcon = getTreeIcon('x');\n\nconst props = withDefaults(\n defineProps<{\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n side?: TDrawerSide;\n title?: string;\n description?: string;\n closeOnEscape?: boolean;\n closeOnOverlay?: boolean;\n showCloseButton?: boolean;\n closeLabel?: string;\n id?: string;\n }>(),\n {\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n side: 'right',\n title: '',\n description: '',\n closeOnEscape: true,\n closeOnOverlay: true,\n showCloseButton: true,\n closeLabel: 'Close drawer',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\nconst attrs = useAttrs();\nconst drawerId = props.id ?? createId('t-drawer');\nconst titleId = `${drawerId}-title`;\nconst descriptionId = `${drawerId}-description`;\nconst rootRef = ref<HTMLElement | null>(null);\nconst surfaceRef = ref<HTMLElement | null>(null);\nconst previousFocusedElement = ref<HTMLElement | null>(null);\nconst hasHeaderContent = computed(() => Boolean(props.title || slots.header));\n\nconst slots = defineSlots<{\n default?: () => unknown;\n trigger?: () => unknown;\n header?: () => unknown;\n content?: () => unknown;\n footer?: () => unknown;\n}>();\n\nconst rootClasses = computed(() => ['t-drawer', attrs.class]);\nconst rootStyle = computed(() => attrs.style);\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs;\n return rest;\n});\nconst surfaceClasses = computed(() => [\n 't-drawer__surface',\n `t-drawer__surface--${props.size}`,\n `t-drawer__surface--${props.side}`,\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 labelledBy = computed(() => (hasHeaderContent.value ? titleId : undefined));\nconst describedBy = computed(() => (props.description ? descriptionId : undefined));\n\nlet openOverlayCount = 0;\nlet previousBodyOverflow = '';\n\nconst lockBodyScroll = () => {\n if (typeof document === 'undefined') {\n return;\n }\n\n if (openOverlayCount === 0) {\n previousBodyOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n\n openOverlayCount += 1;\n};\n\nconst unlockBodyScroll = () => {\n if (typeof document === 'undefined' || openOverlayCount === 0) {\n return;\n }\n\n openOverlayCount -= 1;\n\n if (openOverlayCount === 0) {\n document.body.style.overflow = previousBodyOverflow;\n }\n};\n\nconst focusSurface = () => {\n nextTick(() => {\n if (!surfaceRef.value) {\n return;\n }\n\n const focused = focusFirst(surfaceRef.value);\n if (!focused) {\n surfaceRef.value.focus();\n }\n });\n};\n\nconst openDrawer = () => {\n if (props.disabled) {\n return;\n }\n\n previousFocusedElement.value = document.activeElement as HTMLElement | null;\n setValue(true);\n};\n\nconst closeDrawer = () => {\n setValue(false);\n};\n\nconst onTriggerClick = (event: MouseEvent) => {\n if (props.disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n if (event.defaultPrevented) {\n return;\n }\n\n openDrawer();\n};\n\nconst onOverlayClick = () => {\n if (!props.closeOnOverlay) {\n return;\n }\n\n closeDrawer();\n};\n\nconst onSurfaceClick = (event: MouseEvent) => {\n event.stopPropagation();\n};\n\nconst onKeydown = (event: KeyboardEvent) => {\n if (isEscapeKey(event) && props.closeOnEscape) {\n event.preventDefault();\n closeDrawer();\n return;\n }\n\n if (event.key !== 'Tab' || !surfaceRef.value) {\n return;\n }\n\n const focusable = getFocusableElements(surfaceRef.value);\n\n if (!focusable.length) {\n event.preventDefault();\n surfaceRef.value.focus();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const activeElement = document.activeElement as HTMLElement | null;\n\n if (event.shiftKey && activeElement === first) {\n event.preventDefault();\n focusLast(surfaceRef.value);\n }\n\n if (!event.shiftKey && activeElement === last) {\n event.preventDefault();\n focusFirst(surfaceRef.value);\n }\n};\n\nwatch(isOpen, (value, previousValue) => {\n if (value) {\n lockBodyScroll();\n focusSurface();\n return;\n }\n\n if (previousValue) {\n unlockBodyScroll();\n nextTick(() => {\n previousFocusedElement.value?.focus();\n });\n }\n});\n\nonBeforeUnmount(() => {\n if (isOpen.value) {\n unlockBodyScroll();\n }\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 <span\n v-if=\"$slots.trigger\"\n class=\"t-drawer__trigger\"\n v-bind=\"triggerAttrs\"\n :aria-disabled=\"disabled || undefined\"\n @click=\"onTriggerClick\"\n >\n <slot name=\"trigger\" />\n </span>\n\n <Teleport to=\"body\">\n <transition name=\"t-drawer-fade\">\n <div\n v-if=\"isOpen\"\n class=\"t-drawer__portal\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n >\n <div\n class=\"t-drawer__backdrop\"\n aria-hidden=\"true\"\n @click=\"onOverlayClick\"\n />\n <div\n :id=\"drawerId\"\n ref=\"surfaceRef\"\n :class=\"surfaceClasses\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n tabindex=\"-1\"\n @click=\"onSurfaceClick\"\n @keydown=\"onKeydown\"\n >\n <div\n v-if=\"hasHeaderContent || showCloseButton\"\n class=\"t-drawer__topbar\"\n >\n <div\n v-if=\"hasHeaderContent\"\n :id=\"titleId\"\n class=\"t-drawer__header\"\n >\n <slot name=\"header\">\n <h2 class=\"t-drawer__title\">\n {{ title }}\n </h2>\n </slot>\n </div>\n <button\n v-if=\"showCloseButton\"\n type=\"button\"\n class=\"t-drawer__close\"\n :aria-label=\"closeLabel\"\n @click=\"closeDrawer\"\n >\n <CloseIcon v-bind=\"treeIconDefaults\" />\n </button>\n </div>\n\n <p\n v-if=\"description\"\n :id=\"descriptionId\"\n class=\"t-drawer__description\"\n >\n {{ description }}\n </p>\n\n <div class=\"t-drawer__body\">\n <slot name=\"content\">\n <slot />\n </slot>\n </div>\n\n <div\n v-if=\"$slots.footer\"\n class=\"t-drawer__footer\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </transition>\n </Teleport>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"TDrawer.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../src/components/TDrawer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n createId,\n focusFirst,\n focusLast,\n getFocusableElements,\n isEscapeKey,\n} from '@treeui/utils';\nimport { getTreeIcon, treeIconDefaults } from '@treeui/icons';\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n ref,\n toRef,\n useAttrs,\n watch,\n} from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TDrawerSide, TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nconst CloseIcon = computed(() => getTreeIcon('x'));\n\nconst props = withDefaults(\n defineProps<{\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n side?: TDrawerSide;\n title?: string;\n description?: string;\n closeOnEscape?: boolean;\n closeOnOverlay?: boolean;\n showCloseButton?: boolean;\n closeLabel?: string;\n id?: string;\n }>(),\n {\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n side: 'right',\n title: '',\n description: '',\n closeOnEscape: true,\n closeOnOverlay: true,\n showCloseButton: true,\n closeLabel: 'Close drawer',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\nconst attrs = useAttrs();\nconst drawerId = props.id ?? createId('t-drawer');\nconst titleId = `${drawerId}-title`;\nconst descriptionId = `${drawerId}-description`;\nconst rootRef = ref<HTMLElement | null>(null);\nconst surfaceRef = ref<HTMLElement | null>(null);\nconst previousFocusedElement = ref<HTMLElement | null>(null);\nconst hasHeaderContent = computed(() => Boolean(props.title || slots.header));\n\nconst slots = defineSlots<{\n default?: () => unknown;\n trigger?: () => unknown;\n header?: () => unknown;\n content?: () => unknown;\n footer?: () => unknown;\n}>();\n\nconst rootClasses = computed(() => ['t-drawer', attrs.class]);\nconst rootStyle = computed(() => attrs.style);\nconst triggerAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs;\n return rest;\n});\nconst surfaceClasses = computed(() => [\n 't-drawer__surface',\n `t-drawer__surface--${props.size}`,\n `t-drawer__surface--${props.side}`,\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 labelledBy = computed(() => (hasHeaderContent.value ? titleId : undefined));\nconst describedBy = computed(() => (props.description ? descriptionId : undefined));\n\nlet openOverlayCount = 0;\nlet previousBodyOverflow = '';\n\nconst lockBodyScroll = () => {\n if (typeof document === 'undefined') {\n return;\n }\n\n if (openOverlayCount === 0) {\n previousBodyOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n\n openOverlayCount += 1;\n};\n\nconst unlockBodyScroll = () => {\n if (typeof document === 'undefined' || openOverlayCount === 0) {\n return;\n }\n\n openOverlayCount -= 1;\n\n if (openOverlayCount === 0) {\n document.body.style.overflow = previousBodyOverflow;\n }\n};\n\nconst focusSurface = () => {\n nextTick(() => {\n if (!surfaceRef.value) {\n return;\n }\n\n const focused = focusFirst(surfaceRef.value);\n if (!focused) {\n surfaceRef.value.focus();\n }\n });\n};\n\nconst openDrawer = () => {\n if (props.disabled) {\n return;\n }\n\n previousFocusedElement.value = document.activeElement as HTMLElement | null;\n setValue(true);\n};\n\nconst closeDrawer = () => {\n setValue(false);\n};\n\nconst onTriggerClick = (event: MouseEvent) => {\n if (props.disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n if (event.defaultPrevented) {\n return;\n }\n\n openDrawer();\n};\n\nconst onOverlayClick = () => {\n if (!props.closeOnOverlay) {\n return;\n }\n\n closeDrawer();\n};\n\nconst onSurfaceClick = (event: MouseEvent) => {\n event.stopPropagation();\n};\n\nconst onKeydown = (event: KeyboardEvent) => {\n if (isEscapeKey(event) && props.closeOnEscape) {\n event.preventDefault();\n closeDrawer();\n return;\n }\n\n if (event.key !== 'Tab' || !surfaceRef.value) {\n return;\n }\n\n const focusable = getFocusableElements(surfaceRef.value);\n\n if (!focusable.length) {\n event.preventDefault();\n surfaceRef.value.focus();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const activeElement = document.activeElement as HTMLElement | null;\n\n if (event.shiftKey && activeElement === first) {\n event.preventDefault();\n focusLast(surfaceRef.value);\n }\n\n if (!event.shiftKey && activeElement === last) {\n event.preventDefault();\n focusFirst(surfaceRef.value);\n }\n};\n\nwatch(isOpen, (value, previousValue) => {\n if (value) {\n lockBodyScroll();\n focusSurface();\n return;\n }\n\n if (previousValue) {\n unlockBodyScroll();\n nextTick(() => {\n previousFocusedElement.value?.focus();\n });\n }\n});\n\nonBeforeUnmount(() => {\n if (isOpen.value) {\n unlockBodyScroll();\n }\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 <span\n v-if=\"$slots.trigger\"\n class=\"t-drawer__trigger\"\n v-bind=\"triggerAttrs\"\n :aria-disabled=\"disabled || undefined\"\n @click=\"onTriggerClick\"\n >\n <slot name=\"trigger\" />\n </span>\n\n <Teleport to=\"body\">\n <transition name=\"t-drawer-fade\">\n <div\n v-if=\"isOpen\"\n class=\"t-drawer__portal\"\n :data-state=\"isOpen ? 'open' : 'closed'\"\n >\n <div\n class=\"t-drawer__backdrop\"\n aria-hidden=\"true\"\n @click=\"onOverlayClick\"\n />\n <div\n :id=\"drawerId\"\n ref=\"surfaceRef\"\n :class=\"surfaceClasses\"\n role=\"dialog\"\n aria-modal=\"true\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n tabindex=\"-1\"\n @click=\"onSurfaceClick\"\n @keydown=\"onKeydown\"\n >\n <div\n v-if=\"hasHeaderContent || showCloseButton\"\n class=\"t-drawer__topbar\"\n >\n <div\n v-if=\"hasHeaderContent\"\n :id=\"titleId\"\n class=\"t-drawer__header\"\n >\n <slot name=\"header\">\n <h2 class=\"t-drawer__title\">\n {{ title }}\n </h2>\n </slot>\n </div>\n <button\n v-if=\"showCloseButton\"\n type=\"button\"\n class=\"t-drawer__close\"\n :aria-label=\"closeLabel\"\n @click=\"closeDrawer\"\n >\n <CloseIcon v-bind=\"treeIconDefaults\" />\n </button>\n </div>\n\n <p\n v-if=\"description\"\n :id=\"descriptionId\"\n class=\"t-drawer__description\"\n >\n {{ description }}\n </p>\n\n <div class=\"t-drawer__body\">\n <slot name=\"content\">\n <slot />\n </slot>\n </div>\n\n <div\n v-if=\"$slots.footer\"\n class=\"t-drawer__footer\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n </div>\n </transition>\n </Teleport>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TDropdown.cjs","names":[],"sources":["../../src/components/TDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, focusFirst, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nexport interface TDropdownItem {\n label: string;\n value: string;\n disabled?: boolean;\n}\n\nexport type TDropdownAlign = 'start' | 'end';\n\nconst props = withDefaults(\n defineProps<{\n items?: TDropdownItem[];\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n label?: string;\n align?: TDropdownAlign;\n }>(),\n {\n items: () => [],\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n label: '',\n align: 'start',\n },\n);\n\nconst emit = defineEmits<{\n select: [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean }): unknown;\n item(props: { item: TDropdownItem; index: number }): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst menuId = createId('t-dropdown');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLElement | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\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-dropdown',\n `t-dropdown--${props.size}`,\n {\n 't-dropdown--align-end': props.align === 'end',\n 'is-disabled': props.disabled,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst enabledItems = computed(() => props.items.filter((i) => !i.disabled));\n\nconst openMenu = () => {\n if (props.disabled) return;\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n setValue(true);\n nextTick(() => focusItem(focusedIndex.value));\n};\n\nconst closeMenu = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst toggleMenu = () => {\n if (props.disabled) return;\n if (isOpen.value) {\n closeMenu();\n } else {\n openMenu();\n }\n};\n\nconst selectItem = (item: TDropdownItem) => {\n if (item.disabled) return;\n emit('select', item.value);\n closeMenu(true);\n};\n\nconst focusItem = (index: number) => {\n const item = props.items[index];\n if (!item) return;\n const el = itemRefs.value.get(item.value);\n el?.focus();\n};\n\nconst setItemRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n itemRefs.value.set(value, el);\n } else {\n itemRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.items.length) {\n if (!props.items[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusItem(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 closeMenu();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openMenu();\n }\n};\n\nconst onItemKeydown = (event: KeyboardEvent, item: TDropdownItem) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeMenu(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectItem(item);\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 = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n focusItem(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[enabledItems.value.length - 1])\n : props.items.length - 1;\n focusItem(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 closeMenu();\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 <span\n ref=\"triggerRef\"\n class=\"t-dropdown__trigger-wrapper\"\n @click=\"toggleMenu\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n >\n <button\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-dropdown__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? menuId : undefined\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"isOpen\"\n >\n <span class=\"t-dropdown__label\">{{ label }}</span>\n <svg\n class=\"t-dropdown__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 </slot>\n </span>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"menuId\"\n role=\"menu\"\n class=\"t-dropdown__menu\"\n :aria-label=\"label || undefined\"\n >\n <li\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :ref=\"(el) => setItemRef(el as Element | null, item.value)\"\n role=\"menuitem\"\n class=\"t-dropdown__item\"\n :class=\"{\n 'is-disabled': item.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-disabled=\"item.disabled || undefined\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"selectItem(item)\"\n @keydown=\"onItemKeydown($event, item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n >\n {{ item.label }}\n </slot>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"TDropdown.cjs","names":[],"sources":["../../src/components/TDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, focusFirst, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nexport interface TDropdownItem {\n label: string;\n value: string;\n disabled?: boolean;\n}\n\nexport type TDropdownAlign = 'start' | 'end';\n\nconst props = withDefaults(\n defineProps<{\n items?: TDropdownItem[];\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n label?: string;\n align?: TDropdownAlign;\n id?: string;\n }>(),\n {\n items: () => [],\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n label: '',\n align: 'start',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n select: [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean; menuId: string }): unknown;\n item(props: { item: TDropdownItem; index: number }): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst menuId = props.id ?? createId('t-dropdown');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLElement | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\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-dropdown',\n `t-dropdown--${props.size}`,\n {\n 't-dropdown--align-end': props.align === 'end',\n 'is-disabled': props.disabled,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst enabledItems = computed(() => props.items.filter((i) => !i.disabled));\n\nconst openMenu = () => {\n if (props.disabled) return;\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n setValue(true);\n nextTick(() => focusItem(focusedIndex.value));\n};\n\nconst closeMenu = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst toggleMenu = () => {\n if (props.disabled) return;\n if (isOpen.value) {\n closeMenu();\n } else {\n openMenu();\n }\n};\n\nconst selectItem = (item: TDropdownItem) => {\n if (item.disabled) return;\n emit('select', item.value);\n closeMenu(true);\n};\n\nconst focusItem = (index: number) => {\n const item = props.items[index];\n if (!item) return;\n const el = itemRefs.value.get(item.value);\n el?.focus();\n};\n\nconst setItemRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n itemRefs.value.set(value, el);\n } else {\n itemRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.items.length) {\n if (!props.items[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusItem(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 closeMenu();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openMenu();\n }\n};\n\nconst onItemKeydown = (event: KeyboardEvent, item: TDropdownItem) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeMenu(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectItem(item);\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 = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n focusItem(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[enabledItems.value.length - 1])\n : props.items.length - 1;\n focusItem(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 closeMenu();\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 <span\n ref=\"triggerRef\"\n class=\"t-dropdown__trigger-wrapper\"\n @click=\"toggleMenu\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n :menu-id=\"menuId\"\n >\n <button\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-dropdown__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? menuId : undefined\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"isOpen\"\n >\n <span class=\"t-dropdown__label\">{{ label }}</span>\n <svg\n class=\"t-dropdown__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 </slot>\n </span>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"menuId\"\n role=\"menu\"\n class=\"t-dropdown__menu\"\n :aria-label=\"label || undefined\"\n >\n <li\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :ref=\"(el) => setItemRef(el as Element | null, item.value)\"\n role=\"menuitem\"\n class=\"t-dropdown__item\"\n :class=\"{\n 'is-disabled': item.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-disabled=\"item.disabled || undefined\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"selectItem(item)\"\n @keydown=\"onItemKeydown($event, item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n >\n {{ item.label }}\n </slot>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"TDropdown.js","names":[],"sources":["../../src/components/TDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, focusFirst, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nexport interface TDropdownItem {\n label: string;\n value: string;\n disabled?: boolean;\n}\n\nexport type TDropdownAlign = 'start' | 'end';\n\nconst props = withDefaults(\n defineProps<{\n items?: TDropdownItem[];\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n label?: string;\n align?: TDropdownAlign;\n }>(),\n {\n items: () => [],\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n label: '',\n align: 'start',\n },\n);\n\nconst emit = defineEmits<{\n select: [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean }): unknown;\n item(props: { item: TDropdownItem; index: number }): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst menuId = createId('t-dropdown');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLElement | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\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-dropdown',\n `t-dropdown--${props.size}`,\n {\n 't-dropdown--align-end': props.align === 'end',\n 'is-disabled': props.disabled,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst enabledItems = computed(() => props.items.filter((i) => !i.disabled));\n\nconst openMenu = () => {\n if (props.disabled) return;\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n setValue(true);\n nextTick(() => focusItem(focusedIndex.value));\n};\n\nconst closeMenu = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst toggleMenu = () => {\n if (props.disabled) return;\n if (isOpen.value) {\n closeMenu();\n } else {\n openMenu();\n }\n};\n\nconst selectItem = (item: TDropdownItem) => {\n if (item.disabled) return;\n emit('select', item.value);\n closeMenu(true);\n};\n\nconst focusItem = (index: number) => {\n const item = props.items[index];\n if (!item) return;\n const el = itemRefs.value.get(item.value);\n el?.focus();\n};\n\nconst setItemRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n itemRefs.value.set(value, el);\n } else {\n itemRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.items.length) {\n if (!props.items[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusItem(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 closeMenu();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openMenu();\n }\n};\n\nconst onItemKeydown = (event: KeyboardEvent, item: TDropdownItem) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeMenu(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectItem(item);\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 = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n focusItem(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[enabledItems.value.length - 1])\n : props.items.length - 1;\n focusItem(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 closeMenu();\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 <span\n ref=\"triggerRef\"\n class=\"t-dropdown__trigger-wrapper\"\n @click=\"toggleMenu\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n >\n <button\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-dropdown__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? menuId : undefined\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"isOpen\"\n >\n <span class=\"t-dropdown__label\">{{ label }}</span>\n <svg\n class=\"t-dropdown__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 </slot>\n </span>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"menuId\"\n role=\"menu\"\n class=\"t-dropdown__menu\"\n :aria-label=\"label || undefined\"\n >\n <li\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :ref=\"(el) => setItemRef(el as Element | null, item.value)\"\n role=\"menuitem\"\n class=\"t-dropdown__item\"\n :class=\"{\n 'is-disabled': item.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-disabled=\"item.disabled || undefined\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"selectItem(item)\"\n @keydown=\"onItemKeydown($event, item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n >\n {{ item.label }}\n </slot>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"TDropdown.js","names":[],"sources":["../../src/components/TDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, focusFirst, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nexport interface TDropdownItem {\n label: string;\n value: string;\n disabled?: boolean;\n}\n\nexport type TDropdownAlign = 'start' | 'end';\n\nconst props = withDefaults(\n defineProps<{\n items?: TDropdownItem[];\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n label?: string;\n align?: TDropdownAlign;\n id?: string;\n }>(),\n {\n items: () => [],\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n label: '',\n align: 'start',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n select: [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean; menuId: string }): unknown;\n item(props: { item: TDropdownItem; index: number }): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst menuId = props.id ?? createId('t-dropdown');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLElement | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\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-dropdown',\n `t-dropdown--${props.size}`,\n {\n 't-dropdown--align-end': props.align === 'end',\n 'is-disabled': props.disabled,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst enabledItems = computed(() => props.items.filter((i) => !i.disabled));\n\nconst openMenu = () => {\n if (props.disabled) return;\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n setValue(true);\n nextTick(() => focusItem(focusedIndex.value));\n};\n\nconst closeMenu = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst toggleMenu = () => {\n if (props.disabled) return;\n if (isOpen.value) {\n closeMenu();\n } else {\n openMenu();\n }\n};\n\nconst selectItem = (item: TDropdownItem) => {\n if (item.disabled) return;\n emit('select', item.value);\n closeMenu(true);\n};\n\nconst focusItem = (index: number) => {\n const item = props.items[index];\n if (!item) return;\n const el = itemRefs.value.get(item.value);\n el?.focus();\n};\n\nconst setItemRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n itemRefs.value.set(value, el);\n } else {\n itemRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.items.length) {\n if (!props.items[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusItem(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 closeMenu();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openMenu();\n }\n};\n\nconst onItemKeydown = (event: KeyboardEvent, item: TDropdownItem) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeMenu(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectItem(item);\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 = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n focusItem(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[enabledItems.value.length - 1])\n : props.items.length - 1;\n focusItem(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 closeMenu();\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 <span\n ref=\"triggerRef\"\n class=\"t-dropdown__trigger-wrapper\"\n @click=\"toggleMenu\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n :menu-id=\"menuId\"\n >\n <button\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-dropdown__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? menuId : undefined\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"isOpen\"\n >\n <span class=\"t-dropdown__label\">{{ label }}</span>\n <svg\n class=\"t-dropdown__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 </slot>\n </span>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"menuId\"\n role=\"menu\"\n class=\"t-dropdown__menu\"\n :aria-label=\"label || undefined\"\n >\n <li\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :ref=\"(el) => setItemRef(el as Element | null, item.value)\"\n role=\"menuitem\"\n class=\"t-dropdown__item\"\n :class=\"{\n 'is-disabled': item.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-disabled=\"item.disabled || undefined\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"selectItem(item)\"\n @keydown=\"onItemKeydown($event, item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n >\n {{ item.label }}\n </slot>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":""}
@@ -13,12 +13,14 @@ type __VLS_Props = {
13
13
  size?: TSize;
14
14
  label?: string;
15
15
  align?: TDropdownAlign;
16
+ id?: string;
16
17
  };
17
18
  declare function __VLS_template(): {
18
19
  attrs: Partial<{}>;
19
20
  slots: Readonly<{
20
21
  trigger(props: {
21
22
  isOpen: boolean;
23
+ menuId: string;
22
24
  }): unknown;
23
25
  item(props: {
24
26
  item: TDropdownItem;
@@ -27,6 +29,7 @@ declare function __VLS_template(): {
27
29
  }> & {
28
30
  trigger(props: {
29
31
  isOpen: boolean;
32
+ menuId: string;
30
33
  }): unknown;
31
34
  item(props: {
32
35
  item: TDropdownItem;
@@ -52,6 +55,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_Props, {}, {}
52
55
  disabled: boolean;
53
56
  size: TSize;
54
57
  label: string;
58
+ id: string;
55
59
  align: TDropdownAlign;
56
60
  open: boolean;
57
61
  defaultOpen: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"TDropdown.vue.d.ts","sourceRoot":"","sources":["../../src/components/TDropdown.vue"],"names":[],"mappings":"AAkTA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAMhD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,KAAK,CAAC;AAE7C,KAAK,WAAW,GAAG;IACf,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB,CAAC;AAkNJ,iBAAS,cAAc;WA8GT,OAAO,IAA6B;;uBA1SjC;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO;oBAChC;YAAE,IAAI,EAAE,aAAa,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO;;uBAD7C;YAAE,MAAM,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO;oBAChC;YAAE,IAAI,EAAE,aAAa,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO;;;;;;;EA8S7D;AAuBD,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAC9D,QAAA,MAAM,eAAe;;;;;;;;;cAjWN,OAAO;UACX,KAAK;WACJ,MAAM;WACN,cAAc;UALf,OAAO;iBACA,OAAO;WAFb,aAAa,EAAE;;;;OA6WzB,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
+ {"version":3,"file":"TDropdown.vue.d.ts","sourceRoot":"","sources":["../../src/components/TDropdown.vue"],"names":[],"mappings":"AAqTA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAMhD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,KAAK,CAAC;AAE7C,KAAK,WAAW,GAAG;IACf,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAoNJ,iBAAS,cAAc;WA+GT,OAAO,IAA6B;;uBA5SjC;YAAE,MAAM,EAAE,OAAO,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO;oBAChD;YAAE,IAAI,EAAE,aAAa,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO;;uBAD7C;YAAE,MAAM,EAAE,OAAO,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO;oBAChD;YAAE,IAAI,EAAE,aAAa,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,OAAO;;;;;;;EAgT7D;AAuBD,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAC9D,QAAA,MAAM,eAAe;;;;;;;;;cArWN,OAAO;UACX,KAAK;WACJ,MAAM;QAET,MAAM;WADH,cAAc;UALf,OAAO;iBACA,OAAO;WAFb,aAAa,EAAE;;;;OAiXzB,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-controls`,`aria-expanded`],a={class:`t-dropdown__label`},o=[`id`,`aria-label`],s=[`aria-disabled`,`tabindex`,`onClick`,`onKeydown`],c=(0,t.defineComponent)({inheritAttrs:!1,__name:`TDropdown`,props:{items:{default:()=>[]},open:{type:Boolean,default:void 0},defaultOpen:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},size:{default:`md`},label:{default:``},align:{default:`start`}},emits:[`select`,`update:open`,`open-change`],setup(c,{emit:l}){let u=c,d=l,f=(0,t.useAttrs)(),p=(0,n.createId)(`t-dropdown`),m=(0,t.ref)(null),h=(0,t.ref)(null),g=(0,t.ref)(new Map),_=(0,t.ref)(-1),v=(0,t.computed)(()=>{let{class:e,style:t,...n}=f;return n}),{value:y,setValue:b}=e.useControllableOpen((0,t.toRef)(u,`open`),u.defaultOpen,e=>{d(`update:open`,e),d(`open-change`,e)}),x=(0,t.computed)(()=>[`t-dropdown`,`t-dropdown--${u.size}`,{"t-dropdown--align-end":u.align===`end`,"is-disabled":u.disabled,"is-open":y.value},f.class]),S=(0,t.computed)(()=>f.style),C=(0,t.computed)(()=>u.items.filter(e=>!e.disabled)),w=()=>{u.disabled||(_.value=C.value.length>0?u.items.indexOf(C.value[0]):0,b(!0),(0,t.nextTick)(()=>O(_.value)))},T=(e=!1)=>{b(!1),_.value=-1,e&&(0,t.nextTick)(()=>{h.value&&(0,n.focusFirst)(h.value)})},E=()=>{u.disabled||(y.value?T():w())},D=e=>{e.disabled||(d(`select`,e.value),T(!0))},O=e=>{let t=u.items[e];t&&g.value.get(t.value)?.focus()},k=(e,t)=>{e instanceof HTMLElement?g.value.set(t,e):g.value.delete(t)},A=e=>{let t=_.value+e;for(;t>=0&&t<u.items.length;){if(!u.items[t].disabled){_.value=t,O(t);return}t+=e}},j=e=>{if(!u.disabled){if((0,n.isEscapeKey)(e)&&y.value){e.preventDefault(),T();return}((0,n.isActivationKey)(e)||e.key===`ArrowDown`||e.key===`ArrowUp`)&&(e.preventDefault(),w())}},M=(e,t)=>{if((0,n.isEscapeKey)(e)){e.preventDefault(),T(!0);return}if((0,n.isActivationKey)(e)){e.preventDefault(),D(t);return}switch(e.key){case`ArrowDown`:e.preventDefault(),A(1);break;case`ArrowUp`:e.preventDefault(),A(-1);break;case`Home`:e.preventDefault(),_.value=C.value.length>0?u.items.indexOf(C.value[0]):0,O(_.value);break;case`End`:e.preventDefault(),_.value=C.value.length>0?u.items.indexOf(C.value[C.value.length-1]):u.items.length-1,O(_.value);break;default:break}},N=e=>{if(!y.value)return;let t=e.target;t instanceof Node&&(m.value?.contains(t)||T())};return(0,t.watch)(y,e=>{e?document.addEventListener(`pointerdown`,N):document.removeEventListener(`pointerdown`,N)}),(0,t.onBeforeUnmount)(()=>{document.removeEventListener(`pointerdown`,N)}),(e,n)=>((0,t.openBlock)(),(0,t.createElementBlock)(`div`,{ref_key:`rootRef`,ref:m,class:(0,t.normalizeClass)(x.value),style:(0,t.normalizeStyle)(S.value),"data-state":(0,t.unref)(y)?`open`:`closed`},[(0,t.createElementVNode)(`span`,{ref_key:`triggerRef`,ref:h,class:`t-dropdown__trigger-wrapper`,onClick:E,onKeydown:j},[(0,t.renderSlot)(e.$slots,`trigger`,{isOpen:(0,t.unref)(y)},()=>[(0,t.createElementVNode)(`button`,(0,t.mergeProps)(v.value,{type:`button`,class:`t-dropdown__trigger`,disabled:c.disabled,"aria-controls":(0,t.unref)(y)?(0,t.unref)(p):void 0,"aria-haspopup":`menu`,"aria-expanded":(0,t.unref)(y)}),[(0,t.createElementVNode)(`span`,a,(0,t.toDisplayString)(c.label),1),n[0]||=(0,t.createElementVNode)(`svg`,{class:`t-dropdown__chevron`,viewBox:`0 0 16 16`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[(0,t.createElementVNode)(`polyline`,{points:`4 6 8 10 12 6`})],-1)],16,i)])],544),(0,t.createVNode)(t.Transition,{name:`t-fade`},{default:(0,t.withCtx)(()=>[(0,t.unref)(y)&&!c.disabled?((0,t.openBlock)(),(0,t.createElementBlock)(`ul`,{key:0,id:(0,t.unref)(p),role:`menu`,class:`t-dropdown__menu`,"aria-label":c.label||void 0},[((0,t.openBlock)(!0),(0,t.createElementBlock)(t.Fragment,null,(0,t.renderList)(c.items,(n,r)=>((0,t.openBlock)(),(0,t.createElementBlock)(`li`,{key:n.value,ref_for:!0,ref:e=>k(e,n.value),role:`menuitem`,class:(0,t.normalizeClass)([`t-dropdown__item`,{"is-disabled":n.disabled,"is-focused":r===_.value}]),"aria-disabled":n.disabled||void 0,tabindex:n.disabled?-1:0,onClick:e=>D(n),onKeydown:e=>M(e,n)},[(0,t.renderSlot)(e.$slots,`item`,{item:n,index:r},()=>[(0,t.createTextVNode)((0,t.toDisplayString)(n.label),1)])],42,s))),128))],8,o)):(0,t.createCommentVNode)(``,!0)]),_:3})],14,r))}});exports.default=c;
1
+ const e=require("../composables/useControllableOpen.cjs");let t=require("vue"),n=require("@treeui/utils");var r=[`data-state`],i=[`disabled`,`aria-controls`,`aria-expanded`],a={class:`t-dropdown__label`},o=[`id`,`aria-label`],s=[`aria-disabled`,`tabindex`,`onClick`,`onKeydown`],c=(0,t.defineComponent)({inheritAttrs:!1,__name:`TDropdown`,props:{items:{default:()=>[]},open:{type:Boolean,default:void 0},defaultOpen:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},size:{default:`md`},label:{default:``},align:{default:`start`},id:{default:void 0}},emits:[`select`,`update:open`,`open-change`],setup(c,{emit:l}){let u=c,d=l,f=(0,t.useAttrs)(),p=u.id??(0,n.createId)(`t-dropdown`),m=(0,t.ref)(null),h=(0,t.ref)(null),g=(0,t.ref)(new Map),_=(0,t.ref)(-1),v=(0,t.computed)(()=>{let{class:e,style:t,...n}=f;return n}),{value:y,setValue:b}=e.useControllableOpen((0,t.toRef)(u,`open`),u.defaultOpen,e=>{d(`update:open`,e),d(`open-change`,e)}),x=(0,t.computed)(()=>[`t-dropdown`,`t-dropdown--${u.size}`,{"t-dropdown--align-end":u.align===`end`,"is-disabled":u.disabled,"is-open":y.value},f.class]),S=(0,t.computed)(()=>f.style),C=(0,t.computed)(()=>u.items.filter(e=>!e.disabled)),w=()=>{u.disabled||(_.value=C.value.length>0?u.items.indexOf(C.value[0]):0,b(!0),(0,t.nextTick)(()=>O(_.value)))},T=(e=!1)=>{b(!1),_.value=-1,e&&(0,t.nextTick)(()=>{h.value&&(0,n.focusFirst)(h.value)})},E=()=>{u.disabled||(y.value?T():w())},D=e=>{e.disabled||(d(`select`,e.value),T(!0))},O=e=>{let t=u.items[e];t&&g.value.get(t.value)?.focus()},k=(e,t)=>{e instanceof HTMLElement?g.value.set(t,e):g.value.delete(t)},A=e=>{let t=_.value+e;for(;t>=0&&t<u.items.length;){if(!u.items[t].disabled){_.value=t,O(t);return}t+=e}},j=e=>{if(!u.disabled){if((0,n.isEscapeKey)(e)&&y.value){e.preventDefault(),T();return}((0,n.isActivationKey)(e)||e.key===`ArrowDown`||e.key===`ArrowUp`)&&(e.preventDefault(),w())}},M=(e,t)=>{if((0,n.isEscapeKey)(e)){e.preventDefault(),T(!0);return}if((0,n.isActivationKey)(e)){e.preventDefault(),D(t);return}switch(e.key){case`ArrowDown`:e.preventDefault(),A(1);break;case`ArrowUp`:e.preventDefault(),A(-1);break;case`Home`:e.preventDefault(),_.value=C.value.length>0?u.items.indexOf(C.value[0]):0,O(_.value);break;case`End`:e.preventDefault(),_.value=C.value.length>0?u.items.indexOf(C.value[C.value.length-1]):u.items.length-1,O(_.value);break;default:break}},N=e=>{if(!y.value)return;let t=e.target;t instanceof Node&&(m.value?.contains(t)||T())};return(0,t.watch)(y,e=>{e?document.addEventListener(`pointerdown`,N):document.removeEventListener(`pointerdown`,N)}),(0,t.onBeforeUnmount)(()=>{document.removeEventListener(`pointerdown`,N)}),(e,n)=>((0,t.openBlock)(),(0,t.createElementBlock)(`div`,{ref_key:`rootRef`,ref:m,class:(0,t.normalizeClass)(x.value),style:(0,t.normalizeStyle)(S.value),"data-state":(0,t.unref)(y)?`open`:`closed`},[(0,t.createElementVNode)(`span`,{ref_key:`triggerRef`,ref:h,class:`t-dropdown__trigger-wrapper`,onClick:E,onKeydown:j},[(0,t.renderSlot)(e.$slots,`trigger`,{isOpen:(0,t.unref)(y),menuId:(0,t.unref)(p)},()=>[(0,t.createElementVNode)(`button`,(0,t.mergeProps)(v.value,{type:`button`,class:`t-dropdown__trigger`,disabled:c.disabled,"aria-controls":(0,t.unref)(y)?(0,t.unref)(p):void 0,"aria-haspopup":`menu`,"aria-expanded":(0,t.unref)(y)}),[(0,t.createElementVNode)(`span`,a,(0,t.toDisplayString)(c.label),1),n[0]||=(0,t.createElementVNode)(`svg`,{class:`t-dropdown__chevron`,viewBox:`0 0 16 16`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,"aria-hidden":`true`},[(0,t.createElementVNode)(`polyline`,{points:`4 6 8 10 12 6`})],-1)],16,i)])],544),(0,t.createVNode)(t.Transition,{name:`t-fade`},{default:(0,t.withCtx)(()=>[(0,t.unref)(y)&&!c.disabled?((0,t.openBlock)(),(0,t.createElementBlock)(`ul`,{key:0,id:(0,t.unref)(p),role:`menu`,class:`t-dropdown__menu`,"aria-label":c.label||void 0},[((0,t.openBlock)(!0),(0,t.createElementBlock)(t.Fragment,null,(0,t.renderList)(c.items,(n,r)=>((0,t.openBlock)(),(0,t.createElementBlock)(`li`,{key:n.value,ref_for:!0,ref:e=>k(e,n.value),role:`menuitem`,class:(0,t.normalizeClass)([`t-dropdown__item`,{"is-disabled":n.disabled,"is-focused":r===_.value}]),"aria-disabled":n.disabled||void 0,tabindex:n.disabled?-1:0,onClick:e=>D(n),onKeydown:e=>M(e,n)},[(0,t.renderSlot)(e.$slots,`item`,{item:n,index:r},()=>[(0,t.createTextVNode)((0,t.toDisplayString)(n.label),1)])],42,s))),128))],8,o)):(0,t.createCommentVNode)(``,!0)]),_:3})],14,r))}});exports.default=c;
2
2
  //# sourceMappingURL=TDropdown.vue_vue_type_script_setup_true_lang.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"TDropdown.vue_vue_type_script_setup_true_lang.cjs","names":[],"sources":["../../src/components/TDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, focusFirst, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nexport interface TDropdownItem {\n label: string;\n value: string;\n disabled?: boolean;\n}\n\nexport type TDropdownAlign = 'start' | 'end';\n\nconst props = withDefaults(\n defineProps<{\n items?: TDropdownItem[];\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n label?: string;\n align?: TDropdownAlign;\n }>(),\n {\n items: () => [],\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n label: '',\n align: 'start',\n },\n);\n\nconst emit = defineEmits<{\n select: [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean }): unknown;\n item(props: { item: TDropdownItem; index: number }): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst menuId = createId('t-dropdown');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLElement | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\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-dropdown',\n `t-dropdown--${props.size}`,\n {\n 't-dropdown--align-end': props.align === 'end',\n 'is-disabled': props.disabled,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst enabledItems = computed(() => props.items.filter((i) => !i.disabled));\n\nconst openMenu = () => {\n if (props.disabled) return;\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n setValue(true);\n nextTick(() => focusItem(focusedIndex.value));\n};\n\nconst closeMenu = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst toggleMenu = () => {\n if (props.disabled) return;\n if (isOpen.value) {\n closeMenu();\n } else {\n openMenu();\n }\n};\n\nconst selectItem = (item: TDropdownItem) => {\n if (item.disabled) return;\n emit('select', item.value);\n closeMenu(true);\n};\n\nconst focusItem = (index: number) => {\n const item = props.items[index];\n if (!item) return;\n const el = itemRefs.value.get(item.value);\n el?.focus();\n};\n\nconst setItemRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n itemRefs.value.set(value, el);\n } else {\n itemRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.items.length) {\n if (!props.items[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusItem(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 closeMenu();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openMenu();\n }\n};\n\nconst onItemKeydown = (event: KeyboardEvent, item: TDropdownItem) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeMenu(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectItem(item);\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 = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n focusItem(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[enabledItems.value.length - 1])\n : props.items.length - 1;\n focusItem(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 closeMenu();\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 <span\n ref=\"triggerRef\"\n class=\"t-dropdown__trigger-wrapper\"\n @click=\"toggleMenu\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n >\n <button\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-dropdown__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? menuId : undefined\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"isOpen\"\n >\n <span class=\"t-dropdown__label\">{{ label }}</span>\n <svg\n class=\"t-dropdown__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 </slot>\n </span>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"menuId\"\n role=\"menu\"\n class=\"t-dropdown__menu\"\n :aria-label=\"label || undefined\"\n >\n <li\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :ref=\"(el) => setItemRef(el as Element | null, item.value)\"\n role=\"menuitem\"\n class=\"t-dropdown__item\"\n :class=\"{\n 'is-disabled': item.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-disabled=\"item.disabled || undefined\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"selectItem(item)\"\n @keydown=\"onItemKeydown($event, item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n >\n {{ item.label }}\n </slot>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"TDropdown.vue_vue_type_script_setup_true_lang.cjs","names":[],"sources":["../../src/components/TDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, focusFirst, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nexport interface TDropdownItem {\n label: string;\n value: string;\n disabled?: boolean;\n}\n\nexport type TDropdownAlign = 'start' | 'end';\n\nconst props = withDefaults(\n defineProps<{\n items?: TDropdownItem[];\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n label?: string;\n align?: TDropdownAlign;\n id?: string;\n }>(),\n {\n items: () => [],\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n label: '',\n align: 'start',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n select: [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean; menuId: string }): unknown;\n item(props: { item: TDropdownItem; index: number }): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst menuId = props.id ?? createId('t-dropdown');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLElement | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\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-dropdown',\n `t-dropdown--${props.size}`,\n {\n 't-dropdown--align-end': props.align === 'end',\n 'is-disabled': props.disabled,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst enabledItems = computed(() => props.items.filter((i) => !i.disabled));\n\nconst openMenu = () => {\n if (props.disabled) return;\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n setValue(true);\n nextTick(() => focusItem(focusedIndex.value));\n};\n\nconst closeMenu = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst toggleMenu = () => {\n if (props.disabled) return;\n if (isOpen.value) {\n closeMenu();\n } else {\n openMenu();\n }\n};\n\nconst selectItem = (item: TDropdownItem) => {\n if (item.disabled) return;\n emit('select', item.value);\n closeMenu(true);\n};\n\nconst focusItem = (index: number) => {\n const item = props.items[index];\n if (!item) return;\n const el = itemRefs.value.get(item.value);\n el?.focus();\n};\n\nconst setItemRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n itemRefs.value.set(value, el);\n } else {\n itemRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.items.length) {\n if (!props.items[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusItem(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 closeMenu();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openMenu();\n }\n};\n\nconst onItemKeydown = (event: KeyboardEvent, item: TDropdownItem) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeMenu(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectItem(item);\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 = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n focusItem(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[enabledItems.value.length - 1])\n : props.items.length - 1;\n focusItem(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 closeMenu();\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 <span\n ref=\"triggerRef\"\n class=\"t-dropdown__trigger-wrapper\"\n @click=\"toggleMenu\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n :menu-id=\"menuId\"\n >\n <button\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-dropdown__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? menuId : undefined\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"isOpen\"\n >\n <span class=\"t-dropdown__label\">{{ label }}</span>\n <svg\n class=\"t-dropdown__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 </slot>\n </span>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"menuId\"\n role=\"menu\"\n class=\"t-dropdown__menu\"\n :aria-label=\"label || undefined\"\n >\n <li\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :ref=\"(el) => setItemRef(el as Element | null, item.value)\"\n role=\"menuitem\"\n class=\"t-dropdown__item\"\n :class=\"{\n 'is-disabled': item.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-disabled=\"item.disabled || undefined\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"selectItem(item)\"\n @keydown=\"onItemKeydown($event, item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n >\n {{ item.label }}\n </slot>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":"gnBAkBA,IAAM,EAAQ,EAuBR,EAAO,EAWP,GAAA,EAAA,EAAA,SAAA,CAAiB,EACjB,EAAS,EAAM,KAAA,EAAA,EAAA,SAAA,CAAe,YAAY,EAC1C,GAAA,EAAA,EAAA,IAAA,CAAkC,IAAI,EACtC,GAAA,EAAA,EAAA,IAAA,CAAqC,IAAI,EACzC,GAAA,EAAA,EAAA,IAAA,CAAyC,IAAI,GAAK,EAClD,GAAA,EAAA,EAAA,IAAA,CAAmB,EAAE,EAErB,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,aACA,eAAe,EAAM,OACrB,CACE,wBAAyB,EAAM,QAAU,MACzC,cAAe,EAAM,SACrB,UAAW,EAAO,KACpB,EACA,EAAM,KACR,CAAC,EAEK,GAAA,EAAA,EAAA,SAAA,KAA2B,EAAM,KAAK,EAEtC,GAAA,EAAA,EAAA,SAAA,KAA8B,EAAM,MAAM,OAAQ,GAAM,CAAC,EAAE,QAAQ,CAAC,EAEpE,MAAiB,CACjB,EAAM,WACV,EAAa,MAAQ,EAAa,MAAM,OAAS,EAC7C,EAAM,MAAM,QAAQ,EAAa,MAAM,EAAE,EACzC,EACJ,EAAS,EAAI,GACb,EAAA,EAAA,SAAA,KAAe,EAAU,EAAa,KAAK,CAAC,EAC9C,EAEM,GAAa,EAAe,KAAU,CAC1C,EAAS,EAAK,EACd,EAAa,MAAQ,GACjB,IACF,EAAA,EAAA,SAAA,KAAe,CACT,EAAW,QAAO,EAAA,EAAA,WAAA,CAAW,EAAW,KAAK,CACnD,CAAC,CAEL,EAEM,MAAmB,CACnB,EAAM,WACN,EAAO,MACT,EAAU,EAEV,EAAS,EAEb,EAEM,EAAc,GAAwB,CACtC,EAAK,WACT,EAAK,SAAU,EAAK,KAAK,EACzB,EAAU,EAAI,EAChB,EAEM,EAAa,GAAkB,CACnC,IAAM,EAAO,EAAM,MAAM,GACpB,GAEL,EADoB,MAAM,IAAI,EAAK,KACnC,CAAA,EAAI,MAAM,CACZ,EAEM,GAAc,EAAoB,IAAkB,CACpD,aAAc,YAChB,EAAS,MAAM,IAAI,EAAO,CAAE,EAE5B,EAAS,MAAM,OAAO,CAAK,CAE/B,EAEM,EAAa,GAAsB,CACvC,IAAI,EAAY,EAAa,MAAQ,EACrC,KAAO,GAAa,GAAK,EAAY,EAAM,MAAM,QAAQ,CACvD,GAAI,CAAC,EAAM,MAAM,EAAU,CAAC,SAAU,CACpC,EAAa,MAAQ,EACrB,EAAU,CAAS,EACnB,MACF,CACA,GAAa,CACf,CACF,EAEM,EAAoB,GAAyB,CAC7C,MAAM,SAEV,KAAA,EAAA,EAAA,YAAA,CAAgB,CAAK,GAAK,EAAO,MAAO,CACtC,EAAM,eAAe,EACrB,EAAU,EACV,MACF,GAEA,EAAA,EAAA,gBAAA,CAAoB,CAAK,GAAK,EAAM,MAAQ,aAAe,EAAM,MAAQ,aACvE,EAAM,eAAe,EACrB,EAAS,EAJX,CAMF,EAEM,GAAiB,EAAsB,IAAwB,CACnE,IAAA,EAAA,EAAA,YAAA,CAAgB,CAAK,EAAG,CACtB,EAAM,eAAe,EACrB,EAAU,EAAI,EACd,MACF,CAEA,IAAA,EAAA,EAAA,gBAAA,CAAoB,CAAK,EAAG,CAC1B,EAAM,eAAe,EACrB,EAAW,CAAI,EACf,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,EAAa,MAAM,OAAS,EAC7C,EAAM,MAAM,QAAQ,EAAa,MAAM,EAAE,EACzC,EACJ,EAAU,EAAa,KAAK,EAC5B,MACF,IAAK,MACH,EAAM,eAAe,EACrB,EAAa,MAAQ,EAAa,MAAM,OAAS,EAC7C,EAAM,MAAM,QAAQ,EAAa,MAAM,EAAa,MAAM,OAAS,EAAE,EACrE,EAAM,MAAM,OAAS,EACzB,EAAU,EAAa,KAAK,EAC5B,MACF,QACE,KACJ,CACF,EAEM,EAAyB,GAAwB,CACrD,GAAI,CAAC,EAAO,MAAO,OACnB,IAAM,EAAS,EAAM,OACf,aAAkB,OACpB,EAAQ,OAAO,SAAS,CAAM,GAClC,EAAU,EACZ,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,qDA+EO,MAAA,SA1EA,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,oCAqCZ,OAAA,SAlCD,aAAJ,IAAI,EACJ,MAAM,8BACL,QAAO,EACP,UAAS,qBA8BH,EAAA,OAAA,UAAA,CA1BJ,QAAA,EAAA,EAAA,MAAA,CAAS,CAAA,EACT,QAAA,EAAA,EAAA,MAAA,CAAS,CAAA,OAyBL,EAAA,EAAA,EAAA,mBAAA,CADI,UAAA,EAAA,EAAA,WAAA,CArBC,EAqBD,MArBa,CACpB,KAAK,SACL,MAAM,sBACL,SAAU,EAAA,SACV,iBAAA,EAAA,EAAA,MAAA,CAAe,CAAA,GAAA,EAAA,EAAA,MAAA,CAAS,CAAA,EAAS,IAAA,GAClC,gBAAc,OACb,iBAAA,EAAA,EAAA,MAAA,CAAe,CAAA,8BAEkC,OAAlD,GAAA,EAAA,EAAA,gBAAA,CAAmC,EAAA,KAAK,EAAA,CAAA,EAAA,AAAA,EAAA,MAAA,EAAA,EAAA,mBAAA,CAYlC,MAAA,CAVJ,MAAM,sBACN,QAAQ,YACR,KAAK,OACL,OAAO,eACP,eAAa,IACb,iBAAe,QACf,kBAAgB,QAChB,cAAY,kCAEuB,WAAA,CAAzB,OAAO,eAAe,CAAA,CAAA,EAAA,EAAA,CAAA,EAAA,GAAA,CAAA,CAAA,CAAA,CAAA,EAAA,GAAA,GAAA,EAAA,EAAA,YAAA,CAqC3B,EAAA,WAAA,CAhCD,KAAK,QAAQ,EAAA,2BA+BlB,EAAA,EAAA,EAAA,MAAA,CA7BG,CAAA,GAAM,CAAK,EAAA,WAAA,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CA6Bd,KAAA,OA5BF,IAAA,EAAA,EAAA,MAAA,CAAI,CAAA,EACL,KAAK,OACL,MAAM,mBACL,aAAY,EAAA,OAAS,IAAA,mDAwBjB,EAAA,SAAA,MAAA,EAAA,EAAA,WAAA,CArBqB,EAAA,OAAhB,EAAM,gDAqBX,KAAA,CApBF,IAAK,EAAK,iBACV,IAAM,GAAO,EAAW,EAAsB,EAAK,KAAK,EACzD,KAAK,WACL,OAAA,EAAA,EAAA,eAAA,CAAK,CAAC,mBAAkB,eACa,EAAK,sBAAoC,IAAU,EAAA,SAIvF,gBAAe,EAAK,UAAY,IAAA,GAChC,SAAU,EAAK,SAAQ,GAAA,EACvB,QAAK,GAAE,EAAW,CAAI,EACtB,UAAO,GAAE,EAAc,EAAQ,CAAI,qBAQ7B,EAAA,OAAA,OAAA,CAJE,OACC,aAGH,EAAA,EAAA,EAAA,gBAAA,EAAA,EAAA,EAAA,gBAAA,CADF,EAAK,KAAK,EAAA,CAAA,CAAA,CAAA,CAAA,EAAA,GAAA,CAAA"}
@@ -1,6 +1,6 @@
1
1
  import { useControllableOpen as e } from "../composables/useControllableOpen.js";
2
- import { Fragment as t, Transition as n, computed as r, createCommentVNode as ee, createElementBlock as i, createElementVNode as a, createTextVNode as o, createVNode as s, defineComponent as c, mergeProps as l, nextTick as u, normalizeClass as d, normalizeStyle as f, onBeforeUnmount as p, openBlock as m, ref as h, renderList as g, renderSlot as _, toDisplayString as v, toRef as y, unref as b, useAttrs as x, watch as S, withCtx as C } from "vue";
3
- import { createId as w, focusFirst as te, isActivationKey as T, isEscapeKey as E } from "@treeui/utils";
2
+ import { Fragment as t, Transition as n, computed as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, createTextVNode as s, createVNode as c, defineComponent as l, mergeProps as ee, nextTick as u, normalizeClass as d, normalizeStyle as f, onBeforeUnmount as p, openBlock as m, ref as h, renderList as g, renderSlot as _, toDisplayString as v, toRef as y, unref as b, useAttrs as te, watch as x, withCtx as S } from "vue";
3
+ import { createId as C, focusFirst as w, isActivationKey as T, isEscapeKey as E } from "@treeui/utils";
4
4
  //#region src/components/TDropdown.vue?vue&type=script&setup=true&lang.ts
5
5
  var D = ["data-state"], O = [
6
6
  "disabled",
@@ -11,7 +11,7 @@ var D = ["data-state"], O = [
11
11
  "tabindex",
12
12
  "onClick",
13
13
  "onKeydown"
14
- ], M = /*@__PURE__*/ c({
14
+ ], M = /*@__PURE__*/ l({
15
15
  inheritAttrs: !1,
16
16
  __name: "TDropdown",
17
17
  props: {
@@ -30,15 +30,16 @@ var D = ["data-state"], O = [
30
30
  },
31
31
  size: { default: "md" },
32
32
  label: { default: "" },
33
- align: { default: "start" }
33
+ align: { default: "start" },
34
+ id: { default: void 0 }
34
35
  },
35
36
  emits: [
36
37
  "select",
37
38
  "update:open",
38
39
  "open-change"
39
40
  ],
40
- setup(c, { emit: M }) {
41
- let N = c, P = M, F = x(), I = w("t-dropdown"), L = h(null), R = h(null), z = h(/* @__PURE__ */ new Map()), B = h(-1), V = r(() => {
41
+ setup(l, { emit: M }) {
42
+ let N = l, P = M, F = te(), I = N.id ?? C("t-dropdown"), L = h(null), R = h(null), z = h(/* @__PURE__ */ new Map()), B = h(-1), V = r(() => {
42
43
  let { class: e, style: t, ...n } = F;
43
44
  return n;
44
45
  }), { value: H, setValue: U } = e(y(N, "open"), N.defaultOpen, (e) => {
@@ -56,7 +57,7 @@ var D = ["data-state"], O = [
56
57
  N.disabled || (B.value = K.value.length > 0 ? N.items.indexOf(K.value[0]) : 0, U(!0), u(() => Z(B.value)));
57
58
  }, J = (e = !1) => {
58
59
  U(!1), B.value = -1, e && u(() => {
59
- R.value && te(R.value);
60
+ R.value && w(R.value);
60
61
  });
61
62
  }, Y = () => {
62
63
  N.disabled || (H.value ? J() : q());
@@ -113,30 +114,33 @@ var D = ["data-state"], O = [
113
114
  let t = e.target;
114
115
  t instanceof Node && (L.value?.contains(t) || J());
115
116
  };
116
- return S(H, (e) => {
117
+ return x(H, (e) => {
117
118
  e ? document.addEventListener("pointerdown", $) : document.removeEventListener("pointerdown", $);
118
119
  }), p(() => {
119
120
  document.removeEventListener("pointerdown", $);
120
- }), (e, r) => (m(), i("div", {
121
+ }), (e, r) => (m(), a("div", {
121
122
  ref_key: "rootRef",
122
123
  ref: L,
123
124
  class: d(W.value),
124
125
  style: f(G.value),
125
126
  "data-state": b(H) ? "open" : "closed"
126
- }, [a("span", {
127
+ }, [o("span", {
127
128
  ref_key: "triggerRef",
128
129
  ref: R,
129
130
  class: "t-dropdown__trigger-wrapper",
130
131
  onClick: Y,
131
132
  onKeydown: re
132
- }, [_(e.$slots, "trigger", { isOpen: b(H) }, () => [a("button", l(V.value, {
133
+ }, [_(e.$slots, "trigger", {
134
+ isOpen: b(H),
135
+ menuId: b(I)
136
+ }, () => [o("button", ee(V.value, {
133
137
  type: "button",
134
138
  class: "t-dropdown__trigger",
135
- disabled: c.disabled,
139
+ disabled: l.disabled,
136
140
  "aria-controls": b(H) ? b(I) : void 0,
137
141
  "aria-haspopup": "menu",
138
142
  "aria-expanded": b(H)
139
- }), [a("span", k, v(c.label), 1), r[0] ||= a("svg", {
143
+ }), [o("span", k, v(l.label), 1), r[0] ||= o("svg", {
140
144
  class: "t-dropdown__chevron",
141
145
  viewBox: "0 0 16 16",
142
146
  fill: "none",
@@ -145,14 +149,14 @@ var D = ["data-state"], O = [
145
149
  "stroke-linecap": "round",
146
150
  "stroke-linejoin": "round",
147
151
  "aria-hidden": "true"
148
- }, [a("polyline", { points: "4 6 8 10 12 6" })], -1)], 16, O)])], 544), s(n, { name: "t-fade" }, {
149
- default: C(() => [b(H) && !c.disabled ? (m(), i("ul", {
152
+ }, [o("polyline", { points: "4 6 8 10 12 6" })], -1)], 16, O)])], 544), c(n, { name: "t-fade" }, {
153
+ default: S(() => [b(H) && !l.disabled ? (m(), a("ul", {
150
154
  key: 0,
151
155
  id: b(I),
152
156
  role: "menu",
153
157
  class: "t-dropdown__menu",
154
- "aria-label": c.label || void 0
155
- }, [(m(!0), i(t, null, g(c.items, (t, n) => (m(), i("li", {
158
+ "aria-label": l.label || void 0
159
+ }, [(m(!0), a(t, null, g(l.items, (t, n) => (m(), a("li", {
156
160
  key: t.value,
157
161
  ref_for: !0,
158
162
  ref: (e) => ne(e, t.value),
@@ -168,7 +172,7 @@ var D = ["data-state"], O = [
168
172
  }, [_(e.$slots, "item", {
169
173
  item: t,
170
174
  index: n
171
- }, () => [o(v(t.label), 1)])], 42, j))), 128))], 8, A)) : ee("", !0)]),
175
+ }, () => [s(v(t.label), 1)])], 42, j))), 128))], 8, A)) : i("", !0)]),
172
176
  _: 3
173
177
  })], 14, D));
174
178
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TDropdown.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../src/components/TDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, focusFirst, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nexport interface TDropdownItem {\n label: string;\n value: string;\n disabled?: boolean;\n}\n\nexport type TDropdownAlign = 'start' | 'end';\n\nconst props = withDefaults(\n defineProps<{\n items?: TDropdownItem[];\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n label?: string;\n align?: TDropdownAlign;\n }>(),\n {\n items: () => [],\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n label: '',\n align: 'start',\n },\n);\n\nconst emit = defineEmits<{\n select: [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean }): unknown;\n item(props: { item: TDropdownItem; index: number }): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst menuId = createId('t-dropdown');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLElement | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\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-dropdown',\n `t-dropdown--${props.size}`,\n {\n 't-dropdown--align-end': props.align === 'end',\n 'is-disabled': props.disabled,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst enabledItems = computed(() => props.items.filter((i) => !i.disabled));\n\nconst openMenu = () => {\n if (props.disabled) return;\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n setValue(true);\n nextTick(() => focusItem(focusedIndex.value));\n};\n\nconst closeMenu = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst toggleMenu = () => {\n if (props.disabled) return;\n if (isOpen.value) {\n closeMenu();\n } else {\n openMenu();\n }\n};\n\nconst selectItem = (item: TDropdownItem) => {\n if (item.disabled) return;\n emit('select', item.value);\n closeMenu(true);\n};\n\nconst focusItem = (index: number) => {\n const item = props.items[index];\n if (!item) return;\n const el = itemRefs.value.get(item.value);\n el?.focus();\n};\n\nconst setItemRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n itemRefs.value.set(value, el);\n } else {\n itemRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.items.length) {\n if (!props.items[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusItem(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 closeMenu();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openMenu();\n }\n};\n\nconst onItemKeydown = (event: KeyboardEvent, item: TDropdownItem) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeMenu(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectItem(item);\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 = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n focusItem(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[enabledItems.value.length - 1])\n : props.items.length - 1;\n focusItem(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 closeMenu();\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 <span\n ref=\"triggerRef\"\n class=\"t-dropdown__trigger-wrapper\"\n @click=\"toggleMenu\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n >\n <button\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-dropdown__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? menuId : undefined\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"isOpen\"\n >\n <span class=\"t-dropdown__label\">{{ label }}</span>\n <svg\n class=\"t-dropdown__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 </slot>\n </span>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"menuId\"\n role=\"menu\"\n class=\"t-dropdown__menu\"\n :aria-label=\"label || undefined\"\n >\n <li\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :ref=\"(el) => setItemRef(el as Element | null, item.value)\"\n role=\"menuitem\"\n class=\"t-dropdown__item\"\n :class=\"{\n 'is-disabled': item.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-disabled=\"item.disabled || undefined\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"selectItem(item)\"\n @keydown=\"onItemKeydown($event, item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n >\n {{ item.label }}\n </slot>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"TDropdown.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../src/components/TDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { createId, focusFirst, isActivationKey, isEscapeKey } from '@treeui/utils';\nimport { computed, nextTick, onBeforeUnmount, ref, toRef, useAttrs, watch } from 'vue';\nimport { useControllableOpen } from '../composables/useControllableOpen';\nimport type { TSize } from '../types/contracts';\n\ndefineOptions({\n inheritAttrs: false,\n});\n\nexport interface TDropdownItem {\n label: string;\n value: string;\n disabled?: boolean;\n}\n\nexport type TDropdownAlign = 'start' | 'end';\n\nconst props = withDefaults(\n defineProps<{\n items?: TDropdownItem[];\n open?: boolean;\n defaultOpen?: boolean;\n disabled?: boolean;\n size?: TSize;\n label?: string;\n align?: TDropdownAlign;\n id?: string;\n }>(),\n {\n items: () => [],\n open: undefined,\n defaultOpen: false,\n disabled: false,\n size: 'md',\n label: '',\n align: 'start',\n id: undefined,\n },\n);\n\nconst emit = defineEmits<{\n select: [value: string];\n 'update:open': [value: boolean];\n 'open-change': [value: boolean];\n}>();\n\ndefineSlots<{\n trigger(props: { isOpen: boolean; menuId: string }): unknown;\n item(props: { item: TDropdownItem; index: number }): unknown;\n}>();\n\nconst attrs = useAttrs();\nconst menuId = props.id ?? createId('t-dropdown');\nconst rootRef = ref<HTMLElement | null>(null);\nconst triggerRef = ref<HTMLElement | null>(null);\nconst itemRefs = ref<Map<string, HTMLElement>>(new Map());\nconst focusedIndex = ref(-1);\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-dropdown',\n `t-dropdown--${props.size}`,\n {\n 't-dropdown--align-end': props.align === 'end',\n 'is-disabled': props.disabled,\n 'is-open': isOpen.value,\n },\n attrs.class,\n]);\n\nconst rootStyle = computed(() => attrs.style);\n\nconst enabledItems = computed(() => props.items.filter((i) => !i.disabled));\n\nconst openMenu = () => {\n if (props.disabled) return;\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n setValue(true);\n nextTick(() => focusItem(focusedIndex.value));\n};\n\nconst closeMenu = (restoreFocus = false) => {\n setValue(false);\n focusedIndex.value = -1;\n if (restoreFocus) {\n nextTick(() => {\n if (triggerRef.value) focusFirst(triggerRef.value);\n });\n }\n};\n\nconst toggleMenu = () => {\n if (props.disabled) return;\n if (isOpen.value) {\n closeMenu();\n } else {\n openMenu();\n }\n};\n\nconst selectItem = (item: TDropdownItem) => {\n if (item.disabled) return;\n emit('select', item.value);\n closeMenu(true);\n};\n\nconst focusItem = (index: number) => {\n const item = props.items[index];\n if (!item) return;\n const el = itemRefs.value.get(item.value);\n el?.focus();\n};\n\nconst setItemRef = (el: Element | null, value: string) => {\n if (el instanceof HTMLElement) {\n itemRefs.value.set(value, el);\n } else {\n itemRefs.value.delete(value);\n }\n};\n\nconst moveFocus = (direction: 1 | -1) => {\n let nextIndex = focusedIndex.value + direction;\n while (nextIndex >= 0 && nextIndex < props.items.length) {\n if (!props.items[nextIndex].disabled) {\n focusedIndex.value = nextIndex;\n focusItem(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 closeMenu();\n return;\n }\n\n if (isActivationKey(event) || event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n openMenu();\n }\n};\n\nconst onItemKeydown = (event: KeyboardEvent, item: TDropdownItem) => {\n if (isEscapeKey(event)) {\n event.preventDefault();\n closeMenu(true);\n return;\n }\n\n if (isActivationKey(event)) {\n event.preventDefault();\n selectItem(item);\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 = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[0])\n : 0;\n focusItem(focusedIndex.value);\n break;\n case 'End':\n event.preventDefault();\n focusedIndex.value = enabledItems.value.length > 0\n ? props.items.indexOf(enabledItems.value[enabledItems.value.length - 1])\n : props.items.length - 1;\n focusItem(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 closeMenu();\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 <span\n ref=\"triggerRef\"\n class=\"t-dropdown__trigger-wrapper\"\n @click=\"toggleMenu\"\n @keydown=\"onTriggerKeydown\"\n >\n <slot\n name=\"trigger\"\n :is-open=\"isOpen\"\n :menu-id=\"menuId\"\n >\n <button\n v-bind=\"triggerAttrs\"\n type=\"button\"\n class=\"t-dropdown__trigger\"\n :disabled=\"disabled\"\n :aria-controls=\"isOpen ? menuId : undefined\"\n aria-haspopup=\"menu\"\n :aria-expanded=\"isOpen\"\n >\n <span class=\"t-dropdown__label\">{{ label }}</span>\n <svg\n class=\"t-dropdown__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 </slot>\n </span>\n <transition name=\"t-fade\">\n <ul\n v-if=\"isOpen && !disabled\"\n :id=\"menuId\"\n role=\"menu\"\n class=\"t-dropdown__menu\"\n :aria-label=\"label || undefined\"\n >\n <li\n v-for=\"(item, index) in items\"\n :key=\"item.value\"\n :ref=\"(el) => setItemRef(el as Element | null, item.value)\"\n role=\"menuitem\"\n class=\"t-dropdown__item\"\n :class=\"{\n 'is-disabled': item.disabled,\n 'is-focused': index === focusedIndex,\n }\"\n :aria-disabled=\"item.disabled || undefined\"\n :tabindex=\"item.disabled ? -1 : 0\"\n @click=\"selectItem(item)\"\n @keydown=\"onItemKeydown($event, item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :index=\"index\"\n >\n {{ item.label }}\n </slot>\n </li>\n </ul>\n </transition>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBA,IAAM,IAAQ,GAuBR,IAAO,GAWP,IAAQ,GAAS,GACjB,IAAS,EAAM,MAAM,EAAS,YAAY,GAC1C,IAAU,EAAwB,IAAI,GACtC,IAAa,EAAwB,IAAI,GACzC,IAAW,kBAA8B,IAAI,IAAI,CAAC,GAClD,IAAe,EAAI,EAAE,GAErB,IAAe,QAAe;GAClC,IAAM,EAAE,OAAO,GAAQ,OAAO,GAAQ,GAAG,MAAS;GAClD,OAAO;EACT,CAAC,GAEK,EAAE,OAAO,GAAQ,gBAAa,EAClC,EAAM,GAAO,MAAM,GACnB,EAAM,cACL,MAAU;GAET,AADA,EAAK,eAAe,CAAK,GACzB,EAAK,eAAe,CAAK;EAC3B,CACF,GAEM,IAAc,QAAe;GACjC;GACA,eAAe,EAAM;GACrB;IACE,yBAAyB,EAAM,UAAU;IACzC,eAAe,EAAM;IACrB,WAAW,EAAO;GACpB;GACA,EAAM;EACR,CAAC,GAEK,IAAY,QAAe,EAAM,KAAK,GAEtC,IAAe,QAAe,EAAM,MAAM,QAAQ,MAAM,CAAC,EAAE,QAAQ,CAAC,GAEpE,UAAiB;GACjB,EAAM,aACV,EAAa,QAAQ,EAAa,MAAM,SAAS,IAC7C,EAAM,MAAM,QAAQ,EAAa,MAAM,EAAE,IACzC,GACJ,EAAS,EAAI,GACb,QAAe,EAAU,EAAa,KAAK,CAAC;EAC9C,GAEM,KAAa,IAAe,OAAU;GAG1C,AAFA,EAAS,EAAK,GACd,EAAa,QAAQ,IACjB,KACF,QAAe;IACb,AAAI,EAAW,SAAO,EAAW,EAAW,KAAK;GACnD,CAAC;EAEL,GAEM,UAAmB;GACnB,EAAM,aACN,EAAO,QACT,EAAU,IAEV,EAAS;EAEb,GAEM,KAAc,MAAwB;GACtC,EAAK,aACT,EAAK,UAAU,EAAK,KAAK,GACzB,EAAU,EAAI;EAChB,GAEM,KAAa,MAAkB;GACnC,IAAM,IAAO,EAAM,MAAM;GACpB,KAEL,EADoB,MAAM,IAAI,EAAK,KACnC,CAAA,EAAI,MAAM;EACZ,GAEM,MAAc,GAAoB,MAAkB;GACxD,AAAI,aAAc,cAChB,EAAS,MAAM,IAAI,GAAO,CAAE,IAE5B,EAAS,MAAM,OAAO,CAAK;EAE/B,GAEM,KAAa,MAAsB;GACvC,IAAI,IAAY,EAAa,QAAQ;GACrC,OAAO,KAAa,KAAK,IAAY,EAAM,MAAM,SAAQ;IACvD,IAAI,CAAC,EAAM,MAAM,EAAU,CAAC,UAAU;KAEpC,AADA,EAAa,QAAQ,GACrB,EAAU,CAAS;KACnB;IACF;IACA,KAAa;GACf;EACF,GAEM,MAAoB,MAAyB;GAC7C,OAAM,UAEV;QAAI,EAAY,CAAK,KAAK,EAAO,OAAO;KAEtC,AADA,EAAM,eAAe,GACrB,EAAU;KACV;IACF;IAEA,CAAI,EAAgB,CAAK,KAAK,EAAM,QAAQ,eAAe,EAAM,QAAQ,eACvE,EAAM,eAAe,GACrB,EAAS;GAJX;EAMF,GAEM,MAAiB,GAAsB,MAAwB;GACnE,IAAI,EAAY,CAAK,GAAG;IAEtB,AADA,EAAM,eAAe,GACrB,EAAU,EAAI;IACd;GACF;GAEA,IAAI,EAAgB,CAAK,GAAG;IAE1B,AADA,EAAM,eAAe,GACrB,EAAW,CAAI;IACf;GACF;GAEA,QAAQ,EAAM,KAAd;IACE,KAAK;KAEH,AADA,EAAM,eAAe,GACrB,EAAU,CAAC;KACX;IACF,KAAK;KAEH,AADA,EAAM,eAAe,GACrB,EAAU,EAAE;KACZ;IACF,KAAK;KAKH,AAJA,EAAM,eAAe,GACrB,EAAa,QAAQ,EAAa,MAAM,SAAS,IAC7C,EAAM,MAAM,QAAQ,EAAa,MAAM,EAAE,IACzC,GACJ,EAAU,EAAa,KAAK;KAC5B;IACF,KAAK;KAKH,AAJA,EAAM,eAAe,GACrB,EAAa,QAAQ,EAAa,MAAM,SAAS,IAC7C,EAAM,MAAM,QAAQ,EAAa,MAAM,EAAa,MAAM,SAAS,EAAE,IACrE,EAAM,MAAM,SAAS,GACzB,EAAU,EAAa,KAAK;KAC5B;IACF,SACE;GACJ;EACF,GAEM,KAAyB,MAAwB;GACrD,IAAI,CAAC,EAAO,OAAO;GACnB,IAAM,IAAS,EAAM;GACf,aAAkB,SACpB,EAAQ,OAAO,SAAS,CAAM,KAClC,EAAU;EACZ;SAEA,EAAM,IAAS,MAAU;GACvB,AAAI,IACF,SAAS,iBAAiB,eAAe,CAAqB,IAE9D,SAAS,oBAAoB,eAAe,CAAqB;EAErE,CAAC,GAED,QAAsB;GACpB,SAAS,oBAAoB,eAAe,CAAqB;EACnE,CAAC,mBAIC,EA2EM,OAAA;YA1EA;GAAJ,KAAI;GACH,OAAK,EAAE,EAAA,KAAW;GAClB,OAAK,EAAE,EAAA,KAAS;GAChB,cAAY,EAAA,CAAA,IAAM,SAAA;MAEnB,EAmCO,QAAA;YAlCD;GAAJ,KAAI;GACJ,OAAM;GACL,SAAO;GACP,WAAS;MAEV,EA4BO,EAAA,QAAA,WAAA;GA1BJ,QAAS,EAAA,CAAA;GACT,QAAS,EAAA,CAAA;WAyBL,CAvBL,EAsBS,UAtBT,GACU,EAqBD,OArBa;GACpB,MAAK;GACL,OAAM;GACL,UAAU,EAAA;GACV,iBAAe,EAAA,CAAA,IAAS,EAAA,CAAA,IAAS,KAAA;GAClC,iBAAc;GACb,iBAAe,EAAA,CAAA;OAEhB,EAAkD,QAAlD,GAAkD,EAAf,EAAA,KAAK,GAAA,CAAA,GAAA,AAAA,EAAA,OACxC,EAWM,OAAA;GAVJ,OAAM;GACN,SAAQ;GACR,MAAK;GACL,QAAO;GACP,gBAAa;GACb,kBAAe;GACf,mBAAgB;GAChB,eAAY;MAEZ,EAAmC,YAAA,EAAzB,QAAO,gBAAe,CAAA,CAAA,GAAA,EAAA,CAAA,GAAA,IAAA,CAAA,CAAA,CAAA,CAAA,GAAA,GAAA,GAKxC,EAgCa,GAAA,EAhCD,MAAK,SAAQ,GAAA;oBA+BlB,CA7BG,EAAA,CAAA,KAAM,CAAK,EAAA,YAAA,EAAA,GADnB,EA8BK,MAAA;;IA5BF,IAAI,EAAA,CAAA;IACL,MAAK;IACL,OAAM;IACL,cAAY,EAAA,SAAS,KAAA;eAEtB,EAsBK,GAAA,MAAA,EArBqB,EAAA,QAAhB,GAAM,YADhB,EAsBK,MAAA;IApBF,KAAK,EAAK;;IACV,MAAM,MAAO,GAAW,GAAsB,EAAK,KAAK;IACzD,MAAK;IACL,OAAK,EAAA,CAAC,oBAAkB;oBACa,EAAK;mBAAoC,MAAU,EAAA;;IAIvF,iBAAe,EAAK,YAAY,KAAA;IAChC,UAAU,EAAK,WAAQ,KAAA;IACvB,UAAK,MAAE,EAAW,CAAI;IACtB,YAAO,MAAE,GAAc,GAAQ,CAAI;OAEpC,EAMO,EAAA,QAAA,QAAA;IAJE;IACC;YAGH,CAAA,EAAA,EADF,EAAK,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,IAAA,CAAA"}
@@ -0,0 +1,2 @@
1
+ var e=require("./TFlag.vue_vue_type_script_setup_true_lang.cjs").default;exports.default=e;
2
+ //# sourceMappingURL=TFlag.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TFlag.cjs","names":[],"sources":["../../src/components/TFlag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue';\nimport type { TSize } from '../types/contracts';\n\n/**\n * Flags are requested from the CDN's fixed-height endpoints, which serve the\n * flat artwork at each flag's true proportions — Nepal stays a pennant and\n * Switzerland stays square. The CDN's 4:3 endpoints would normalise every ratio,\n * but only by switching to the waving artwork, which reads as decoration next to\n * flat UI icons. A common height is what actually aligns a column of flags; the\n * varying widths are absorbed by the fixed box in CSS.\n *\n * Each step's retina asset is at least twice its box height so 2x screens never\n * upscale.\n */\nconst FLAG_ASSETS: Record<TSize, { base: string; retina: string }> = {\n sm: { base: 'h20', retina: 'h40' },\n md: { base: 'h20', retina: 'h40' },\n lg: { base: 'h24', retina: 'h60' },\n};\n\nconst props = withDefaults(\n defineProps<{\n /** ISO 3166-1 alpha-2 country code. Case-insensitive. */\n code: string;\n /** Origin serving the flag assets. Point at a mirror to self-host. */\n baseUrl?: string;\n size?: TSize;\n /** Set to expose the flag to assistive tech; omit to keep it decorative. */\n label?: string;\n /** Text shown when the image cannot load. Defaults to the uppercased code. */\n fallbackText?: string;\n }>(),\n {\n baseUrl: 'https://flagcdn.com',\n size: 'md',\n label: undefined,\n fallbackText: undefined,\n },\n);\n\nconst classes = computed(() => [\n 't-flag',\n `t-flag--${props.size}`,\n]);\n\nconst normalizedCode = computed(() => props.code.trim().toLowerCase());\n\n// A JS consumer can hand us a size outside the union; fall back rather than\n// throwing on an undefined lookup.\nconst assets = computed(() => FLAG_ASSETS[props.size] ?? FLAG_ASSETS.md);\n\n// Tolerate a baseUrl written with a trailing slash so a self-hosted mirror does\n// not silently produce a double-slashed path.\nconst origin = computed(() => props.baseUrl.replace(/\\/+$/, ''));\n\nconst src = computed(\n () => `${origin.value}/${assets.value.base}/${normalizedCode.value}.png`,\n);\n\nconst srcset = computed(\n () => `${origin.value}/${assets.value.retina}/${normalizedCode.value}.png 2x`,\n);\n\nconst resolvedFallback = computed(\n () => props.fallbackText ?? normalizedCode.value.toUpperCase(),\n);\n\nconst failed = ref(false);\n\n// A new source deserves a fresh attempt — otherwise one bad code would leave the\n// component stuck on the fallback for every later flag.\nwatch(src, () => {\n failed.value = false;\n});\n\nconst onError = () => {\n failed.value = true;\n};\n</script>\n\n<template>\n <span\n :class=\"classes\"\n :role=\"label ? 'img' : undefined\"\n :aria-label=\"label || undefined\"\n :aria-hidden=\"label ? undefined : 'true'\"\n >\n <img\n v-if=\"!failed\"\n :src=\"src\"\n :srcset=\"srcset\"\n alt=\"\"\n class=\"t-flag__image\"\n @error=\"onError\"\n >\n <!--\n Flags come from a third-party origin, so the request can fail offline or\n behind a strict img-src policy. Showing the country code keeps the control\n legible instead of collapsing it to an empty box.\n -->\n <span\n v-else\n class=\"t-flag__fallback\"\n >\n {{ resolvedFallback }}\n </span>\n </span>\n</template>\n"],"mappings":""}
@@ -0,0 +1,7 @@
1
+ import e from "./TFlag.vue_vue_type_script_setup_true_lang.js";
2
+ //#region src/components/TFlag.vue
3
+ var t = e;
4
+ //#endregion
5
+ export { t as default };
6
+
7
+ //# sourceMappingURL=TFlag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TFlag.js","names":[],"sources":["../../src/components/TFlag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue';\nimport type { TSize } from '../types/contracts';\n\n/**\n * Flags are requested from the CDN's fixed-height endpoints, which serve the\n * flat artwork at each flag's true proportions — Nepal stays a pennant and\n * Switzerland stays square. The CDN's 4:3 endpoints would normalise every ratio,\n * but only by switching to the waving artwork, which reads as decoration next to\n * flat UI icons. A common height is what actually aligns a column of flags; the\n * varying widths are absorbed by the fixed box in CSS.\n *\n * Each step's retina asset is at least twice its box height so 2x screens never\n * upscale.\n */\nconst FLAG_ASSETS: Record<TSize, { base: string; retina: string }> = {\n sm: { base: 'h20', retina: 'h40' },\n md: { base: 'h20', retina: 'h40' },\n lg: { base: 'h24', retina: 'h60' },\n};\n\nconst props = withDefaults(\n defineProps<{\n /** ISO 3166-1 alpha-2 country code. Case-insensitive. */\n code: string;\n /** Origin serving the flag assets. Point at a mirror to self-host. */\n baseUrl?: string;\n size?: TSize;\n /** Set to expose the flag to assistive tech; omit to keep it decorative. */\n label?: string;\n /** Text shown when the image cannot load. Defaults to the uppercased code. */\n fallbackText?: string;\n }>(),\n {\n baseUrl: 'https://flagcdn.com',\n size: 'md',\n label: undefined,\n fallbackText: undefined,\n },\n);\n\nconst classes = computed(() => [\n 't-flag',\n `t-flag--${props.size}`,\n]);\n\nconst normalizedCode = computed(() => props.code.trim().toLowerCase());\n\n// A JS consumer can hand us a size outside the union; fall back rather than\n// throwing on an undefined lookup.\nconst assets = computed(() => FLAG_ASSETS[props.size] ?? FLAG_ASSETS.md);\n\n// Tolerate a baseUrl written with a trailing slash so a self-hosted mirror does\n// not silently produce a double-slashed path.\nconst origin = computed(() => props.baseUrl.replace(/\\/+$/, ''));\n\nconst src = computed(\n () => `${origin.value}/${assets.value.base}/${normalizedCode.value}.png`,\n);\n\nconst srcset = computed(\n () => `${origin.value}/${assets.value.retina}/${normalizedCode.value}.png 2x`,\n);\n\nconst resolvedFallback = computed(\n () => props.fallbackText ?? normalizedCode.value.toUpperCase(),\n);\n\nconst failed = ref(false);\n\n// A new source deserves a fresh attempt — otherwise one bad code would leave the\n// component stuck on the fallback for every later flag.\nwatch(src, () => {\n failed.value = false;\n});\n\nconst onError = () => {\n failed.value = true;\n};\n</script>\n\n<template>\n <span\n :class=\"classes\"\n :role=\"label ? 'img' : undefined\"\n :aria-label=\"label || undefined\"\n :aria-hidden=\"label ? undefined : 'true'\"\n >\n <img\n v-if=\"!failed\"\n :src=\"src\"\n :srcset=\"srcset\"\n alt=\"\"\n class=\"t-flag__image\"\n @error=\"onError\"\n >\n <!--\n Flags come from a third-party origin, so the request can fail offline or\n behind a strict img-src policy. Showing the country code keeps the control\n legible instead of collapsing it to an empty box.\n -->\n <span\n v-else\n class=\"t-flag__fallback\"\n >\n {{ resolvedFallback }}\n </span>\n </span>\n</template>\n"],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import { TSize } from '../types/contracts';
2
+ type __VLS_Props = {
3
+ /** ISO 3166-1 alpha-2 country code. Case-insensitive. */
4
+ code: string;
5
+ /** Origin serving the flag assets. Point at a mirror to self-host. */
6
+ baseUrl?: string;
7
+ size?: TSize;
8
+ /** Set to expose the flag to assistive tech; omit to keep it decorative. */
9
+ label?: string;
10
+ /** Text shown when the image cannot load. Defaults to the uppercased code. */
11
+ fallbackText?: string;
12
+ };
13
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
14
+ size: TSize;
15
+ label: string;
16
+ baseUrl: string;
17
+ fallbackText: string;
18
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLSpanElement>;
19
+ export default _default;
20
+ //# sourceMappingURL=TFlag.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TFlag.vue.d.ts","sourceRoot":"","sources":["../../src/components/TFlag.vue"],"names":[],"mappings":"AAgHA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAmBhD,KAAK,WAAW,GAAG;IACf,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;;UALO,KAAK;WAEJ,MAAM;aAHJ,MAAM;kBAKD,MAAM;;AAuHzB,wBAQG"}
@@ -0,0 +1,2 @@
1
+ let e=require("vue");var t=[`role`,`aria-label`,`aria-hidden`],n=[`src`,`srcset`],r={key:1,class:`t-flag__fallback`},i=(0,e.defineComponent)({__name:`TFlag`,props:{code:{},baseUrl:{default:`https://flagcdn.com`},size:{default:`md`},label:{default:void 0},fallbackText:{default:void 0}},setup(i){let a={sm:{base:`h20`,retina:`h40`},md:{base:`h20`,retina:`h40`},lg:{base:`h24`,retina:`h60`}},o=i,s=(0,e.computed)(()=>[`t-flag`,`t-flag--${o.size}`]),c=(0,e.computed)(()=>o.code.trim().toLowerCase()),l=(0,e.computed)(()=>a[o.size]??a.md),u=(0,e.computed)(()=>o.baseUrl.replace(/\/+$/,``)),d=(0,e.computed)(()=>`${u.value}/${l.value.base}/${c.value}.png`),f=(0,e.computed)(()=>`${u.value}/${l.value.retina}/${c.value}.png 2x`),p=(0,e.computed)(()=>o.fallbackText??c.value.toUpperCase()),m=(0,e.ref)(!1);(0,e.watch)(d,()=>{m.value=!1});let h=()=>{m.value=!0};return(a,o)=>((0,e.openBlock)(),(0,e.createElementBlock)(`span`,{class:(0,e.normalizeClass)(s.value),role:i.label?`img`:void 0,"aria-label":i.label||void 0,"aria-hidden":i.label?void 0:`true`},[m.value?((0,e.openBlock)(),(0,e.createElementBlock)(`span`,r,(0,e.toDisplayString)(p.value),1)):((0,e.openBlock)(),(0,e.createElementBlock)(`img`,{key:0,src:d.value,srcset:f.value,alt:``,class:`t-flag__image`,onError:h},null,40,n))],10,t))}});exports.default=i;
2
+ //# sourceMappingURL=TFlag.vue_vue_type_script_setup_true_lang.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TFlag.vue_vue_type_script_setup_true_lang.cjs","names":[],"sources":["../../src/components/TFlag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue';\nimport type { TSize } from '../types/contracts';\n\n/**\n * Flags are requested from the CDN's fixed-height endpoints, which serve the\n * flat artwork at each flag's true proportions — Nepal stays a pennant and\n * Switzerland stays square. The CDN's 4:3 endpoints would normalise every ratio,\n * but only by switching to the waving artwork, which reads as decoration next to\n * flat UI icons. A common height is what actually aligns a column of flags; the\n * varying widths are absorbed by the fixed box in CSS.\n *\n * Each step's retina asset is at least twice its box height so 2x screens never\n * upscale.\n */\nconst FLAG_ASSETS: Record<TSize, { base: string; retina: string }> = {\n sm: { base: 'h20', retina: 'h40' },\n md: { base: 'h20', retina: 'h40' },\n lg: { base: 'h24', retina: 'h60' },\n};\n\nconst props = withDefaults(\n defineProps<{\n /** ISO 3166-1 alpha-2 country code. Case-insensitive. */\n code: string;\n /** Origin serving the flag assets. Point at a mirror to self-host. */\n baseUrl?: string;\n size?: TSize;\n /** Set to expose the flag to assistive tech; omit to keep it decorative. */\n label?: string;\n /** Text shown when the image cannot load. Defaults to the uppercased code. */\n fallbackText?: string;\n }>(),\n {\n baseUrl: 'https://flagcdn.com',\n size: 'md',\n label: undefined,\n fallbackText: undefined,\n },\n);\n\nconst classes = computed(() => [\n 't-flag',\n `t-flag--${props.size}`,\n]);\n\nconst normalizedCode = computed(() => props.code.trim().toLowerCase());\n\n// A JS consumer can hand us a size outside the union; fall back rather than\n// throwing on an undefined lookup.\nconst assets = computed(() => FLAG_ASSETS[props.size] ?? FLAG_ASSETS.md);\n\n// Tolerate a baseUrl written with a trailing slash so a self-hosted mirror does\n// not silently produce a double-slashed path.\nconst origin = computed(() => props.baseUrl.replace(/\\/+$/, ''));\n\nconst src = computed(\n () => `${origin.value}/${assets.value.base}/${normalizedCode.value}.png`,\n);\n\nconst srcset = computed(\n () => `${origin.value}/${assets.value.retina}/${normalizedCode.value}.png 2x`,\n);\n\nconst resolvedFallback = computed(\n () => props.fallbackText ?? normalizedCode.value.toUpperCase(),\n);\n\nconst failed = ref(false);\n\n// A new source deserves a fresh attempt — otherwise one bad code would leave the\n// component stuck on the fallback for every later flag.\nwatch(src, () => {\n failed.value = false;\n});\n\nconst onError = () => {\n failed.value = true;\n};\n</script>\n\n<template>\n <span\n :class=\"classes\"\n :role=\"label ? 'img' : undefined\"\n :aria-label=\"label || undefined\"\n :aria-hidden=\"label ? undefined : 'true'\"\n >\n <img\n v-if=\"!failed\"\n :src=\"src\"\n :srcset=\"srcset\"\n alt=\"\"\n class=\"t-flag__image\"\n @error=\"onError\"\n >\n <!--\n Flags come from a third-party origin, so the request can fail offline or\n behind a strict img-src policy. Showing the country code keeps the control\n legible instead of collapsing it to an empty box.\n -->\n <span\n v-else\n class=\"t-flag__fallback\"\n >\n {{ resolvedFallback }}\n </span>\n </span>\n</template>\n"],"mappings":"uSAeA,IAAM,EAA+D,CACnE,GAAI,CAAE,KAAM,MAAO,OAAQ,KAAM,EACjC,GAAI,CAAE,KAAM,MAAO,OAAQ,KAAM,EACjC,GAAI,CAAE,KAAM,MAAO,OAAQ,KAAM,CACnC,EAEM,EAAQ,EAoBR,GAAA,EAAA,EAAA,SAAA,KAAyB,CAC7B,SACA,WAAW,EAAM,MACnB,CAAC,EAEK,GAAA,EAAA,EAAA,SAAA,KAAgC,EAAM,KAAK,KAAK,CAAC,CAAC,YAAY,CAAC,EAI/D,GAAA,EAAA,EAAA,SAAA,KAAwB,EAAY,EAAM,OAAS,EAAY,EAAE,EAIjE,GAAA,EAAA,EAAA,SAAA,KAAwB,EAAM,QAAQ,QAAQ,OAAQ,EAAE,CAAC,EAEzD,GAAA,EAAA,EAAA,SAAA,KACE,GAAG,EAAO,MAAM,GAAG,EAAO,MAAM,KAAK,GAAG,EAAe,MAAM,KACrE,EAEM,GAAA,EAAA,EAAA,SAAA,KACE,GAAG,EAAO,MAAM,GAAG,EAAO,MAAM,OAAO,GAAG,EAAe,MAAM,QACvE,EAEM,GAAA,EAAA,EAAA,SAAA,KACE,EAAM,cAAgB,EAAe,MAAM,YAAY,CAC/D,EAEM,GAAA,EAAA,EAAA,IAAA,CAAa,EAAK,GAIxB,EAAA,EAAA,MAAA,CAAM,MAAW,CACf,EAAO,MAAQ,EACjB,CAAC,EAED,IAAM,MAAgB,CACpB,EAAO,MAAQ,EACjB,2DA6BS,OAAA,CAxBJ,OAAA,EAAA,EAAA,eAAA,CAAO,EAAA,KAAO,EACd,KAAM,EAAA,MAAK,MAAW,IAAA,GACtB,aAAY,EAAA,OAAS,IAAA,GACrB,cAAa,EAAA,MAAQ,IAAA,GAAS,SAGtB,EAAA,kDAiBF,OALP,GAAA,EAAA,EAAA,gBAAA,CAIK,EAAA,KAAgB,EAAA,CAAA,KAhBZ,EAAA,EAAA,UAAA,CAAA,GAAA,EAAA,EAAA,mBAAA,CAMR,MAAA,OALE,IAAK,EAAA,MACL,OAAQ,EAAA,MACT,IAAI,GACJ,MAAM,gBACE,sBAWW,EAAA,GAAA,CAAA"}
@@ -0,0 +1,58 @@
1
+ import { computed as e, createElementBlock as t, defineComponent as n, normalizeClass as r, openBlock as i, ref as a, toDisplayString as o, watch as s } from "vue";
2
+ //#region src/components/TFlag.vue?vue&type=script&setup=true&lang.ts
3
+ var c = [
4
+ "role",
5
+ "aria-label",
6
+ "aria-hidden"
7
+ ], l = ["src", "srcset"], u = {
8
+ key: 1,
9
+ class: "t-flag__fallback"
10
+ }, d = /*@__PURE__*/ n({
11
+ __name: "TFlag",
12
+ props: {
13
+ code: {},
14
+ baseUrl: { default: "https://flagcdn.com" },
15
+ size: { default: "md" },
16
+ label: { default: void 0 },
17
+ fallbackText: { default: void 0 }
18
+ },
19
+ setup(n) {
20
+ let d = {
21
+ sm: {
22
+ base: "h20",
23
+ retina: "h40"
24
+ },
25
+ md: {
26
+ base: "h20",
27
+ retina: "h40"
28
+ },
29
+ lg: {
30
+ base: "h24",
31
+ retina: "h60"
32
+ }
33
+ }, f = n, p = e(() => ["t-flag", `t-flag--${f.size}`]), m = e(() => f.code.trim().toLowerCase()), h = e(() => d[f.size] ?? d.md), g = e(() => f.baseUrl.replace(/\/+$/, "")), _ = e(() => `${g.value}/${h.value.base}/${m.value}.png`), v = e(() => `${g.value}/${h.value.retina}/${m.value}.png 2x`), y = e(() => f.fallbackText ?? m.value.toUpperCase()), b = a(!1);
34
+ s(_, () => {
35
+ b.value = !1;
36
+ });
37
+ let x = () => {
38
+ b.value = !0;
39
+ };
40
+ return (e, a) => (i(), t("span", {
41
+ class: r(p.value),
42
+ role: n.label ? "img" : void 0,
43
+ "aria-label": n.label || void 0,
44
+ "aria-hidden": n.label ? void 0 : "true"
45
+ }, [b.value ? (i(), t("span", u, o(y.value), 1)) : (i(), t("img", {
46
+ key: 0,
47
+ src: _.value,
48
+ srcset: v.value,
49
+ alt: "",
50
+ class: "t-flag__image",
51
+ onError: x
52
+ }, null, 40, l))], 10, c));
53
+ }
54
+ });
55
+ //#endregion
56
+ export { d as default };
57
+
58
+ //# sourceMappingURL=TFlag.vue_vue_type_script_setup_true_lang.js.map