@eos-ui/vue 0.5.1 → 0.5.3

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 (34) hide show
  1. package/dist/components/AppShell/EAppShell.js.map +1 -1
  2. package/dist/components/AppShell/EAppShell.vue_vue_type_script_setup_true_lang.js.map +1 -1
  3. package/dist/components/Avatar/EAvatar.js.map +1 -1
  4. package/dist/components/Avatar/EAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  5. package/dist/components/Button/EButton.js.map +1 -1
  6. package/dist/components/Button/EButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/components/Combobox/EComboboxBase.js.map +1 -1
  8. package/dist/components/Combobox/EComboboxBase.vue_vue_type_script_setup_true_lang.js.map +1 -1
  9. package/dist/components/DataGrid/EDataGrid.js.map +1 -1
  10. package/dist/components/DataGrid/EDataGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  11. package/dist/components/NavList/ENavList.js.map +1 -1
  12. package/dist/components/NavList/ENavList.vue_vue_type_script_setup_true_lang.js.map +1 -1
  13. package/dist/components/Notice/ENotice.js.map +1 -1
  14. package/dist/components/Notice/ENotice.vue_vue_type_script_setup_true_lang.js.map +1 -1
  15. package/dist/components/Progress/EProgress.js.map +1 -1
  16. package/dist/components/Progress/EProgress.vue_vue_type_script_setup_true_lang.js.map +1 -1
  17. package/dist/components/SearchBar/ESearchBar.js.map +1 -1
  18. package/dist/components/SearchBar/ESearchBar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  19. package/dist/components/Segmented/ESegmented.js.map +1 -1
  20. package/dist/components/Segmented/ESegmented.vue_vue_type_script_setup_true_lang.js.map +1 -1
  21. package/dist/components/Select/ESelectControl.js.map +1 -1
  22. package/dist/components/Select/ESelectControl.vue_vue_type_script_setup_true_lang.js.map +1 -1
  23. package/dist/components/SignaturePad/ESignaturePad.js.map +1 -1
  24. package/dist/components/SignaturePad/ESignaturePad.vue_vue_type_script_setup_true_lang.js.map +1 -1
  25. package/dist/components/Stepper/EStepper.js.map +1 -1
  26. package/dist/components/Stepper/EStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
  27. package/dist/components/Switch/ESwitch.js.map +1 -1
  28. package/dist/components/Switch/ESwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  29. package/dist/components/Tabs/ETabs.js.map +1 -1
  30. package/dist/components/Tabs/ETabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  31. package/dist/components/Textarea/ETextarea.js.map +1 -1
  32. package/dist/components/Textarea/ETextarea.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/style.css +179 -156
  34. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"EAppShell.js","names":["_sfc_main","EAppShell_vue_vue_type_script_setup_true_lang_default","EAppShell_default"],"sources":["../../../src/components/AppShell/EAppShell.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport ESkipLink from \"../SkipLink/ESkipLink.vue\";\nimport { useMessages } from \"../../config.js\";\nimport \"../../styles/base.css\";\n\nwithDefaults(\n defineProps<{\n /** The `id` of the `main` element, which the skip link targets. Keep it unique. */\n mainId?: string;\n /** The name of the sidebar landmark. @default \"Main\" */\n sidebarLabel?: string;\n }>(),\n { mainId: \"main\" },\n);\n\ndefineSlots<{\n /** An EAppHeader. */\n header?(): unknown;\n /** The side navigation, usually an ENavList. Two columns from 48rem wide; above the content below that. */\n sidebar?(): unknown;\n /** An EAppFooter. */\n footer?(): unknown;\n /** The page: start it with an EPageHeader. */\n default?(): unknown;\n}>();\n\nconst t = useMessages();\n</script>\n\n<template>\n <div class=\"e-shell\" :class=\"$slots.sidebar && 'e-shell--side'\">\n <ESkipLink :href=\"`#${mainId}`\" />\n <slot name=\"header\" />\n <div class=\"e-shell-body\">\n <aside v-if=\"$slots.sidebar\" class=\"e-shell-side\" :aria-label=\"sidebarLabel || t('mainNav')\">\n <slot name=\"sidebar\" />\n </aside>\n <main :id=\"mainId\" class=\"e-shell-main\" tabindex=\"-1\">\n <slot />\n </main>\n </div>\n <slot name=\"footer\" />\n </div>\n</template>\n\n<style>\n@layer e.page {\n .e-shell {\n position: relative;\n display: grid;\n grid-template-rows: auto 1fr auto;\n min-height: 100%;\n background: var(--e-background);\n }\n\n .e-shell-body {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--e-space-6);\n width: 100%;\n max-width: var(--e-shell-width, 72rem);\n margin-inline: auto;\n padding: var(--e-space-6) var(--e-space-4);\n }\n\n /* Hairlines down both edges of the page column, drawn over the header and footer. */\n @media (min-width: 64rem) {\n .e-shell::after {\n content: \"\";\n position: absolute;\n inset-block: 0;\n inset-inline: 0;\n z-index: var(--e-z-sticky);\n box-sizing: border-box;\n width: min(100%, var(--e-shell-width, 72rem));\n margin-inline: auto;\n border-inline: var(--e-stroke-hair) solid var(--e-shell-rail, var(--e-border));\n pointer-events: none;\n }\n }\n\n @media (min-width: 48rem) {\n .e-shell--side .e-shell-body {\n grid-template-columns: 15rem minmax(0, 1fr);\n }\n }\n\n .e-shell-main {\n min-width: 0;\n }\n\n .e-shell-main:focus:not(:focus-visible) {\n outline: none;\n }\n\n .e-shell-main:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: calc(-1 * var(--e-stroke-focus));\n }\n\n @media print {\n .e-root,\n body {\n background: var(--e-print-paper, #fff);\n color: var(--e-print-ink, #000);\n }\n\n .e-shell::after,\n .e-shell-side {\n display: none;\n }\n\n .e-shell-body {\n max-width: none;\n padding: 0;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"EAppShell.js","names":["_sfc_main","EAppShell_vue_vue_type_script_setup_true_lang_default","EAppShell_default"],"sources":["../../../src/components/AppShell/EAppShell.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport ESkipLink from \"../SkipLink/ESkipLink.vue\";\nimport { useMessages } from \"../../config.js\";\nimport \"../../styles/base.css\";\n\nwithDefaults(\n defineProps<{\n /** The `id` of the `main` element, which the skip link targets. Keep it unique. */\n mainId?: string;\n /** The name of the sidebar landmark. @default \"Main\" */\n sidebarLabel?: string;\n }>(),\n { mainId: \"main\" },\n);\n\ndefineSlots<{\n /** An EAppHeader. */\n header?(): unknown;\n /** The side navigation, usually an ENavList. Two columns from 48rem wide; above the content below that. */\n sidebar?(): unknown;\n /** An EAppFooter. */\n footer?(): unknown;\n /** The page: start it with an EPageHeader. */\n default?(): unknown;\n}>();\n\nconst t = useMessages();\n</script>\n\n<template>\n <div class=\"e-shell\" :class=\"$slots.sidebar && 'e-shell--side'\">\n <ESkipLink :href=\"`#${mainId}`\" />\n <slot name=\"header\" />\n <div class=\"e-shell-body\">\n <aside v-if=\"$slots.sidebar\" class=\"e-shell-side\" :aria-label=\"sidebarLabel || t('mainNav')\">\n <slot name=\"sidebar\" />\n </aside>\n <main :id=\"mainId\" class=\"e-shell-main\" tabindex=\"-1\">\n <slot />\n </main>\n </div>\n <slot name=\"footer\" />\n </div>\n</template>\n\n<style>\n@layer e.page {\n .e-shell {\n position: relative;\n overflow-x: clip;\n display: grid;\n grid-template-rows: auto 1fr auto;\n min-height: 100%;\n background: var(--e-background);\n }\n\n .e-shell-body {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--e-space-6);\n width: 100%;\n max-width: var(--e-shell-width, 72rem);\n margin-inline: auto;\n padding: var(--e-space-6) var(--e-space-4);\n }\n\n /* Hairlines just outside both edges of the page column, drawn over the header and footer. When the column fills the screen they fall off it and nothing shows. */\n .e-shell::after {\n content: \"\";\n position: absolute;\n inset-block: 0;\n inset-inline: 0;\n z-index: var(--e-z-sticky);\n width: min(100%, var(--e-shell-width, 72rem));\n margin-inline: auto;\n box-shadow:\n calc(-1 * var(--e-stroke-hair)) 0 0 0 var(--e-shell-rail, var(--e-border)),\n var(--e-stroke-hair) 0 0 0 var(--e-shell-rail, var(--e-border));\n pointer-events: none;\n }\n\n @media (min-width: 48rem) {\n .e-shell--side .e-shell-body {\n grid-template-columns: 15rem minmax(0, 1fr);\n }\n }\n\n .e-shell-main {\n min-width: 0;\n }\n\n .e-shell-main:focus:not(:focus-visible) {\n outline: none;\n }\n\n .e-shell-main:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: calc(-1 * var(--e-stroke-focus));\n }\n\n @media print {\n .e-root,\n body {\n background: var(--e-print-paper, #fff);\n color: var(--e-print-ink, #000);\n }\n\n .e-shell::after,\n .e-shell-side {\n display: none;\n }\n\n .e-shell-body {\n max-width: none;\n padding: 0;\n }\n }\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"EAppShell.vue_vue_type_script_setup_true_lang.js","names":["$slots","_openBlock","_createElementBlock","_normalizeClass","_createVNode","ESkipLink","_renderSlot","_createElementVNode","_unref","_createCommentVNode","ESkipLink_default","_hoisted_1","_hoisted_2","_hoisted_3","EAppShell_vue_vue_type_script_setup_true_lang_default","t","useMessages","openBlock","createElementBlock","normalizeClass","_ctx","createVNode","__props","renderSlot","createElementVNode","unref","createCommentVNode"],"sources":["../../../src/components/AppShell/EAppShell.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport ESkipLink from \"../SkipLink/ESkipLink.vue\";\nimport { useMessages } from \"../../config.js\";\nimport \"../../styles/base.css\";\n\nwithDefaults(\n defineProps<{\n /** The `id` of the `main` element, which the skip link targets. Keep it unique. */\n mainId?: string;\n /** The name of the sidebar landmark. @default \"Main\" */\n sidebarLabel?: string;\n }>(),\n { mainId: \"main\" },\n);\n\ndefineSlots<{\n /** An EAppHeader. */\n header?(): unknown;\n /** The side navigation, usually an ENavList. Two columns from 48rem wide; above the content below that. */\n sidebar?(): unknown;\n /** An EAppFooter. */\n footer?(): unknown;\n /** The page: start it with an EPageHeader. */\n default?(): unknown;\n}>();\n\nconst t = useMessages();\n</script>\n\n<template>\n <div class=\"e-shell\" :class=\"$slots.sidebar && 'e-shell--side'\">\n <ESkipLink :href=\"`#${mainId}`\" />\n <slot name=\"header\" />\n <div class=\"e-shell-body\">\n <aside v-if=\"$slots.sidebar\" class=\"e-shell-side\" :aria-label=\"sidebarLabel || t('mainNav')\">\n <slot name=\"sidebar\" />\n </aside>\n <main :id=\"mainId\" class=\"e-shell-main\" tabindex=\"-1\">\n <slot />\n </main>\n </div>\n <slot name=\"footer\" />\n </div>\n</template>\n\n<style>\n@layer e.page {\n .e-shell {\n position: relative;\n display: grid;\n grid-template-rows: auto 1fr auto;\n min-height: 100%;\n background: var(--e-background);\n }\n\n .e-shell-body {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--e-space-6);\n width: 100%;\n max-width: var(--e-shell-width, 72rem);\n margin-inline: auto;\n padding: var(--e-space-6) var(--e-space-4);\n }\n\n /* Hairlines down both edges of the page column, drawn over the header and footer. */\n @media (min-width: 64rem) {\n .e-shell::after {\n content: \"\";\n position: absolute;\n inset-block: 0;\n inset-inline: 0;\n z-index: var(--e-z-sticky);\n box-sizing: border-box;\n width: min(100%, var(--e-shell-width, 72rem));\n margin-inline: auto;\n border-inline: var(--e-stroke-hair) solid var(--e-shell-rail, var(--e-border));\n pointer-events: none;\n }\n }\n\n @media (min-width: 48rem) {\n .e-shell--side .e-shell-body {\n grid-template-columns: 15rem minmax(0, 1fr);\n }\n }\n\n .e-shell-main {\n min-width: 0;\n }\n\n .e-shell-main:focus:not(:focus-visible) {\n outline: none;\n }\n\n .e-shell-main:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: calc(-1 * var(--e-stroke-focus));\n }\n\n @media print {\n .e-root,\n body {\n background: var(--e-print-paper, #fff);\n color: var(--e-print-ink, #000);\n }\n\n .e-shell::after,\n .e-shell-side {\n display: none;\n }\n\n .e-shell-body {\n max-width: none;\n padding: 0;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;EA0BA,IAAMe,IAAIC,EAAY;E,kBAIpBf,EAAA,GAAAC,EAYM,OAAA,EAZD,OAAKC,EAAA,CAAC,WAAkBH,EAAAA,OAAO,WAAO,eAAA,CAAA,E;GACzCI,EAAkCC,GAAA,EAAtB,MAAI,IAAMiB,EAAA,S;GACtBhB,EAAsBc,EAAA,QAAA,QAAA;GACtBb,EAOM,OAPNI,GAOM,CANSX,EAAAA,OAAO,WAApBC,EAAA,GAAAC,EAEQ,SAAA;;IAFqB,OAAM;IAAgB,cAAYoB,EAAA,gBAAgBd,EAAAO,CAAA,CAAC,CAAA,SAAA;G,IAC9ET,EAAuBc,EAAA,QAAA,SAAA,C,uBAEzBb,EAEO,QAAA;IAFA,IAAIe,EAAA;IAAQ,OAAM;IAAe,UAAS;G,IAC/ChB,EAAQc,EAAA,QAAA,SAAA,C;GAGZd,EAAsBc,EAAA,QAAA,QAAA"}
1
+ {"version":3,"file":"EAppShell.vue_vue_type_script_setup_true_lang.js","names":["$slots","_openBlock","_createElementBlock","_normalizeClass","_createVNode","ESkipLink","_renderSlot","_createElementVNode","_unref","_createCommentVNode","ESkipLink_default","_hoisted_1","_hoisted_2","_hoisted_3","EAppShell_vue_vue_type_script_setup_true_lang_default","t","useMessages","openBlock","createElementBlock","normalizeClass","_ctx","createVNode","__props","renderSlot","createElementVNode","unref","createCommentVNode"],"sources":["../../../src/components/AppShell/EAppShell.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport ESkipLink from \"../SkipLink/ESkipLink.vue\";\nimport { useMessages } from \"../../config.js\";\nimport \"../../styles/base.css\";\n\nwithDefaults(\n defineProps<{\n /** The `id` of the `main` element, which the skip link targets. Keep it unique. */\n mainId?: string;\n /** The name of the sidebar landmark. @default \"Main\" */\n sidebarLabel?: string;\n }>(),\n { mainId: \"main\" },\n);\n\ndefineSlots<{\n /** An EAppHeader. */\n header?(): unknown;\n /** The side navigation, usually an ENavList. Two columns from 48rem wide; above the content below that. */\n sidebar?(): unknown;\n /** An EAppFooter. */\n footer?(): unknown;\n /** The page: start it with an EPageHeader. */\n default?(): unknown;\n}>();\n\nconst t = useMessages();\n</script>\n\n<template>\n <div class=\"e-shell\" :class=\"$slots.sidebar && 'e-shell--side'\">\n <ESkipLink :href=\"`#${mainId}`\" />\n <slot name=\"header\" />\n <div class=\"e-shell-body\">\n <aside v-if=\"$slots.sidebar\" class=\"e-shell-side\" :aria-label=\"sidebarLabel || t('mainNav')\">\n <slot name=\"sidebar\" />\n </aside>\n <main :id=\"mainId\" class=\"e-shell-main\" tabindex=\"-1\">\n <slot />\n </main>\n </div>\n <slot name=\"footer\" />\n </div>\n</template>\n\n<style>\n@layer e.page {\n .e-shell {\n position: relative;\n overflow-x: clip;\n display: grid;\n grid-template-rows: auto 1fr auto;\n min-height: 100%;\n background: var(--e-background);\n }\n\n .e-shell-body {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--e-space-6);\n width: 100%;\n max-width: var(--e-shell-width, 72rem);\n margin-inline: auto;\n padding: var(--e-space-6) var(--e-space-4);\n }\n\n /* Hairlines just outside both edges of the page column, drawn over the header and footer. When the column fills the screen they fall off it and nothing shows. */\n .e-shell::after {\n content: \"\";\n position: absolute;\n inset-block: 0;\n inset-inline: 0;\n z-index: var(--e-z-sticky);\n width: min(100%, var(--e-shell-width, 72rem));\n margin-inline: auto;\n box-shadow:\n calc(-1 * var(--e-stroke-hair)) 0 0 0 var(--e-shell-rail, var(--e-border)),\n var(--e-stroke-hair) 0 0 0 var(--e-shell-rail, var(--e-border));\n pointer-events: none;\n }\n\n @media (min-width: 48rem) {\n .e-shell--side .e-shell-body {\n grid-template-columns: 15rem minmax(0, 1fr);\n }\n }\n\n .e-shell-main {\n min-width: 0;\n }\n\n .e-shell-main:focus:not(:focus-visible) {\n outline: none;\n }\n\n .e-shell-main:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: calc(-1 * var(--e-stroke-focus));\n }\n\n @media print {\n .e-root,\n body {\n background: var(--e-print-paper, #fff);\n color: var(--e-print-ink, #000);\n }\n\n .e-shell::after,\n .e-shell-side {\n display: none;\n }\n\n .e-shell-body {\n max-width: none;\n padding: 0;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;EA0BA,IAAMe,IAAIC,EAAY;E,kBAIpBf,EAAA,GAAAC,EAYM,OAAA,EAZD,OAAKC,EAAA,CAAC,WAAkBH,EAAAA,OAAO,WAAO,eAAA,CAAA,E;GACzCI,EAAkCC,GAAA,EAAtB,MAAI,IAAMiB,EAAA,S;GACtBhB,EAAsBc,EAAA,QAAA,QAAA;GACtBb,EAOM,OAPNI,GAOM,CANSX,EAAAA,OAAO,WAApBC,EAAA,GAAAC,EAEQ,SAAA;;IAFqB,OAAM;IAAgB,cAAYoB,EAAA,gBAAgBd,EAAAO,CAAA,CAAC,CAAA,SAAA;G,IAC9ET,EAAuBc,EAAA,QAAA,SAAA,C,uBAEzBb,EAEO,QAAA;IAFA,IAAIe,EAAA;IAAQ,OAAM;IAAe,UAAS;G,IAC/ChB,EAAQc,EAAA,QAAA,SAAA,C;GAGZd,EAAsBc,EAAA,QAAA,QAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"EAvatar.js","names":["_sfc_main","EAvatar_vue_vue_type_script_setup_true_lang_default","EAvatar_default"],"sources":["../../../src/components/Avatar/EAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from \"vue\";\nimport \"../../styles/base.css\";\n\nconst props = withDefaults(\n defineProps<{\n /** The person's name. Screen readers read it; the initials are the first letters of its first and last word. */\n name: string;\n /** A photo URL. If it fails to load, the initials appear. */\n src?: string;\n /** 32px, for rows and bars. */\n small?: boolean;\n /** 64px, for a profile or practitioner on an appointment card. The default is 44px. */\n large?: boolean;\n /** `button` renders a `button` with `type=\"button\"`, a pointer cursor and a focus ring, named by `name`, such as the `trigger` of an `EMenu`. */\n as?: \"span\" | \"button\";\n }>(),\n { as: \"span\" },\n);\n\nconst failed = ref(false);\nwatch(\n () => props.src,\n () => (failed.value = false),\n);\n\nconst initials = computed(() => {\n const parts = String(props.name || \"?\")\n .split(/\\s+/)\n .filter(Boolean);\n const first = [...(parts[0] ?? \"?\")][0] ?? \"?\";\n const last = parts.length > 1 ? ([...parts[parts.length - 1]!][0] ?? \"\") : \"\";\n return (first + last).toUpperCase();\n});\n</script>\n\n<template>\n <component\n :is=\"as\"\n class=\"e-avatar\"\n :class=\"{ 'e-avatar--s': small, 'e-avatar--l': large, 'e-avatar--button': as === 'button' }\"\n :type=\"as === 'button' ? 'button' : undefined\"\n :role=\"as === 'button' ? undefined : 'img'\"\n :aria-label=\"as === 'button' ? undefined : name\"\n >\n <img v-if=\"src && !failed\" class=\"e-avatar-img\" :src=\"src\" alt=\"\" @error=\"failed = true\" />\n <span v-else-if=\"as === 'button'\" aria-hidden=\"true\">{{ initials }}</span>\n <template v-else>{{ initials }}</template>\n <span v-if=\"as === 'button'\" class=\"e-sr\">{{ name }}</span>\n </component>\n</template>\n\n<style>\n@layer e.primitives {\n .e-avatar {\n --e-ring: var(--e-border-strong);\n\n position: relative;\n display: inline-grid;\n place-items: center;\n flex: none;\n box-sizing: border-box;\n width: var(--e-tap, 44px);\n height: var(--e-tap, 44px);\n overflow: hidden;\n border: 0;\n border-radius: var(--e-radius-md);\n background: var(--e-surface-tint);\n color: var(--e-primary);\n font: 600 var(--e-text-sm) / 1 var(--e-font-mono);\n letter-spacing: 0.02em;\n }\n\n /* The ring sits over the picture so an image never covers it. */\n .e-avatar::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-ring);\n pointer-events: none;\n transition: box-shadow var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-avatar--button {\n position: relative;\n padding: 0;\n cursor: pointer;\n }\n\n .e-avatar--button:hover {\n --e-ring: var(--e-ink);\n }\n\n .e-avatar--button:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-avatar--button {\n transition: none;\n }\n }\n\n .e-avatar--s {\n width: 32px;\n height: 32px;\n font-size: var(--e-text-xs);\n border-radius: var(--e-radius-sm);\n }\n\n .e-avatar--l {\n width: 64px;\n height: 64px;\n font-size: var(--e-text-lg);\n }\n\n .e-avatar-img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n @media (forced-colors: active) {\n .e-avatar {\n border-color: CanvasText;\n outline-color: CanvasText;\n color: CanvasText;\n }\n\n .e-avatar--button:focus-visible {\n outline-color: Highlight;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"EAvatar.js","names":["_sfc_main","EAvatar_vue_vue_type_script_setup_true_lang_default","EAvatar_default"],"sources":["../../../src/components/Avatar/EAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from \"vue\";\nimport \"../../styles/base.css\";\n\nconst props = withDefaults(\n defineProps<{\n /** The person's name. Screen readers read it; the initials are the first letters of its first and last word. */\n name: string;\n /** A photo URL. If it fails to load, the initials appear. */\n src?: string;\n /** 32px, for rows and bars. */\n small?: boolean;\n /** 64px, for a profile or practitioner on an appointment card. The default is 44px. */\n large?: boolean;\n /** `button` renders a `button` with `type=\"button\"`, a pointer cursor and a focus ring, named by `name`, such as the `trigger` of an `EMenu`. */\n as?: \"span\" | \"button\";\n }>(),\n { as: \"span\" },\n);\n\nconst failed = ref(false);\nwatch(\n () => props.src,\n () => (failed.value = false),\n);\n\nconst initials = computed(() => {\n const parts = String(props.name || \"?\")\n .split(/\\s+/)\n .filter(Boolean);\n const first = [...(parts[0] ?? \"?\")][0] ?? \"?\";\n const last = parts.length > 1 ? ([...parts[parts.length - 1]!][0] ?? \"\") : \"\";\n return (first + last).toUpperCase();\n});\n</script>\n\n<template>\n <component\n :is=\"as\"\n class=\"e-avatar\"\n :class=\"{ 'e-avatar--s': small, 'e-avatar--l': large, 'e-avatar--button': as === 'button' }\"\n :type=\"as === 'button' ? 'button' : undefined\"\n :role=\"as === 'button' ? undefined : 'img'\"\n :aria-label=\"as === 'button' ? undefined : name\"\n >\n <img v-if=\"src && !failed\" class=\"e-avatar-img\" :src=\"src\" alt=\"\" @error=\"failed = true\" />\n <span v-else-if=\"as === 'button'\" aria-hidden=\"true\">{{ initials }}</span>\n <template v-else>{{ initials }}</template>\n <span v-if=\"as === 'button'\" class=\"e-sr\">{{ name }}</span>\n </component>\n</template>\n\n<style>\n@layer e.primitives {\n .e-avatar {\n --e-ring: var(--e-border-strong);\n\n position: relative;\n display: inline-grid;\n place-items: center;\n flex: none;\n box-sizing: border-box;\n width: var(--e-tap, 44px);\n height: var(--e-tap, 44px);\n overflow: hidden;\n border: var(--e-stroke-edge) solid var(--e-ring);\n border-radius: var(--e-radius-md);\n background: var(--e-surface-tint);\n background-clip: padding-box;\n color: var(--e-primary);\n font: 600 var(--e-text-sm) / 1 var(--e-font-mono);\n letter-spacing: 0.02em;\n transition: border-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-avatar--button {\n position: relative;\n padding: 0;\n cursor: pointer;\n }\n\n .e-avatar--button:hover {\n --e-ring: var(--e-ink);\n }\n\n .e-avatar--button:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-avatar--button {\n transition: none;\n }\n }\n\n .e-avatar--s {\n width: 32px;\n height: 32px;\n font-size: var(--e-text-xs);\n border-radius: var(--e-radius-sm);\n }\n\n .e-avatar--l {\n width: 64px;\n height: 64px;\n font-size: var(--e-text-lg);\n }\n\n .e-avatar-img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n @media (forced-colors: active) {\n .e-avatar {\n border-color: CanvasText;\n outline-color: CanvasText;\n color: CanvasText;\n }\n\n .e-avatar--button:focus-visible {\n outline-color: Highlight;\n }\n }\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"EAvatar.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeClass","_withCtx","_createElementBlock","_toDisplayString","_Fragment","_createTextVNode","_createCommentVNode","_hoisted_1","_hoisted_2","_hoisted_3","EAvatar_vue_vue_type_script_setup_true_lang_default","props","__props","failed","ref","initials","computed","parts","openBlock","createBlock","resolveDynamicComponent","normalizeClass","withCtx","createElementBlock","_cache","toDisplayString","Fragment","createTextVNode","createCommentVNode"],"sources":["../../../src/components/Avatar/EAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from \"vue\";\nimport \"../../styles/base.css\";\n\nconst props = withDefaults(\n defineProps<{\n /** The person's name. Screen readers read it; the initials are the first letters of its first and last word. */\n name: string;\n /** A photo URL. If it fails to load, the initials appear. */\n src?: string;\n /** 32px, for rows and bars. */\n small?: boolean;\n /** 64px, for a profile or practitioner on an appointment card. The default is 44px. */\n large?: boolean;\n /** `button` renders a `button` with `type=\"button\"`, a pointer cursor and a focus ring, named by `name`, such as the `trigger` of an `EMenu`. */\n as?: \"span\" | \"button\";\n }>(),\n { as: \"span\" },\n);\n\nconst failed = ref(false);\nwatch(\n () => props.src,\n () => (failed.value = false),\n);\n\nconst initials = computed(() => {\n const parts = String(props.name || \"?\")\n .split(/\\s+/)\n .filter(Boolean);\n const first = [...(parts[0] ?? \"?\")][0] ?? \"?\";\n const last = parts.length > 1 ? ([...parts[parts.length - 1]!][0] ?? \"\") : \"\";\n return (first + last).toUpperCase();\n});\n</script>\n\n<template>\n <component\n :is=\"as\"\n class=\"e-avatar\"\n :class=\"{ 'e-avatar--s': small, 'e-avatar--l': large, 'e-avatar--button': as === 'button' }\"\n :type=\"as === 'button' ? 'button' : undefined\"\n :role=\"as === 'button' ? undefined : 'img'\"\n :aria-label=\"as === 'button' ? undefined : name\"\n >\n <img v-if=\"src && !failed\" class=\"e-avatar-img\" :src=\"src\" alt=\"\" @error=\"failed = true\" />\n <span v-else-if=\"as === 'button'\" aria-hidden=\"true\">{{ initials }}</span>\n <template v-else>{{ initials }}</template>\n <span v-if=\"as === 'button'\" class=\"e-sr\">{{ name }}</span>\n </component>\n</template>\n\n<style>\n@layer e.primitives {\n .e-avatar {\n --e-ring: var(--e-border-strong);\n\n position: relative;\n display: inline-grid;\n place-items: center;\n flex: none;\n box-sizing: border-box;\n width: var(--e-tap, 44px);\n height: var(--e-tap, 44px);\n overflow: hidden;\n border: 0;\n border-radius: var(--e-radius-md);\n background: var(--e-surface-tint);\n color: var(--e-primary);\n font: 600 var(--e-text-sm) / 1 var(--e-font-mono);\n letter-spacing: 0.02em;\n }\n\n /* The ring sits over the picture so an image never covers it. */\n .e-avatar::after {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-ring);\n pointer-events: none;\n transition: box-shadow var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-avatar--button {\n position: relative;\n padding: 0;\n cursor: pointer;\n }\n\n .e-avatar--button:hover {\n --e-ring: var(--e-ink);\n }\n\n .e-avatar--button:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-avatar--button {\n transition: none;\n }\n }\n\n .e-avatar--s {\n width: 32px;\n height: 32px;\n font-size: var(--e-text-xs);\n border-radius: var(--e-radius-sm);\n }\n\n .e-avatar--l {\n width: 64px;\n height: 64px;\n font-size: var(--e-text-lg);\n }\n\n .e-avatar-img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n @media (forced-colors: active) {\n .e-avatar {\n border-color: CanvasText;\n outline-color: CanvasText;\n color: CanvasText;\n }\n\n .e-avatar--button:focus-visible {\n outline-color: Highlight;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAIA,IAAMc,IAAQC,GAgBRC,IAASC,EAAI,EAAK;EACxB,QACQH,EAAM,WACL,EAAO,QAAQ,EACxB;EAEA,IAAMI,IAAWC,QAAe;GAC9B,IAAMC,IAAQ,OAAON,EAAM,QAAQ,GAAG,CAAA,CACnC,MAAM,KAAK,CAAA,CACX,OAAO,OAAO;GAGjB,SAFc,CAAC,GAAIM,EAAM,MAAM,GAAI,CAAC,CAAC,MAAM,QAC9BA,EAAM,SAAS,IAAK,CAAC,GAAGA,EAAMA,EAAM,SAAS,EAAG,CAAC,CAAC,MAAM,KAAM,IAAA,CACrD,YAAY;EACpC,CAAC;E,kBAICpB,EAAA,GAAAC,EAYYC,EAXLa,EAAA,EAAE,GAAA;GACP,OAAKZ,EAAA,CAAC,YAAU;IAAA,eACSY,EAAA;IAAK,eAAiBA,EAAA;IAAK,oBAAsBA,EAAA,OAAE;GAAA,CAAA,CAAA;GAC3E,MAAMA,EAAA,OAAE,WAAA,WAA2B,KAAA;GACnC,MAAMA,EAAA,OAAE,WAAgB,KAAA,IAAS;GACjC,cAAYA,EAAA,OAAE,WAAgB,KAAA,IAAYA,EAAA;;GAE3C,SAAAX,QAA2F,CAAhFW,EAAA,OAAG,CAAKC,EAAA,SAAnBhB,EAAA,GAAAK,EAA2F,OAAA;;IAAhE,OAAM;IAAgB,KAAKU,EAAA;IAAK,KAAI;IAAI,SAAK,AAAAY,EAAA,QAAA,MAAE,EAAA,QAAM;G,mBAC/DZ,EAAA,OAAE,YAAnBf,EAAA,GAAAK,EAA0E,QAA1EM,GAA0EL,EAAlBY,EAAA,KAAQ,GAAA,CAAA,MAChElB,EAAA,GAAAK,EAA0CE,GAAA,EAAA,KAAA,EAAA,GAAA,CAAtBC,EAAAF,EAAAY,EAAA,KAAQ,GAAA,CAAA,C,SAChBH,EAAA,OAAE,YAAdf,EAAA,GAAAK,EAA2D,QAA3DO,GAA2DN,EAAdS,EAAA,IAAI,GAAA,CAAA,K"}
1
+ {"version":3,"file":"EAvatar.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeClass","_withCtx","_createElementBlock","_toDisplayString","_Fragment","_createTextVNode","_createCommentVNode","_hoisted_1","_hoisted_2","_hoisted_3","EAvatar_vue_vue_type_script_setup_true_lang_default","props","__props","failed","ref","initials","computed","parts","openBlock","createBlock","resolveDynamicComponent","normalizeClass","withCtx","createElementBlock","_cache","toDisplayString","Fragment","createTextVNode","createCommentVNode"],"sources":["../../../src/components/Avatar/EAvatar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from \"vue\";\nimport \"../../styles/base.css\";\n\nconst props = withDefaults(\n defineProps<{\n /** The person's name. Screen readers read it; the initials are the first letters of its first and last word. */\n name: string;\n /** A photo URL. If it fails to load, the initials appear. */\n src?: string;\n /** 32px, for rows and bars. */\n small?: boolean;\n /** 64px, for a profile or practitioner on an appointment card. The default is 44px. */\n large?: boolean;\n /** `button` renders a `button` with `type=\"button\"`, a pointer cursor and a focus ring, named by `name`, such as the `trigger` of an `EMenu`. */\n as?: \"span\" | \"button\";\n }>(),\n { as: \"span\" },\n);\n\nconst failed = ref(false);\nwatch(\n () => props.src,\n () => (failed.value = false),\n);\n\nconst initials = computed(() => {\n const parts = String(props.name || \"?\")\n .split(/\\s+/)\n .filter(Boolean);\n const first = [...(parts[0] ?? \"?\")][0] ?? \"?\";\n const last = parts.length > 1 ? ([...parts[parts.length - 1]!][0] ?? \"\") : \"\";\n return (first + last).toUpperCase();\n});\n</script>\n\n<template>\n <component\n :is=\"as\"\n class=\"e-avatar\"\n :class=\"{ 'e-avatar--s': small, 'e-avatar--l': large, 'e-avatar--button': as === 'button' }\"\n :type=\"as === 'button' ? 'button' : undefined\"\n :role=\"as === 'button' ? undefined : 'img'\"\n :aria-label=\"as === 'button' ? undefined : name\"\n >\n <img v-if=\"src && !failed\" class=\"e-avatar-img\" :src=\"src\" alt=\"\" @error=\"failed = true\" />\n <span v-else-if=\"as === 'button'\" aria-hidden=\"true\">{{ initials }}</span>\n <template v-else>{{ initials }}</template>\n <span v-if=\"as === 'button'\" class=\"e-sr\">{{ name }}</span>\n </component>\n</template>\n\n<style>\n@layer e.primitives {\n .e-avatar {\n --e-ring: var(--e-border-strong);\n\n position: relative;\n display: inline-grid;\n place-items: center;\n flex: none;\n box-sizing: border-box;\n width: var(--e-tap, 44px);\n height: var(--e-tap, 44px);\n overflow: hidden;\n border: var(--e-stroke-edge) solid var(--e-ring);\n border-radius: var(--e-radius-md);\n background: var(--e-surface-tint);\n background-clip: padding-box;\n color: var(--e-primary);\n font: 600 var(--e-text-sm) / 1 var(--e-font-mono);\n letter-spacing: 0.02em;\n transition: border-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-avatar--button {\n position: relative;\n padding: 0;\n cursor: pointer;\n }\n\n .e-avatar--button:hover {\n --e-ring: var(--e-ink);\n }\n\n .e-avatar--button:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-avatar--button {\n transition: none;\n }\n }\n\n .e-avatar--s {\n width: 32px;\n height: 32px;\n font-size: var(--e-text-xs);\n border-radius: var(--e-radius-sm);\n }\n\n .e-avatar--l {\n width: 64px;\n height: 64px;\n font-size: var(--e-text-lg);\n }\n\n .e-avatar-img {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n @media (forced-colors: active) {\n .e-avatar {\n border-color: CanvasText;\n outline-color: CanvasText;\n color: CanvasText;\n }\n\n .e-avatar--button:focus-visible {\n outline-color: Highlight;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAIA,IAAMc,IAAQC,GAgBRC,IAASC,EAAI,EAAK;EACxB,QACQH,EAAM,WACL,EAAO,QAAQ,EACxB;EAEA,IAAMI,IAAWC,QAAe;GAC9B,IAAMC,IAAQ,OAAON,EAAM,QAAQ,GAAG,CAAA,CACnC,MAAM,KAAK,CAAA,CACX,OAAO,OAAO;GAGjB,SAFc,CAAC,GAAIM,EAAM,MAAM,GAAI,CAAC,CAAC,MAAM,QAC9BA,EAAM,SAAS,IAAK,CAAC,GAAGA,EAAMA,EAAM,SAAS,EAAG,CAAC,CAAC,MAAM,KAAM,IAAA,CACrD,YAAY;EACpC,CAAC;E,kBAICpB,EAAA,GAAAC,EAYYC,EAXLa,EAAA,EAAE,GAAA;GACP,OAAKZ,EAAA,CAAC,YAAU;IAAA,eACSY,EAAA;IAAK,eAAiBA,EAAA;IAAK,oBAAsBA,EAAA,OAAE;GAAA,CAAA,CAAA;GAC3E,MAAMA,EAAA,OAAE,WAAA,WAA2B,KAAA;GACnC,MAAMA,EAAA,OAAE,WAAgB,KAAA,IAAS;GACjC,cAAYA,EAAA,OAAE,WAAgB,KAAA,IAAYA,EAAA;;GAE3C,SAAAX,QAA2F,CAAhFW,EAAA,OAAG,CAAKC,EAAA,SAAnBhB,EAAA,GAAAK,EAA2F,OAAA;;IAAhE,OAAM;IAAgB,KAAKU,EAAA;IAAK,KAAI;IAAI,SAAK,AAAAY,EAAA,QAAA,MAAE,EAAA,QAAM;G,mBAC/DZ,EAAA,OAAE,YAAnBf,EAAA,GAAAK,EAA0E,QAA1EM,GAA0EL,EAAlBY,EAAA,KAAQ,GAAA,CAAA,MAChElB,EAAA,GAAAK,EAA0CE,GAAA,EAAA,KAAA,EAAA,GAAA,CAAtBC,EAAAF,EAAAY,EAAA,KAAQ,GAAA,CAAA,C,SAChBH,EAAA,OAAE,YAAdf,EAAA,GAAAK,EAA2D,QAA3DO,GAA2DN,EAAdS,EAAA,IAAI,GAAA,CAAA,K"}
@@ -1 +1 @@
1
- {"version":3,"file":"EButton.js","names":["_sfc_main","EButton_vue_vue_type_script_setup_true_lang_default","EButton_default"],"sources":["../../../src/components/Button/EButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport EIcon from \"../Icon/EIcon.vue\";\nimport type { IconProp } from \"../../icons/types.js\";\nimport \"../../styles/base.css\";\n\nconst props = withDefaults(\n defineProps<{\n /** `primary` is the one main action on a screen; `secondary` confirms; `outline` is for the other actions beside it; `danger` cancels or removes; `quiet` is an underlined text action. */\n variant?: \"primary\" | \"secondary\" | \"outline\" | \"danger\" | \"quiet\";\n /** An icon before the label: a name such as `download`, or a component. */\n icon?: IconProp;\n /** Full width. */\n block?: boolean;\n /** Dashed and unfilled; not focusable, ignores clicks. With `href` the link gets `aria-disabled=\"true\"` and `tabindex=\"-1\"` and does not navigate. */\n disabled?: boolean;\n /** Set `submit` on the one that submits a form. */\n type?: \"button\" | \"submit\" | \"reset\";\n /** Renders a link that looks like the button, for a destination rather than an action (a call to action that goes to a page). Space does not follow it. */\n href?: string;\n /** With `href`: opens in a new tab. */\n external?: boolean;\n /** Swaps the icon for a spinner, flattens the face, dashes its edge and animates stripes across it, and ignores clicks while an action runs. The button keeps its width and stays focusable, and is announced as busy. */\n loading?: boolean;\n }>(),\n { variant: \"primary\", type: \"button\" },\n);\n\ndefineSlots<{\n /** The label: a verb that says what happens, like \"Pay $162.40\". */\n default(): unknown;\n}>();\n\nfunction blockWhenDisabled(event: Event) {\n if (!props.disabled && !props.loading) return;\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n</script>\n\n<template>\n <a\n v-if=\"href\"\n :href=\"href\"\n class=\"e-btn\"\n :class=\"[variant !== 'primary' && `e-btn--${variant}`, block && 'e-btn--block', loading && 'e-btn--loading']\"\n :target=\"external ? '_blank' : undefined\"\n :rel=\"external ? 'noreferrer' : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-busy=\"loading ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click.capture=\"blockWhenDisabled\"\n @auxclick.capture=\"blockWhenDisabled\"\n >\n <svg v-if=\"loading\" class=\"e-btn-spinner\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /></svg>\n <EIcon v-else-if=\"icon\" :name=\"icon\" />\n <slot />\n </a>\n <button\n v-else\n :type=\"type\"\n class=\"e-btn\"\n :class=\"[variant !== 'primary' && `e-btn--${variant}`, block && 'e-btn--block', loading && 'e-btn--loading']\"\n :disabled=\"disabled\"\n :aria-busy=\"loading ? 'true' : undefined\"\n @click.capture=\"blockWhenDisabled\"\n >\n <svg v-if=\"loading\" class=\"e-btn-spinner\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /></svg>\n <EIcon v-else-if=\"icon\" :name=\"icon\" />\n <slot />\n </button>\n</template>\n\n<style>\n@layer e.primitives {\n .e-btn {\n --e-fill: var(--e-primary);\n --e-on-fill: var(--e-on-primary);\n --e-slab: color-mix(in srgb, var(--e-fill), var(--e-shade-slab));\n --e-hover: color-mix(in srgb, var(--e-fill), var(--e-shade-hover));\n --e-press: color-mix(in srgb, var(--e-fill), var(--e-shade-press));\n\n /* One rounded box, one control height tall. The slab is an inset shadow shifted up by the lift: the part of the box left uncovered along its bottom, which follows the corners up the sides, in the colour of the box's own edge. It is cut by the box's one outline, so nothing sits behind the curve. Pressing sinks the face over it. */\n --e-lift: var(--e-depth);\n --e-band: calc(var(--e-lift) + var(--e-stroke-edge));\n --e-ring: var(--e-slab);\n\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--e-space-2);\n height: var(--e-control-height);\n padding: 0 var(--e-space-4) var(--e-lift);\n border: 0;\n border-radius: var(--e-radius-md);\n background-color: var(--e-fill);\n box-shadow:\n inset 0 0 0 var(--e-stroke-edge) var(--e-ring),\n inset 0 calc(-1 * var(--e-band)) 0 0 var(--e-slab);\n color: var(--e-on-fill);\n font: 500 var(--e-text-md) / 1 var(--e-font-sans);\n letter-spacing: 0.01em;\n white-space: nowrap;\n text-decoration: none;\n cursor: pointer;\n transition:\n box-shadow var(--e-duration-tap) var(--e-easing-out),\n background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-btn:hover {\n --e-slab: color-mix(in srgb, var(--e-hover), var(--e-shade-slab));\n\n background-color: var(--e-hover);\n }\n\n .e-btn:active {\n --e-lift: 0px;\n\n background-color: var(--e-press);\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-ring);\n }\n\n .e-btn--secondary {\n --e-fill: var(--e-secondary);\n --e-on-fill: var(--e-on-secondary);\n }\n\n .e-btn--danger {\n --e-fill: var(--e-danger);\n --e-on-fill: var(--e-on-danger);\n }\n\n .e-btn--outline {\n --e-fill: var(--e-surface);\n --e-on-fill: var(--e-ink);\n --e-slab: var(--e-border-strong);\n }\n\n .e-btn--outline:hover {\n --e-ring: var(--e-ink);\n --e-slab: var(--e-ink);\n\n background-color: color-mix(in srgb, var(--e-surface), var(--e-shade-hover));\n }\n\n .e-btn--outline:active {\n --e-ring: var(--e-ink);\n --e-slab: var(--e-ink);\n\n background-color: color-mix(in srgb, var(--e-surface), var(--e-shade-press));\n }\n\n .e-btn--quiet {\n --e-ring: transparent;\n --e-lift: 0px;\n\n background: transparent;\n color: var(--e-ink);\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-ring);\n padding-inline: var(--e-space-3);\n text-decoration: underline;\n text-underline-offset: 5px;\n text-decoration-thickness: var(--e-stroke-edge);\n text-decoration-color: var(--e-border-strong);\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):hover {\n --e-ring: var(--e-wash-ring);\n\n background: var(--e-wash-hover);\n text-decoration-color: currentcolor;\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):active {\n --e-ring: var(--e-ink);\n\n background: var(--e-wash-press);\n transform: none;\n }\n\n .e-btn .e-icon,\n .e-btn-spinner {\n margin-inline-start: calc(-0.5 * var(--e-space-1));\n }\n\n .e-btn-spinner {\n flex: none;\n width: 1.125em;\n height: 1.125em;\n fill: none;\n stroke: currentcolor;\n stroke-width: 3;\n stroke-linecap: round;\n stroke-dasharray: 36 56;\n animation: e-btn-spin 0.9s linear infinite;\n }\n\n /* Busy reads as unavailable and in progress: a soft tint of the button's colour with a dashed edge like a disabled button, and stripes that move. The face grows over its slab, so the button stays one control height tall. The edge is a pseudo-element, so a page's focus reset cannot remove it. */\n .e-btn--loading {\n --e-lift: 0px;\n --e-tint: var(--e-fill);\n --e-busy: color-mix(in srgb, var(--e-tint) 80%, var(--e-ink));\n }\n\n .e-btn--outline.e-btn--loading {\n --e-tint: var(--e-border-strong);\n }\n\n .e-btn--loading,\n .e-btn--loading:hover,\n .e-btn--loading:active {\n background-color: color-mix(in srgb, var(--e-tint) 14%, var(--e-surface));\n background-image: repeating-linear-gradient(135deg, transparent 0 8px, color-mix(in srgb, var(--e-tint) 20%, transparent) 8px 16px);\n background-size: 22.63px 22.63px;\n box-shadow: none;\n color: var(--e-busy);\n transform: none;\n cursor: not-allowed;\n animation: e-btn-stripes 0.8s linear infinite;\n }\n\n .e-btn--loading::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border: var(--e-stroke-edge) dashed var(--e-busy);\n border-radius: inherit;\n pointer-events: none;\n }\n\n @keyframes e-btn-stripes {\n to {\n background-position-x: 22.63px;\n }\n }\n\n @keyframes e-btn-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n .e-btn--block {\n width: 100%;\n }\n\n /* A toggle: any button with aria-pressed=\"true\" reads as selected. */\n .e-btn[aria-pressed=\"true\"],\n .e-btn[aria-pressed=\"true\"]:hover,\n .e-btn[aria-pressed=\"true\"]:active {\n --e-slab: var(--e-primary);\n --e-ring: var(--e-primary);\n\n background-color: var(--e-surface-hover);\n color: var(--e-primary);\n }\n\n .e-btn[disabled],\n .e-btn[aria-disabled=\"true\"] {\n --e-lift: 0px;\n\n cursor: not-allowed;\n background: transparent;\n color: var(--e-muted);\n outline: var(--e-stroke-edge) dashed var(--e-border-strong);\n outline-offset: calc(-1 * var(--e-stroke-edge));\n box-shadow: none;\n transform: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-btn {\n transition: none;\n }\n\n .e-btn-spinner {\n animation-duration: 3s;\n }\n\n .e-btn--loading {\n animation: none;\n }\n }\n\n @media print {\n .e-btn {\n display: none;\n }\n }\n\n @media (forced-colors: active) {\n .e-btn {\n border: var(--e-stroke-focus) solid ButtonText;\n }\n\n .e-btn[aria-pressed=\"true\"] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .e-btn[disabled],\n .e-btn[aria-disabled=\"true\"] {\n outline-color: GrayText;\n color: GrayText;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"EButton.js","names":["_sfc_main","EButton_vue_vue_type_script_setup_true_lang_default","EButton_default"],"sources":["../../../src/components/Button/EButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport EIcon from \"../Icon/EIcon.vue\";\nimport type { IconProp } from \"../../icons/types.js\";\nimport \"../../styles/base.css\";\n\nconst props = withDefaults(\n defineProps<{\n /** `primary` is the one main action on a screen; `secondary` confirms; `outline` is for the other actions beside it; `danger` cancels or removes; `quiet` is an underlined text action. */\n variant?: \"primary\" | \"secondary\" | \"outline\" | \"danger\" | \"quiet\";\n /** An icon before the label: a name such as `download`, or a component. */\n icon?: IconProp;\n /** Full width. */\n block?: boolean;\n /** Dashed and unfilled; not focusable, ignores clicks. With `href` the link gets `aria-disabled=\"true\"` and `tabindex=\"-1\"` and does not navigate. */\n disabled?: boolean;\n /** Set `submit` on the one that submits a form. */\n type?: \"button\" | \"submit\" | \"reset\";\n /** Renders a link that looks like the button, for a destination rather than an action (a call to action that goes to a page). Space does not follow it. */\n href?: string;\n /** With `href`: opens in a new tab. */\n external?: boolean;\n /** Swaps the icon for a spinner, flattens the face, dashes its edge and animates stripes across it, and ignores clicks while an action runs. The button keeps its width and stays focusable, and is announced as busy. */\n loading?: boolean;\n }>(),\n { variant: \"primary\", type: \"button\" },\n);\n\ndefineSlots<{\n /** The label: a verb that says what happens, like \"Pay $162.40\". */\n default(): unknown;\n}>();\n\nfunction blockWhenDisabled(event: Event) {\n if (!props.disabled && !props.loading) return;\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n</script>\n\n<template>\n <a\n v-if=\"href\"\n :href=\"href\"\n class=\"e-btn\"\n :class=\"[variant !== 'primary' && `e-btn--${variant}`, block && 'e-btn--block', loading && 'e-btn--loading']\"\n :target=\"external ? '_blank' : undefined\"\n :rel=\"external ? 'noreferrer' : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-busy=\"loading ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click.capture=\"blockWhenDisabled\"\n @auxclick.capture=\"blockWhenDisabled\"\n >\n <svg v-if=\"loading\" class=\"e-btn-spinner\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /></svg>\n <EIcon v-else-if=\"icon\" :name=\"icon\" />\n <slot />\n </a>\n <button\n v-else\n :type=\"type\"\n class=\"e-btn\"\n :class=\"[variant !== 'primary' && `e-btn--${variant}`, block && 'e-btn--block', loading && 'e-btn--loading']\"\n :disabled=\"disabled\"\n :aria-busy=\"loading ? 'true' : undefined\"\n @click.capture=\"blockWhenDisabled\"\n >\n <svg v-if=\"loading\" class=\"e-btn-spinner\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /></svg>\n <EIcon v-else-if=\"icon\" :name=\"icon\" />\n <slot />\n </button>\n</template>\n\n<style>\n@layer e.primitives {\n .e-btn {\n --e-fill: var(--e-primary);\n --e-on-fill: var(--e-on-primary);\n --e-slab: color-mix(in srgb, var(--e-fill), var(--e-shade-slab));\n --e-hover: color-mix(in srgb, var(--e-fill), var(--e-shade-hover));\n --e-press: color-mix(in srgb, var(--e-fill), var(--e-shade-press));\n\n /* One border, one control height tall. The slab is the bottom edge made thicker by the lift; the radius tapers it up the corners. Pressing sinks the face over it. */\n --e-lift: var(--e-depth);\n --e-ring: var(--e-slab);\n\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--e-space-2);\n height: var(--e-control-height);\n padding: 0 calc(var(--e-space-4) - var(--e-stroke-edge));\n box-sizing: border-box;\n border: var(--e-stroke-edge) solid var(--e-ring);\n border-bottom-width: calc(var(--e-stroke-edge) + var(--e-lift));\n border-radius: var(--e-radius-md);\n background-color: var(--e-fill);\n\n /* A solid face runs under its border so no page colour shows between them. */\n background-clip: border-box;\n color: var(--e-on-fill);\n font: 500 var(--e-text-md) / 1 var(--e-font-sans);\n letter-spacing: 0.01em;\n white-space: nowrap;\n text-decoration: none;\n cursor: pointer;\n transition:\n border-color var(--e-duration-tap) var(--e-easing-out),\n background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-btn:hover {\n --e-slab: color-mix(in srgb, var(--e-hover), var(--e-shade-slab));\n\n background-color: var(--e-hover);\n }\n\n .e-btn:active {\n --e-lift: 0px;\n\n background-color: var(--e-press);\n }\n\n .e-btn--secondary {\n --e-fill: var(--e-secondary);\n --e-on-fill: var(--e-on-secondary);\n }\n\n .e-btn--danger {\n --e-fill: var(--e-danger);\n --e-on-fill: var(--e-on-danger);\n }\n\n .e-btn--outline {\n --e-fill: var(--e-surface);\n --e-on-fill: var(--e-ink);\n --e-slab: var(--e-border-strong);\n\n background-clip: padding-box;\n }\n\n .e-btn--outline:hover {\n --e-ring: var(--e-ink);\n --e-slab: var(--e-ink);\n\n background-color: color-mix(in srgb, var(--e-surface), var(--e-shade-hover));\n }\n\n .e-btn--outline:active {\n --e-ring: var(--e-ink);\n --e-slab: var(--e-ink);\n\n background-color: color-mix(in srgb, var(--e-surface), var(--e-shade-press));\n }\n\n .e-btn--quiet {\n --e-ring: transparent;\n --e-lift: 0px;\n\n background: transparent;\n color: var(--e-ink);\n padding-inline: calc(var(--e-space-3) - var(--e-stroke-edge));\n text-decoration: underline;\n text-underline-offset: 5px;\n text-decoration-thickness: var(--e-stroke-edge);\n text-decoration-color: var(--e-border-strong);\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):hover {\n --e-ring: var(--e-wash-ring);\n\n background: var(--e-wash-hover);\n text-decoration-color: currentcolor;\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):active {\n --e-ring: var(--e-ink);\n\n background: var(--e-wash-press);\n transform: none;\n }\n\n .e-btn .e-icon,\n .e-btn-spinner {\n margin-inline-start: calc(-0.5 * var(--e-space-1));\n }\n\n .e-btn-spinner {\n flex: none;\n width: 1.125em;\n height: 1.125em;\n fill: none;\n stroke: currentcolor;\n stroke-width: 3;\n stroke-linecap: round;\n stroke-dasharray: 36 56;\n animation: e-btn-spin 0.9s linear infinite;\n }\n\n /* Busy reads as unavailable and in progress: a soft tint of the button's colour with a dashed edge like a disabled button, and stripes that move. The edge is a pseudo-element, so a page's focus reset cannot remove it. */\n .e-btn--loading {\n --e-lift: 0px;\n --e-tint: var(--e-fill);\n --e-busy: color-mix(in srgb, var(--e-tint) 80%, var(--e-ink));\n }\n\n .e-btn--outline.e-btn--loading {\n --e-tint: var(--e-border-strong);\n }\n\n .e-btn--loading,\n .e-btn--loading:hover,\n .e-btn--loading:active {\n background-color: color-mix(in srgb, var(--e-tint) 14%, var(--e-surface));\n background-image: repeating-linear-gradient(135deg, transparent 0 8px, color-mix(in srgb, var(--e-tint) 20%, transparent) 8px 16px);\n background-size: 22.63px 22.63px;\n background-clip: padding-box;\n border-color: transparent;\n color: var(--e-busy);\n transform: none;\n cursor: not-allowed;\n animation: e-btn-stripes 0.8s linear infinite;\n }\n\n .e-btn--loading::before {\n content: \"\";\n position: absolute;\n inset: calc(-1 * var(--e-stroke-edge));\n border: var(--e-stroke-edge) dashed var(--e-busy);\n border-radius: inherit;\n pointer-events: none;\n }\n\n @keyframes e-btn-stripes {\n to {\n background-position-x: 22.63px;\n }\n }\n\n @keyframes e-btn-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n .e-btn--block {\n width: 100%;\n }\n\n /* A toggle: any button with aria-pressed=\"true\" reads as selected. */\n .e-btn[aria-pressed=\"true\"],\n .e-btn[aria-pressed=\"true\"]:hover,\n .e-btn[aria-pressed=\"true\"]:active {\n --e-slab: var(--e-primary);\n --e-ring: var(--e-primary);\n\n background-color: var(--e-surface-hover);\n color: var(--e-primary);\n }\n\n .e-btn[disabled],\n .e-btn[aria-disabled=\"true\"] {\n --e-lift: 0px;\n\n cursor: not-allowed;\n background: transparent;\n color: var(--e-muted);\n outline: var(--e-stroke-edge) dashed var(--e-border-strong);\n outline-offset: calc(-1 * var(--e-stroke-edge));\n border-color: transparent;\n transform: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-btn {\n transition: none;\n }\n\n .e-btn-spinner {\n animation-duration: 3s;\n }\n\n .e-btn--loading {\n animation: none;\n }\n }\n\n @media print {\n .e-btn {\n display: none;\n }\n }\n\n @media (forced-colors: active) {\n .e-btn {\n border: var(--e-stroke-focus) solid ButtonText;\n }\n\n .e-btn[aria-pressed=\"true\"] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .e-btn[disabled],\n .e-btn[aria-disabled=\"true\"] {\n outline-color: GrayText;\n color: GrayText;\n }\n }\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"EButton.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_createBlock","EIcon","_createCommentVNode","_renderSlot","EIcon_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","EButton_vue_vue_type_script_setup_true_lang_default","props","__props","blockWhenDisabled","event","openBlock","createElementBlock","normalizeClass","_cache","createElementVNode","createBlock","createCommentVNode","renderSlot","_ctx"],"sources":["../../../src/components/Button/EButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport EIcon from \"../Icon/EIcon.vue\";\nimport type { IconProp } from \"../../icons/types.js\";\nimport \"../../styles/base.css\";\n\nconst props = withDefaults(\n defineProps<{\n /** `primary` is the one main action on a screen; `secondary` confirms; `outline` is for the other actions beside it; `danger` cancels or removes; `quiet` is an underlined text action. */\n variant?: \"primary\" | \"secondary\" | \"outline\" | \"danger\" | \"quiet\";\n /** An icon before the label: a name such as `download`, or a component. */\n icon?: IconProp;\n /** Full width. */\n block?: boolean;\n /** Dashed and unfilled; not focusable, ignores clicks. With `href` the link gets `aria-disabled=\"true\"` and `tabindex=\"-1\"` and does not navigate. */\n disabled?: boolean;\n /** Set `submit` on the one that submits a form. */\n type?: \"button\" | \"submit\" | \"reset\";\n /** Renders a link that looks like the button, for a destination rather than an action (a call to action that goes to a page). Space does not follow it. */\n href?: string;\n /** With `href`: opens in a new tab. */\n external?: boolean;\n /** Swaps the icon for a spinner, flattens the face, dashes its edge and animates stripes across it, and ignores clicks while an action runs. The button keeps its width and stays focusable, and is announced as busy. */\n loading?: boolean;\n }>(),\n { variant: \"primary\", type: \"button\" },\n);\n\ndefineSlots<{\n /** The label: a verb that says what happens, like \"Pay $162.40\". */\n default(): unknown;\n}>();\n\nfunction blockWhenDisabled(event: Event) {\n if (!props.disabled && !props.loading) return;\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n</script>\n\n<template>\n <a\n v-if=\"href\"\n :href=\"href\"\n class=\"e-btn\"\n :class=\"[variant !== 'primary' && `e-btn--${variant}`, block && 'e-btn--block', loading && 'e-btn--loading']\"\n :target=\"external ? '_blank' : undefined\"\n :rel=\"external ? 'noreferrer' : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-busy=\"loading ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click.capture=\"blockWhenDisabled\"\n @auxclick.capture=\"blockWhenDisabled\"\n >\n <svg v-if=\"loading\" class=\"e-btn-spinner\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /></svg>\n <EIcon v-else-if=\"icon\" :name=\"icon\" />\n <slot />\n </a>\n <button\n v-else\n :type=\"type\"\n class=\"e-btn\"\n :class=\"[variant !== 'primary' && `e-btn--${variant}`, block && 'e-btn--block', loading && 'e-btn--loading']\"\n :disabled=\"disabled\"\n :aria-busy=\"loading ? 'true' : undefined\"\n @click.capture=\"blockWhenDisabled\"\n >\n <svg v-if=\"loading\" class=\"e-btn-spinner\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /></svg>\n <EIcon v-else-if=\"icon\" :name=\"icon\" />\n <slot />\n </button>\n</template>\n\n<style>\n@layer e.primitives {\n .e-btn {\n --e-fill: var(--e-primary);\n --e-on-fill: var(--e-on-primary);\n --e-slab: color-mix(in srgb, var(--e-fill), var(--e-shade-slab));\n --e-hover: color-mix(in srgb, var(--e-fill), var(--e-shade-hover));\n --e-press: color-mix(in srgb, var(--e-fill), var(--e-shade-press));\n\n /* One rounded box, one control height tall. The slab is an inset shadow shifted up by the lift: the part of the box left uncovered along its bottom, which follows the corners up the sides, in the colour of the box's own edge. It is cut by the box's one outline, so nothing sits behind the curve. Pressing sinks the face over it. */\n --e-lift: var(--e-depth);\n --e-band: calc(var(--e-lift) + var(--e-stroke-edge));\n --e-ring: var(--e-slab);\n\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--e-space-2);\n height: var(--e-control-height);\n padding: 0 var(--e-space-4) var(--e-lift);\n border: 0;\n border-radius: var(--e-radius-md);\n background-color: var(--e-fill);\n box-shadow:\n inset 0 0 0 var(--e-stroke-edge) var(--e-ring),\n inset 0 calc(-1 * var(--e-band)) 0 0 var(--e-slab);\n color: var(--e-on-fill);\n font: 500 var(--e-text-md) / 1 var(--e-font-sans);\n letter-spacing: 0.01em;\n white-space: nowrap;\n text-decoration: none;\n cursor: pointer;\n transition:\n box-shadow var(--e-duration-tap) var(--e-easing-out),\n background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-btn:hover {\n --e-slab: color-mix(in srgb, var(--e-hover), var(--e-shade-slab));\n\n background-color: var(--e-hover);\n }\n\n .e-btn:active {\n --e-lift: 0px;\n\n background-color: var(--e-press);\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-ring);\n }\n\n .e-btn--secondary {\n --e-fill: var(--e-secondary);\n --e-on-fill: var(--e-on-secondary);\n }\n\n .e-btn--danger {\n --e-fill: var(--e-danger);\n --e-on-fill: var(--e-on-danger);\n }\n\n .e-btn--outline {\n --e-fill: var(--e-surface);\n --e-on-fill: var(--e-ink);\n --e-slab: var(--e-border-strong);\n }\n\n .e-btn--outline:hover {\n --e-ring: var(--e-ink);\n --e-slab: var(--e-ink);\n\n background-color: color-mix(in srgb, var(--e-surface), var(--e-shade-hover));\n }\n\n .e-btn--outline:active {\n --e-ring: var(--e-ink);\n --e-slab: var(--e-ink);\n\n background-color: color-mix(in srgb, var(--e-surface), var(--e-shade-press));\n }\n\n .e-btn--quiet {\n --e-ring: transparent;\n --e-lift: 0px;\n\n background: transparent;\n color: var(--e-ink);\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-ring);\n padding-inline: var(--e-space-3);\n text-decoration: underline;\n text-underline-offset: 5px;\n text-decoration-thickness: var(--e-stroke-edge);\n text-decoration-color: var(--e-border-strong);\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):hover {\n --e-ring: var(--e-wash-ring);\n\n background: var(--e-wash-hover);\n text-decoration-color: currentcolor;\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):active {\n --e-ring: var(--e-ink);\n\n background: var(--e-wash-press);\n transform: none;\n }\n\n .e-btn .e-icon,\n .e-btn-spinner {\n margin-inline-start: calc(-0.5 * var(--e-space-1));\n }\n\n .e-btn-spinner {\n flex: none;\n width: 1.125em;\n height: 1.125em;\n fill: none;\n stroke: currentcolor;\n stroke-width: 3;\n stroke-linecap: round;\n stroke-dasharray: 36 56;\n animation: e-btn-spin 0.9s linear infinite;\n }\n\n /* Busy reads as unavailable and in progress: a soft tint of the button's colour with a dashed edge like a disabled button, and stripes that move. The face grows over its slab, so the button stays one control height tall. The edge is a pseudo-element, so a page's focus reset cannot remove it. */\n .e-btn--loading {\n --e-lift: 0px;\n --e-tint: var(--e-fill);\n --e-busy: color-mix(in srgb, var(--e-tint) 80%, var(--e-ink));\n }\n\n .e-btn--outline.e-btn--loading {\n --e-tint: var(--e-border-strong);\n }\n\n .e-btn--loading,\n .e-btn--loading:hover,\n .e-btn--loading:active {\n background-color: color-mix(in srgb, var(--e-tint) 14%, var(--e-surface));\n background-image: repeating-linear-gradient(135deg, transparent 0 8px, color-mix(in srgb, var(--e-tint) 20%, transparent) 8px 16px);\n background-size: 22.63px 22.63px;\n box-shadow: none;\n color: var(--e-busy);\n transform: none;\n cursor: not-allowed;\n animation: e-btn-stripes 0.8s linear infinite;\n }\n\n .e-btn--loading::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border: var(--e-stroke-edge) dashed var(--e-busy);\n border-radius: inherit;\n pointer-events: none;\n }\n\n @keyframes e-btn-stripes {\n to {\n background-position-x: 22.63px;\n }\n }\n\n @keyframes e-btn-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n .e-btn--block {\n width: 100%;\n }\n\n /* A toggle: any button with aria-pressed=\"true\" reads as selected. */\n .e-btn[aria-pressed=\"true\"],\n .e-btn[aria-pressed=\"true\"]:hover,\n .e-btn[aria-pressed=\"true\"]:active {\n --e-slab: var(--e-primary);\n --e-ring: var(--e-primary);\n\n background-color: var(--e-surface-hover);\n color: var(--e-primary);\n }\n\n .e-btn[disabled],\n .e-btn[aria-disabled=\"true\"] {\n --e-lift: 0px;\n\n cursor: not-allowed;\n background: transparent;\n color: var(--e-muted);\n outline: var(--e-stroke-edge) dashed var(--e-border-strong);\n outline-offset: calc(-1 * var(--e-stroke-edge));\n box-shadow: none;\n transform: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-btn {\n transition: none;\n }\n\n .e-btn-spinner {\n animation-duration: 3s;\n }\n\n .e-btn--loading {\n animation: none;\n }\n }\n\n @media print {\n .e-btn {\n display: none;\n }\n }\n\n @media (forced-colors: active) {\n .e-btn {\n border: var(--e-stroke-focus) solid ButtonText;\n }\n\n .e-btn[aria-pressed=\"true\"] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .e-btn[disabled],\n .e-btn[aria-disabled=\"true\"] {\n outline-color: GrayText;\n color: GrayText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKA,IAAMc,IAAQC;EA2Bd,SAASC,EAAkB,GAAc;GACvC,CAAKF,EAAM,YAAaA,EAAM,aAC9BG,EAAM,eAAe,GACrBA,EAAM,yBAAyB;EACjC;E,iBAKUF,EAAA,QADRf,EAAA,GAAAC,EAgBI,KAAA;;GAdD,MAAMc,EAAA;GACP,OAAKb,EAAA,CAAC,SAAO;IACJa,EAAA,YAAO,aAAA,UAA4BA,EAAA;IAAWA,EAAA,SAAK;IAAoBA,EAAA,WAAO;GAAA,CAAA,CAAA;GACtF,QAAQA,EAAA,WAAQ,WAAc,KAAA;GAC9B,KAAKA,EAAA,WAAQ,eAAkB,KAAA;GAC/B,iBAAeA,EAAA,WAAQ,SAAY,KAAA;GACnC,aAAWA,EAAA,UAAO,SAAY,KAAA;GAC9B,UAAUA,EAAA,WAAQ,KAAQ,KAAA;GACX,gBAAAC;GACG,mBAAAA;E,IAERD,EAAA,WAAXf,EAAA,GAAAC,EAAuH,OAAvHS,GAAuH,CAAA,GAAA,AAAAW,EAAA,OAAA,CAAtClB,EAAgC,UAAA;GAAxB,IAAG;GAAK,IAAG;GAAK,GAAE;E,mBACzFY,EAAA,QAAlBf,EAAA,GAAAI,EAAuCC,GAAA;;GAAd,MAAMU,EAAA;E,oCAC/BR,EAAQmB,EAAA,QAAA,SAAA,C,cAEV1B,EAAA,GAAAC,EAYS,UAAA;;GAVN,MAAMc,EAAA;GACP,OAAKb,EAAA,CAAC,SAAO;IACJa,EAAA,YAAO,aAAA,UAA4BA,EAAA;IAAWA,EAAA,SAAK;IAAoBA,EAAA,WAAO;GAAA,CAAA,CAAA;GACtF,UAAUA,EAAA;GACV,aAAWA,EAAA,UAAO,SAAY,KAAA;GACf,gBAAAC;E,IAELD,EAAA,WAAXf,EAAA,GAAAC,EAAuH,OAAvHW,GAAuH,CAAA,GAAA,AAAAS,EAAA,OAAA,CAAtClB,EAAgC,UAAA;GAAxB,IAAG;GAAK,IAAG;GAAK,GAAE;E,mBACzFY,EAAA,QAAlBf,EAAA,GAAAI,EAAuCC,GAAA;;GAAd,MAAMU,EAAA;E,oCAC/BR,EAAQmB,EAAA,QAAA,SAAA,C"}
1
+ {"version":3,"file":"EButton.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_createBlock","EIcon","_createCommentVNode","_renderSlot","EIcon_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","EButton_vue_vue_type_script_setup_true_lang_default","props","__props","blockWhenDisabled","event","openBlock","createElementBlock","normalizeClass","_cache","createElementVNode","createBlock","createCommentVNode","renderSlot","_ctx"],"sources":["../../../src/components/Button/EButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport EIcon from \"../Icon/EIcon.vue\";\nimport type { IconProp } from \"../../icons/types.js\";\nimport \"../../styles/base.css\";\n\nconst props = withDefaults(\n defineProps<{\n /** `primary` is the one main action on a screen; `secondary` confirms; `outline` is for the other actions beside it; `danger` cancels or removes; `quiet` is an underlined text action. */\n variant?: \"primary\" | \"secondary\" | \"outline\" | \"danger\" | \"quiet\";\n /** An icon before the label: a name such as `download`, or a component. */\n icon?: IconProp;\n /** Full width. */\n block?: boolean;\n /** Dashed and unfilled; not focusable, ignores clicks. With `href` the link gets `aria-disabled=\"true\"` and `tabindex=\"-1\"` and does not navigate. */\n disabled?: boolean;\n /** Set `submit` on the one that submits a form. */\n type?: \"button\" | \"submit\" | \"reset\";\n /** Renders a link that looks like the button, for a destination rather than an action (a call to action that goes to a page). Space does not follow it. */\n href?: string;\n /** With `href`: opens in a new tab. */\n external?: boolean;\n /** Swaps the icon for a spinner, flattens the face, dashes its edge and animates stripes across it, and ignores clicks while an action runs. The button keeps its width and stays focusable, and is announced as busy. */\n loading?: boolean;\n }>(),\n { variant: \"primary\", type: \"button\" },\n);\n\ndefineSlots<{\n /** The label: a verb that says what happens, like \"Pay $162.40\". */\n default(): unknown;\n}>();\n\nfunction blockWhenDisabled(event: Event) {\n if (!props.disabled && !props.loading) return;\n event.preventDefault();\n event.stopImmediatePropagation();\n}\n</script>\n\n<template>\n <a\n v-if=\"href\"\n :href=\"href\"\n class=\"e-btn\"\n :class=\"[variant !== 'primary' && `e-btn--${variant}`, block && 'e-btn--block', loading && 'e-btn--loading']\"\n :target=\"external ? '_blank' : undefined\"\n :rel=\"external ? 'noreferrer' : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-busy=\"loading ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click.capture=\"blockWhenDisabled\"\n @auxclick.capture=\"blockWhenDisabled\"\n >\n <svg v-if=\"loading\" class=\"e-btn-spinner\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /></svg>\n <EIcon v-else-if=\"icon\" :name=\"icon\" />\n <slot />\n </a>\n <button\n v-else\n :type=\"type\"\n class=\"e-btn\"\n :class=\"[variant !== 'primary' && `e-btn--${variant}`, block && 'e-btn--block', loading && 'e-btn--loading']\"\n :disabled=\"disabled\"\n :aria-busy=\"loading ? 'true' : undefined\"\n @click.capture=\"blockWhenDisabled\"\n >\n <svg v-if=\"loading\" class=\"e-btn-spinner\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"9\" /></svg>\n <EIcon v-else-if=\"icon\" :name=\"icon\" />\n <slot />\n </button>\n</template>\n\n<style>\n@layer e.primitives {\n .e-btn {\n --e-fill: var(--e-primary);\n --e-on-fill: var(--e-on-primary);\n --e-slab: color-mix(in srgb, var(--e-fill), var(--e-shade-slab));\n --e-hover: color-mix(in srgb, var(--e-fill), var(--e-shade-hover));\n --e-press: color-mix(in srgb, var(--e-fill), var(--e-shade-press));\n\n /* One border, one control height tall. The slab is the bottom edge made thicker by the lift; the radius tapers it up the corners. Pressing sinks the face over it. */\n --e-lift: var(--e-depth);\n --e-ring: var(--e-slab);\n\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--e-space-2);\n height: var(--e-control-height);\n padding: 0 calc(var(--e-space-4) - var(--e-stroke-edge));\n box-sizing: border-box;\n border: var(--e-stroke-edge) solid var(--e-ring);\n border-bottom-width: calc(var(--e-stroke-edge) + var(--e-lift));\n border-radius: var(--e-radius-md);\n background-color: var(--e-fill);\n\n /* A solid face runs under its border so no page colour shows between them. */\n background-clip: border-box;\n color: var(--e-on-fill);\n font: 500 var(--e-text-md) / 1 var(--e-font-sans);\n letter-spacing: 0.01em;\n white-space: nowrap;\n text-decoration: none;\n cursor: pointer;\n transition:\n border-color var(--e-duration-tap) var(--e-easing-out),\n background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-btn:hover {\n --e-slab: color-mix(in srgb, var(--e-hover), var(--e-shade-slab));\n\n background-color: var(--e-hover);\n }\n\n .e-btn:active {\n --e-lift: 0px;\n\n background-color: var(--e-press);\n }\n\n .e-btn--secondary {\n --e-fill: var(--e-secondary);\n --e-on-fill: var(--e-on-secondary);\n }\n\n .e-btn--danger {\n --e-fill: var(--e-danger);\n --e-on-fill: var(--e-on-danger);\n }\n\n .e-btn--outline {\n --e-fill: var(--e-surface);\n --e-on-fill: var(--e-ink);\n --e-slab: var(--e-border-strong);\n\n background-clip: padding-box;\n }\n\n .e-btn--outline:hover {\n --e-ring: var(--e-ink);\n --e-slab: var(--e-ink);\n\n background-color: color-mix(in srgb, var(--e-surface), var(--e-shade-hover));\n }\n\n .e-btn--outline:active {\n --e-ring: var(--e-ink);\n --e-slab: var(--e-ink);\n\n background-color: color-mix(in srgb, var(--e-surface), var(--e-shade-press));\n }\n\n .e-btn--quiet {\n --e-ring: transparent;\n --e-lift: 0px;\n\n background: transparent;\n color: var(--e-ink);\n padding-inline: calc(var(--e-space-3) - var(--e-stroke-edge));\n text-decoration: underline;\n text-underline-offset: 5px;\n text-decoration-thickness: var(--e-stroke-edge);\n text-decoration-color: var(--e-border-strong);\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):hover {\n --e-ring: var(--e-wash-ring);\n\n background: var(--e-wash-hover);\n text-decoration-color: currentcolor;\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):active {\n --e-ring: var(--e-ink);\n\n background: var(--e-wash-press);\n transform: none;\n }\n\n .e-btn .e-icon,\n .e-btn-spinner {\n margin-inline-start: calc(-0.5 * var(--e-space-1));\n }\n\n .e-btn-spinner {\n flex: none;\n width: 1.125em;\n height: 1.125em;\n fill: none;\n stroke: currentcolor;\n stroke-width: 3;\n stroke-linecap: round;\n stroke-dasharray: 36 56;\n animation: e-btn-spin 0.9s linear infinite;\n }\n\n /* Busy reads as unavailable and in progress: a soft tint of the button's colour with a dashed edge like a disabled button, and stripes that move. The edge is a pseudo-element, so a page's focus reset cannot remove it. */\n .e-btn--loading {\n --e-lift: 0px;\n --e-tint: var(--e-fill);\n --e-busy: color-mix(in srgb, var(--e-tint) 80%, var(--e-ink));\n }\n\n .e-btn--outline.e-btn--loading {\n --e-tint: var(--e-border-strong);\n }\n\n .e-btn--loading,\n .e-btn--loading:hover,\n .e-btn--loading:active {\n background-color: color-mix(in srgb, var(--e-tint) 14%, var(--e-surface));\n background-image: repeating-linear-gradient(135deg, transparent 0 8px, color-mix(in srgb, var(--e-tint) 20%, transparent) 8px 16px);\n background-size: 22.63px 22.63px;\n background-clip: padding-box;\n border-color: transparent;\n color: var(--e-busy);\n transform: none;\n cursor: not-allowed;\n animation: e-btn-stripes 0.8s linear infinite;\n }\n\n .e-btn--loading::before {\n content: \"\";\n position: absolute;\n inset: calc(-1 * var(--e-stroke-edge));\n border: var(--e-stroke-edge) dashed var(--e-busy);\n border-radius: inherit;\n pointer-events: none;\n }\n\n @keyframes e-btn-stripes {\n to {\n background-position-x: 22.63px;\n }\n }\n\n @keyframes e-btn-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n .e-btn--block {\n width: 100%;\n }\n\n /* A toggle: any button with aria-pressed=\"true\" reads as selected. */\n .e-btn[aria-pressed=\"true\"],\n .e-btn[aria-pressed=\"true\"]:hover,\n .e-btn[aria-pressed=\"true\"]:active {\n --e-slab: var(--e-primary);\n --e-ring: var(--e-primary);\n\n background-color: var(--e-surface-hover);\n color: var(--e-primary);\n }\n\n .e-btn[disabled],\n .e-btn[aria-disabled=\"true\"] {\n --e-lift: 0px;\n\n cursor: not-allowed;\n background: transparent;\n color: var(--e-muted);\n outline: var(--e-stroke-edge) dashed var(--e-border-strong);\n outline-offset: calc(-1 * var(--e-stroke-edge));\n border-color: transparent;\n transform: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-btn {\n transition: none;\n }\n\n .e-btn-spinner {\n animation-duration: 3s;\n }\n\n .e-btn--loading {\n animation: none;\n }\n }\n\n @media print {\n .e-btn {\n display: none;\n }\n }\n\n @media (forced-colors: active) {\n .e-btn {\n border: var(--e-stroke-focus) solid ButtonText;\n }\n\n .e-btn[aria-pressed=\"true\"] {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .e-btn[disabled],\n .e-btn[aria-disabled=\"true\"] {\n outline-color: GrayText;\n color: GrayText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKA,IAAMc,IAAQC;EA2Bd,SAASC,EAAkB,GAAc;GACvC,CAAKF,EAAM,YAAaA,EAAM,aAC9BG,EAAM,eAAe,GACrBA,EAAM,yBAAyB;EACjC;E,iBAKUF,EAAA,QADRf,EAAA,GAAAC,EAgBI,KAAA;;GAdD,MAAMc,EAAA;GACP,OAAKb,EAAA,CAAC,SAAO;IACJa,EAAA,YAAO,aAAA,UAA4BA,EAAA;IAAWA,EAAA,SAAK;IAAoBA,EAAA,WAAO;GAAA,CAAA,CAAA;GACtF,QAAQA,EAAA,WAAQ,WAAc,KAAA;GAC9B,KAAKA,EAAA,WAAQ,eAAkB,KAAA;GAC/B,iBAAeA,EAAA,WAAQ,SAAY,KAAA;GACnC,aAAWA,EAAA,UAAO,SAAY,KAAA;GAC9B,UAAUA,EAAA,WAAQ,KAAQ,KAAA;GACX,gBAAAC;GACG,mBAAAA;E,IAERD,EAAA,WAAXf,EAAA,GAAAC,EAAuH,OAAvHS,GAAuH,CAAA,GAAA,AAAAW,EAAA,OAAA,CAAtClB,EAAgC,UAAA;GAAxB,IAAG;GAAK,IAAG;GAAK,GAAE;E,mBACzFY,EAAA,QAAlBf,EAAA,GAAAI,EAAuCC,GAAA;;GAAd,MAAMU,EAAA;E,oCAC/BR,EAAQmB,EAAA,QAAA,SAAA,C,cAEV1B,EAAA,GAAAC,EAYS,UAAA;;GAVN,MAAMc,EAAA;GACP,OAAKb,EAAA,CAAC,SAAO;IACJa,EAAA,YAAO,aAAA,UAA4BA,EAAA;IAAWA,EAAA,SAAK;IAAoBA,EAAA,WAAO;GAAA,CAAA,CAAA;GACtF,UAAUA,EAAA;GACV,aAAWA,EAAA,UAAO,SAAY,KAAA;GACf,gBAAAC;E,IAELD,EAAA,WAAXf,EAAA,GAAAC,EAAuH,OAAvHW,GAAuH,CAAA,GAAA,AAAAS,EAAA,OAAA,CAAtClB,EAAgC,UAAA;GAAxB,IAAG;GAAK,IAAG;GAAK,GAAE;E,mBACzFY,EAAA,QAAlBf,EAAA,GAAAI,EAAuCC,GAAA;;GAAd,MAAMU,EAAA;E,oCAC/BR,EAAQmB,EAAA,QAAA,SAAA,C"}
@@ -1 +1 @@
1
- {"version":3,"file":"EComboboxBase.js","names":["_sfc_main","EComboboxBase_vue_vue_type_script_setup_true_lang_default","EComboboxBase_default"],"sources":["../../../src/components/Combobox/EComboboxBase.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, h, nextTick, onMounted, ref, watch, type FunctionalComponent } from \"vue\";\nimport {\n ComboboxAnchor,\n ComboboxContent,\n ComboboxInput,\n ComboboxPortal,\n ComboboxRoot,\n ComboboxTrigger,\n ComboboxViewport,\n} from \"reka-ui\";\nimport EField from \"../Field/EField.vue\";\nimport EIcon from \"../Icon/EIcon.vue\";\nimport ESpinner from \"../Spinner/ESpinner.vue\";\nimport EComboboxOption from \"./EComboboxOption.vue\";\nimport { normalizeOptions, sectionOptions } from \"../Select/options.js\";\nimport type { EComboboxProps } from \"./types.js\";\nimport { useMessages, usePortalTarget } from \"../../config.js\";\nimport { useFieldAttrs } from \"../../composables/useFieldAttrs.js\";\nimport { useUid } from \"../../composables/useUid.js\";\nimport \"../../styles/base.css\";\nimport \"../TextField/input.css\";\nimport \"../Select/panel.css\";\nimport \"./combo.css\";\n\ndefineOptions({ inheritAttrs: false });\n\nconst props = withDefaults(defineProps<EComboboxProps>(), {\n clearable: true,\n});\n\nconst emit = defineEmits<{\n /** The text in the input changed, by typing or by choosing. Use it to fetch options from a server. */\n inputChange: [text: string];\n}>();\n\nconst model = defineModel<string | string[]>();\n\nconst t = useMessages();\nconst portal = usePortalTarget();\nconst attrs = useFieldAttrs();\nconst groupId = useUid();\nconst bareId = useUid(() => props.id);\n\nconst Bare: FunctionalComponent = (_, { slots }) =>\n h(\"div\", attrs.wrapper(), slots.default?.({ id: bareId.value, ariaInvalid: undefined, ariaDescribedby: undefined }));\nconst frame = computed(() =>\n props.bare\n ? {}\n : {\n id: props.id,\n label: props.label,\n hideLabel: props.hideLabel,\n hint: props.hint,\n error: props.error,\n required: props.required,\n optional: props.optional,\n },\n);\nconst listName = computed(() => (props.bare ? (props.ariaLabel ?? props.label) : props.label));\n\nconst multiple = computed(() => props.multiple);\n// Free text is for one value; with `multiple` it is ignored.\nconst free = computed(() => props.freeform && !props.multiple);\nconst all = computed(() => normalizeOptions(props.options));\nconst values = computed<string[]>(() => (multiple.value && Array.isArray(model.value) ? model.value : []));\nconst single = computed(() => (typeof model.value === \"string\" ? model.value : \"\"));\nconst rootValue = computed(() => (multiple.value ? values.value : single.value));\n\nfunction labelOf(v: string): string {\n return all.value.find((o) => o.value === v)?.label ?? (free.value ? v : \"\");\n}\nconst resting = () => (multiple.value ? \"\" : labelOf(single.value));\n\nconst text = ref(resting());\nconst typing = ref(false);\nconst wantOpen = defineModel<boolean>(\"open\", { default: false });\nconst anchor = ref<{ $el: HTMLElement } | null>(null);\nconst query = computed(() => (typing.value ? text.value.trim().toLowerCase() : \"\"));\n\nconst shown = computed(() => {\n const q = query.value;\n if (props.filter) return all.value.filter((o) => props.filter!(o, q));\n return all.value.filter(\n (o) => !q || o.label.toLowerCase().includes(q) || (o.description ?? \"\").toLowerCase().includes(q),\n );\n});\nconst sections = computed(() => sectionOptions(shown.value));\nconst hasList = computed(() => shown.value.length > 0 || !!props.loading || !free.value);\nconst open = computed(() => wantOpen.value && hasList.value && !props.disabled);\nconst announce = computed(() =>\n open.value && !shown.value.length ? (props.loading ? t(\"searching\") : props.emptyText || t(\"noMatches\")) : \"\",\n);\nconst hasValue = computed(() => (multiple.value ? values.value.length > 0 : !!text.value));\n\nwatch(rootValue, () => {\n const rest = resting();\n if (rest !== text.value) {\n text.value = rest;\n typing.value = false;\n }\n});\nwatch(all, () => {\n if (!typing.value && !open.value) text.value = resting();\n});\n\nconst listId = ref<string | undefined>();\nconst content = ref<{ $el: HTMLElement } | null>(null);\nonMounted(() => {\n if (!open.value) return;\n let tries = 0;\n const read = () => {\n listId.value = content.value?.$el?.id || undefined;\n if (!listId.value && tries++ < 10) requestAnimationFrame(read);\n };\n void nextTick(read);\n});\n\nconst inputEl = () => anchor.value?.$el?.querySelector(\"input\") ?? null;\nconst focusInput = () => inputEl()?.focus();\n\nfunction isSelected(value: string): boolean {\n return multiple.value ? values.value.includes(value) : free.value ? single.value === value : single.value === value;\n}\nconst itemValue = (o: { value: string; label: string }) => (free.value ? o.label : o.value);\n\nfunction onPick(v: unknown) {\n typing.value = false;\n if (multiple.value) {\n model.value = Array.isArray(v) ? (v as string[]) : [];\n text.value = \"\";\n emit(\"inputChange\", \"\");\n return;\n }\n const next = typeof v === \"string\" ? v : \"\";\n model.value = next;\n text.value = free.value ? next : labelOf(next);\n emit(\"inputChange\", text.value);\n}\n\nfunction onInput(e: Event) {\n const v = (e.target as HTMLInputElement).value;\n text.value = v;\n typing.value = true;\n wantOpen.value = true;\n emit(\"inputChange\", v);\n if (free.value) model.value = v;\n}\n\nfunction remove(v: string) {\n model.value = values.value.filter((x) => x !== v);\n}\n\nfunction clear() {\n model.value = multiple.value ? [] : \"\";\n text.value = \"\";\n typing.value = false;\n emit(\"inputChange\", \"\");\n focusInput();\n}\n\nfunction onKeydown(e: KeyboardEvent) {\n if (e.key === \"Escape\" && !open.value && text.value) {\n e.preventDefault();\n clear();\n } else if (e.key === \"Backspace\" && multiple.value && !text.value && values.value.length) {\n remove(values.value[values.value.length - 1]!);\n }\n}\n\nfunction keepCaretKeys(e: KeyboardEvent) {\n if (e.key === \"Home\" || e.key === \"End\") e.stopImmediatePropagation();\n}\n\nfunction onBlur(e: FocusEvent) {\n const next = e.relatedTarget as Element | null;\n if (next && (anchor.value?.$el?.contains(next) || next.closest?.(\".e-popover\"))) return;\n wantOpen.value = false;\n typing.value = false;\n if (!free.value) text.value = resting();\n}\n\nfunction onWrapDown(e: MouseEvent) {\n if (e.target === e.currentTarget && !props.disabled) {\n e.preventDefault();\n focusInput();\n }\n}\n\ntype FieldSlot = { id: string; ariaInvalid: \"true\" | undefined; ariaDescribedby: string | undefined };\nfunction inputBind(field: FieldSlot) {\n return {\n id: field.id,\n required: props.required && !(multiple.value && values.value.length) ? true : undefined,\n placeholder: multiple.value && values.value.length ? \"\" : props.placeholder,\n \"aria-invalid\": field.ariaInvalid,\n \"aria-label\": props.bare ? listName.value : undefined,\n autocomplete: \"off\",\n ...(listId.value ? { \"aria-controls\": listId.value } : {}),\n ...(shown.value.length ? {} : { \"aria-activedescendant\": undefined }),\n ...attrs.input(field.ariaDescribedby),\n };\n}\n\ndefineExpose({\n input: computed(() => inputEl()),\n focus: focusInput,\n});\n</script>\n\n<template>\n <component :is=\"bare ? Bare : EField\" v-bind=\"{ ...attrs.wrapper(), ...frame }\">\n <template #default=\"field\">\n <ComboboxRoot\n class=\"e-combo-root\"\n :model-value=\"rootValue\"\n :multiple=\"multiple\"\n :open=\"open\"\n :disabled=\"disabled\"\n ignore-filter\n @update:model-value=\"onPick\"\n @update:open=\"wantOpen = $event\"\n >\n <ComboboxAnchor\n ref=\"anchor\"\n class=\"e-input-wrap e-combo\"\n :class=\"{ 'e-combo--multi': multiple }\"\n :data-invalid=\"error && !bare ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n @mousedown=\"onWrapDown\"\n @focusout=\"onBlur\"\n >\n <div class=\"e-combo-main\">\n <template v-if=\"multiple\">\n <span v-for=\"v in values\" :key=\"v\" class=\"e-tag\">\n {{ labelOf(v) }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n class=\"e-tag-x\"\n :aria-label=\"t('removeItem', { label: labelOf(v) })\"\n @click=\"remove(v)\"\n >\n <EIcon name=\"x\" small />\n </button>\n </span>\n </template>\n <ComboboxInput\n class=\"e-input e-combo-input\"\n :model-value=\"text\"\n :display-value=\"(v: unknown) => (typeof v === 'string' ? (free ? v : labelOf(v)) : '')\"\n :disabled=\"disabled\"\n v-bind=\"inputBind(field)\"\n @update:model-value=\"text = $event\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @keydown.capture=\"keepCaretKeys\"\n />\n </div>\n <template v-if=\"name\">\n <input v-for=\"(v, k) in multiple ? values : [single]\" :key=\"k\" type=\"hidden\" :name=\"name\" :value=\"v\" />\n </template>\n <div class=\"e-combo-tail\">\n <button\n v-if=\"hasValue && clearable && !disabled\"\n type=\"button\"\n class=\"e-combo-btn\"\n :aria-label=\"t('clear')\"\n @mousedown.prevent\n @click=\"clear\"\n >\n <EIcon name=\"x\" />\n </button>\n <ComboboxTrigger\n v-if=\"!free\"\n class=\"e-combo-btn\"\n :aria-label=\"t('showOptions')\"\n :disabled=\"disabled\"\n @mousedown.prevent\n >\n <EIcon name=\"chevron-down\" bold />\n </ComboboxTrigger>\n </div>\n </ComboboxAnchor>\n <span class=\"e-sr\" role=\"status\">{{ announce }}</span>\n <ComboboxPortal :to=\"portal\">\n <ComboboxContent\n ref=\"content\"\n position=\"popper\"\n align=\"start\"\n :side-offset=\"6\"\n :collision-padding=\"8\"\n class=\"e-popover e-listpanel e-root\"\n :aria-label=\"listName\"\n :aria-busy=\"loading ? 'true' : undefined\"\n >\n <ComboboxViewport>\n <template v-if=\"shown.length\">\n <template v-for=\"(section, i) in sections\" :key=\"i\">\n <div v-if=\"section.group\" class=\"e-opt-set\" role=\"group\" :aria-labelledby=\"`${groupId}-g${i}`\">\n <div :id=\"`${groupId}-g${i}`\" class=\"e-opt-group\">{{ section.group }}</div>\n <EComboboxOption\n v-for=\"o in section.options\"\n :key=\"o.value\"\n :option=\"o\"\n :value=\"itemValue(o)\"\n :selected=\"isSelected(itemValue(o))\"\n :query=\"query\"\n />\n </div>\n <template v-else>\n <EComboboxOption\n v-for=\"o in section.options\"\n :key=\"o.value\"\n :option=\"o\"\n :value=\"itemValue(o)\"\n :selected=\"isSelected(itemValue(o))\"\n :query=\"query\"\n />\n </template>\n </template>\n </template>\n <div v-else class=\"e-opt-status\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n <ESpinner v-if=\"loading\" :label=\"t('searching')\" />\n <template v-else>{{ emptyText || t(\"noMatches\") }}</template>\n </div>\n </ComboboxViewport>\n </ComboboxContent>\n </ComboboxPortal>\n </ComboboxRoot>\n </template>\n </component>\n</template>\n\n<style>\n@layer e.controls {\n .e-combo-main {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n align-self: stretch;\n gap: var(--e-space-1);\n min-width: 0;\n }\n\n .e-combo-tail {\n display: flex;\n flex: none;\n align-items: center;\n align-self: center;\n }\n\n .e-combo--multi {\n padding: 3px var(--e-space-1) 3px var(--e-space-2);\n gap: var(--e-space-1);\n }\n\n .e-combo--multi .e-input {\n height: calc(var(--e-control-height) - 9px);\n align-self: center;\n padding-inline: var(--e-space-2);\n }\n\n .e-combo-main .e-tag:not(:has(.e-tag-x)) {\n padding-inline-end: var(--e-space-3);\n }\n\n .e-tag {\n display: inline-flex;\n align-items: center;\n gap: var(--e-space-1);\n height: var(--e-space-8);\n padding: 0 var(--e-space-1) 0 var(--e-space-3);\n border-radius: var(--e-radius-pill);\n background: var(--e-surface-tint);\n box-shadow: inset 0 0 0 var(--e-stroke-card) var(--e-primary);\n color: var(--e-ink);\n font: 500 var(--e-text-sm)/1 var(--e-font-sans);\n }\n\n .e-tag-x::after {\n content: \"\";\n position: absolute;\n inset: calc((var(--e-tap) - var(--e-space-6)) / -2);\n }\n\n .e-tag-x {\n position: relative;\n display: inline-grid;\n place-items: center;\n width: var(--e-space-6);\n height: var(--e-space-6);\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--e-primary);\n cursor: pointer;\n }\n\n .e-tag-x:hover {\n background: var(--e-wash-hover);\n box-shadow: inset 0 0 0 var(--e-stroke-card) var(--e-primary);\n }\n\n .e-tag-x:active {\n background: var(--e-wash-press);\n }\n\n .e-tag-x:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n @media (forced-colors: active) {\n .e-tag {\n outline: var(--e-stroke-card) solid CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"EComboboxBase.js","names":["_sfc_main","EComboboxBase_vue_vue_type_script_setup_true_lang_default","EComboboxBase_default"],"sources":["../../../src/components/Combobox/EComboboxBase.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, h, nextTick, onMounted, ref, watch, type FunctionalComponent } from \"vue\";\nimport {\n ComboboxAnchor,\n ComboboxContent,\n ComboboxInput,\n ComboboxPortal,\n ComboboxRoot,\n ComboboxTrigger,\n ComboboxViewport,\n} from \"reka-ui\";\nimport EField from \"../Field/EField.vue\";\nimport EIcon from \"../Icon/EIcon.vue\";\nimport ESpinner from \"../Spinner/ESpinner.vue\";\nimport EComboboxOption from \"./EComboboxOption.vue\";\nimport { normalizeOptions, sectionOptions } from \"../Select/options.js\";\nimport type { EComboboxProps } from \"./types.js\";\nimport { useMessages, usePortalTarget } from \"../../config.js\";\nimport { useFieldAttrs } from \"../../composables/useFieldAttrs.js\";\nimport { useUid } from \"../../composables/useUid.js\";\nimport \"../../styles/base.css\";\nimport \"../TextField/input.css\";\nimport \"../Select/panel.css\";\nimport \"./combo.css\";\n\ndefineOptions({ inheritAttrs: false });\n\nconst props = withDefaults(defineProps<EComboboxProps>(), {\n clearable: true,\n});\n\nconst emit = defineEmits<{\n /** The text in the input changed, by typing or by choosing. Use it to fetch options from a server. */\n inputChange: [text: string];\n}>();\n\nconst model = defineModel<string | string[]>();\n\nconst t = useMessages();\nconst portal = usePortalTarget();\nconst attrs = useFieldAttrs();\nconst groupId = useUid();\nconst bareId = useUid(() => props.id);\n\nconst Bare: FunctionalComponent = (_, { slots }) =>\n h(\"div\", attrs.wrapper(), slots.default?.({ id: bareId.value, ariaInvalid: undefined, ariaDescribedby: undefined }));\nconst frame = computed(() =>\n props.bare\n ? {}\n : {\n id: props.id,\n label: props.label,\n hideLabel: props.hideLabel,\n hint: props.hint,\n error: props.error,\n required: props.required,\n optional: props.optional,\n },\n);\nconst listName = computed(() => (props.bare ? (props.ariaLabel ?? props.label) : props.label));\n\nconst multiple = computed(() => props.multiple);\n// Free text is for one value; with `multiple` it is ignored.\nconst free = computed(() => props.freeform && !props.multiple);\nconst all = computed(() => normalizeOptions(props.options));\nconst values = computed<string[]>(() => (multiple.value && Array.isArray(model.value) ? model.value : []));\nconst single = computed(() => (typeof model.value === \"string\" ? model.value : \"\"));\nconst rootValue = computed(() => (multiple.value ? values.value : single.value));\n\nfunction labelOf(v: string): string {\n return all.value.find((o) => o.value === v)?.label ?? (free.value ? v : \"\");\n}\nconst resting = () => (multiple.value ? \"\" : labelOf(single.value));\n\nconst text = ref(resting());\nconst typing = ref(false);\nconst wantOpen = defineModel<boolean>(\"open\", { default: false });\nconst anchor = ref<{ $el: HTMLElement } | null>(null);\nconst query = computed(() => (typing.value ? text.value.trim().toLowerCase() : \"\"));\n\nconst shown = computed(() => {\n const q = query.value;\n if (props.filter) return all.value.filter((o) => props.filter!(o, q));\n return all.value.filter(\n (o) => !q || o.label.toLowerCase().includes(q) || (o.description ?? \"\").toLowerCase().includes(q),\n );\n});\nconst sections = computed(() => sectionOptions(shown.value));\nconst hasList = computed(() => shown.value.length > 0 || !!props.loading || !free.value);\nconst open = computed(() => wantOpen.value && hasList.value && !props.disabled);\nconst announce = computed(() =>\n open.value && !shown.value.length ? (props.loading ? t(\"searching\") : props.emptyText || t(\"noMatches\")) : \"\",\n);\nconst hasValue = computed(() => (multiple.value ? values.value.length > 0 : !!text.value));\n\nwatch(rootValue, () => {\n const rest = resting();\n if (rest !== text.value) {\n text.value = rest;\n typing.value = false;\n }\n});\nwatch(all, () => {\n if (!typing.value && !open.value) text.value = resting();\n});\n\nconst listId = ref<string | undefined>();\nconst content = ref<{ $el: HTMLElement } | null>(null);\nonMounted(() => {\n if (!open.value) return;\n let tries = 0;\n const read = () => {\n listId.value = content.value?.$el?.id || undefined;\n if (!listId.value && tries++ < 10) requestAnimationFrame(read);\n };\n void nextTick(read);\n});\n\nconst inputEl = () => anchor.value?.$el?.querySelector(\"input\") ?? null;\nconst focusInput = () => inputEl()?.focus();\n\nfunction isSelected(value: string): boolean {\n return multiple.value ? values.value.includes(value) : free.value ? single.value === value : single.value === value;\n}\nconst itemValue = (o: { value: string; label: string }) => (free.value ? o.label : o.value);\n\nfunction onPick(v: unknown) {\n typing.value = false;\n if (multiple.value) {\n model.value = Array.isArray(v) ? (v as string[]) : [];\n text.value = \"\";\n emit(\"inputChange\", \"\");\n return;\n }\n const next = typeof v === \"string\" ? v : \"\";\n model.value = next;\n text.value = free.value ? next : labelOf(next);\n emit(\"inputChange\", text.value);\n}\n\nfunction onInput(e: Event) {\n const v = (e.target as HTMLInputElement).value;\n text.value = v;\n typing.value = true;\n wantOpen.value = true;\n emit(\"inputChange\", v);\n if (free.value) model.value = v;\n}\n\nfunction remove(v: string) {\n model.value = values.value.filter((x) => x !== v);\n}\n\nfunction clear() {\n model.value = multiple.value ? [] : \"\";\n text.value = \"\";\n typing.value = false;\n emit(\"inputChange\", \"\");\n focusInput();\n}\n\nfunction onKeydown(e: KeyboardEvent) {\n if (e.key === \"Escape\" && !open.value && text.value) {\n e.preventDefault();\n clear();\n } else if (e.key === \"Backspace\" && multiple.value && !text.value && values.value.length) {\n remove(values.value[values.value.length - 1]!);\n }\n}\n\nfunction keepCaretKeys(e: KeyboardEvent) {\n if (e.key === \"Home\" || e.key === \"End\") e.stopImmediatePropagation();\n}\n\nfunction onBlur(e: FocusEvent) {\n const next = e.relatedTarget as Element | null;\n if (next && (anchor.value?.$el?.contains(next) || next.closest?.(\".e-popover\"))) return;\n wantOpen.value = false;\n typing.value = false;\n if (!free.value) text.value = resting();\n}\n\nfunction onWrapDown(e: MouseEvent) {\n if (e.target === e.currentTarget && !props.disabled) {\n e.preventDefault();\n focusInput();\n }\n}\n\ntype FieldSlot = { id: string; ariaInvalid: \"true\" | undefined; ariaDescribedby: string | undefined };\nfunction inputBind(field: FieldSlot) {\n return {\n id: field.id,\n required: props.required && !(multiple.value && values.value.length) ? true : undefined,\n placeholder: multiple.value && values.value.length ? \"\" : props.placeholder,\n \"aria-invalid\": field.ariaInvalid,\n \"aria-label\": props.bare ? listName.value : undefined,\n autocomplete: \"off\",\n ...(listId.value ? { \"aria-controls\": listId.value } : {}),\n ...(shown.value.length ? {} : { \"aria-activedescendant\": undefined }),\n ...attrs.input(field.ariaDescribedby),\n };\n}\n\ndefineExpose({\n input: computed(() => inputEl()),\n focus: focusInput,\n});\n</script>\n\n<template>\n <component :is=\"bare ? Bare : EField\" v-bind=\"{ ...attrs.wrapper(), ...frame }\">\n <template #default=\"field\">\n <ComboboxRoot\n class=\"e-combo-root\"\n :model-value=\"rootValue\"\n :multiple=\"multiple\"\n :open=\"open\"\n :disabled=\"disabled\"\n ignore-filter\n @update:model-value=\"onPick\"\n @update:open=\"wantOpen = $event\"\n >\n <ComboboxAnchor\n ref=\"anchor\"\n class=\"e-input-wrap e-combo\"\n :class=\"{ 'e-combo--multi': multiple }\"\n :data-invalid=\"error && !bare ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n @mousedown=\"onWrapDown\"\n @focusout=\"onBlur\"\n >\n <div class=\"e-combo-main\">\n <template v-if=\"multiple\">\n <span v-for=\"v in values\" :key=\"v\" class=\"e-tag\">\n {{ labelOf(v) }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n class=\"e-tag-x\"\n :aria-label=\"t('removeItem', { label: labelOf(v) })\"\n @click=\"remove(v)\"\n >\n <EIcon name=\"x\" small />\n </button>\n </span>\n </template>\n <ComboboxInput\n class=\"e-input e-combo-input\"\n :model-value=\"text\"\n :display-value=\"(v: unknown) => (typeof v === 'string' ? (free ? v : labelOf(v)) : '')\"\n :disabled=\"disabled\"\n v-bind=\"inputBind(field)\"\n @update:model-value=\"text = $event\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @keydown.capture=\"keepCaretKeys\"\n />\n </div>\n <template v-if=\"name\">\n <input v-for=\"(v, k) in multiple ? values : [single]\" :key=\"k\" type=\"hidden\" :name=\"name\" :value=\"v\" />\n </template>\n <div class=\"e-combo-tail\">\n <button\n v-if=\"hasValue && clearable && !disabled\"\n type=\"button\"\n class=\"e-combo-btn\"\n :aria-label=\"t('clear')\"\n @mousedown.prevent\n @click=\"clear\"\n >\n <EIcon name=\"x\" />\n </button>\n <ComboboxTrigger\n v-if=\"!free\"\n class=\"e-combo-btn\"\n :aria-label=\"t('showOptions')\"\n :disabled=\"disabled\"\n @mousedown.prevent\n >\n <EIcon name=\"chevron-down\" bold />\n </ComboboxTrigger>\n </div>\n </ComboboxAnchor>\n <span class=\"e-sr\" role=\"status\">{{ announce }}</span>\n <ComboboxPortal :to=\"portal\">\n <ComboboxContent\n ref=\"content\"\n position=\"popper\"\n align=\"start\"\n :side-offset=\"6\"\n :collision-padding=\"8\"\n class=\"e-popover e-listpanel e-root\"\n :aria-label=\"listName\"\n :aria-busy=\"loading ? 'true' : undefined\"\n >\n <ComboboxViewport>\n <template v-if=\"shown.length\">\n <template v-for=\"(section, i) in sections\" :key=\"i\">\n <div v-if=\"section.group\" class=\"e-opt-set\" role=\"group\" :aria-labelledby=\"`${groupId}-g${i}`\">\n <div :id=\"`${groupId}-g${i}`\" class=\"e-opt-group\">{{ section.group }}</div>\n <EComboboxOption\n v-for=\"o in section.options\"\n :key=\"o.value\"\n :option=\"o\"\n :value=\"itemValue(o)\"\n :selected=\"isSelected(itemValue(o))\"\n :query=\"query\"\n />\n </div>\n <template v-else>\n <EComboboxOption\n v-for=\"o in section.options\"\n :key=\"o.value\"\n :option=\"o\"\n :value=\"itemValue(o)\"\n :selected=\"isSelected(itemValue(o))\"\n :query=\"query\"\n />\n </template>\n </template>\n </template>\n <div v-else class=\"e-opt-status\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n <ESpinner v-if=\"loading\" :label=\"t('searching')\" />\n <template v-else>{{ emptyText || t(\"noMatches\") }}</template>\n </div>\n </ComboboxViewport>\n </ComboboxContent>\n </ComboboxPortal>\n </ComboboxRoot>\n </template>\n </component>\n</template>\n\n<style>\n@layer e.controls {\n .e-combo-main {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n align-self: stretch;\n gap: var(--e-space-1);\n min-width: 0;\n }\n\n .e-combo-tail {\n display: flex;\n flex: none;\n align-items: center;\n align-self: center;\n }\n\n .e-combo--multi {\n padding: calc(3px - var(--e-stroke-edge)) calc(var(--e-space-1) - var(--e-stroke-edge)) calc(3px - var(--e-stroke-edge)) calc(var(--e-space-2) - var(--e-stroke-edge));\n gap: var(--e-space-1);\n }\n\n .e-combo--multi .e-input {\n height: calc(var(--e-control-height) - 9px);\n align-self: center;\n padding-inline: var(--e-space-2);\n }\n\n .e-combo-main .e-tag:not(:has(.e-tag-x)) {\n padding-inline-end: var(--e-space-3);\n }\n\n .e-tag {\n display: inline-flex;\n align-items: center;\n gap: var(--e-space-1);\n height: var(--e-space-8);\n padding: 0 var(--e-space-1) 0 var(--e-space-3);\n border-radius: var(--e-radius-pill);\n background: var(--e-surface-tint);\n box-shadow: inset 0 0 0 var(--e-stroke-card) var(--e-primary);\n color: var(--e-ink);\n font: 500 var(--e-text-sm)/1 var(--e-font-sans);\n }\n\n .e-tag-x::after {\n content: \"\";\n position: absolute;\n inset: calc((var(--e-tap) - var(--e-space-6)) / -2);\n }\n\n .e-tag-x {\n position: relative;\n display: inline-grid;\n place-items: center;\n width: var(--e-space-6);\n height: var(--e-space-6);\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--e-primary);\n cursor: pointer;\n }\n\n .e-tag-x:hover {\n background: var(--e-wash-hover);\n box-shadow: inset 0 0 0 var(--e-stroke-card) var(--e-primary);\n }\n\n .e-tag-x:active {\n background: var(--e-wash-press);\n }\n\n .e-tag-x:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n @media (forced-colors: active) {\n .e-tag {\n outline: var(--e-stroke-card) solid CanvasText;\n }\n }\n}\n</style>\n"],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"EComboboxBase.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_resolveDynamicComponent","EField","_normalizeProps","_guardReactiveProps","_unref","_withCtx","_createVNode","_normalizeClass","_createElementVNode","_createElementBlock","_Fragment","_renderList","_createTextVNode","_toDisplayString","EIcon","_createCommentVNode","_mergeProps","_withModifiers","EComboboxOption","ESpinner","EIcon_default","EField_default","ESpinner_default","EComboboxOption_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","EComboboxBase_vue_vue_type_script_setup_true_lang_default","\"modelValue\"","\"modelModifiers\"","\"open\"","\"openModifiers\"","__expose","__emit","props","__props","emit","model","useModel","t","useMessages","portal","usePortalTarget","attrs","useFieldAttrs","groupId","useUid","bareId","Bare","h","slots","frame","computed","listName","multiple","free","all","normalizeOptions","values","single","rootValue","labelOf","o","v","resting","text","ref","typing","wantOpen","anchor","query","shown","q","sections","sectionOptions","hasList","open","announce","hasValue","watch","rest","listId","content","tries","read","inputEl","focusInput","isSelected","value","itemValue","onPick","next","onInput","remove","x","clear","onKeydown","keepCaretKeys","onBlur","onWrapDown","inputBind","field","openBlock","createBlock","resolveDynamicComponent","normalizeProps","guardReactiveProps","unref","withCtx","createVNode","ComboboxRoot","_cache","$event","ComboboxAnchor","normalizeClass","createElementVNode","createElementBlock","Fragment","renderList","createTextVNode","toDisplayString","createCommentVNode","ComboboxInput","mergeProps","k","withModifiers","ComboboxTrigger","ComboboxPortal","ComboboxContent","ComboboxViewport","i","section"],"sources":["../../../src/components/Combobox/EComboboxBase.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, h, nextTick, onMounted, ref, watch, type FunctionalComponent } from \"vue\";\nimport {\n ComboboxAnchor,\n ComboboxContent,\n ComboboxInput,\n ComboboxPortal,\n ComboboxRoot,\n ComboboxTrigger,\n ComboboxViewport,\n} from \"reka-ui\";\nimport EField from \"../Field/EField.vue\";\nimport EIcon from \"../Icon/EIcon.vue\";\nimport ESpinner from \"../Spinner/ESpinner.vue\";\nimport EComboboxOption from \"./EComboboxOption.vue\";\nimport { normalizeOptions, sectionOptions } from \"../Select/options.js\";\nimport type { EComboboxProps } from \"./types.js\";\nimport { useMessages, usePortalTarget } from \"../../config.js\";\nimport { useFieldAttrs } from \"../../composables/useFieldAttrs.js\";\nimport { useUid } from \"../../composables/useUid.js\";\nimport \"../../styles/base.css\";\nimport \"../TextField/input.css\";\nimport \"../Select/panel.css\";\nimport \"./combo.css\";\n\ndefineOptions({ inheritAttrs: false });\n\nconst props = withDefaults(defineProps<EComboboxProps>(), {\n clearable: true,\n});\n\nconst emit = defineEmits<{\n /** The text in the input changed, by typing or by choosing. Use it to fetch options from a server. */\n inputChange: [text: string];\n}>();\n\nconst model = defineModel<string | string[]>();\n\nconst t = useMessages();\nconst portal = usePortalTarget();\nconst attrs = useFieldAttrs();\nconst groupId = useUid();\nconst bareId = useUid(() => props.id);\n\nconst Bare: FunctionalComponent = (_, { slots }) =>\n h(\"div\", attrs.wrapper(), slots.default?.({ id: bareId.value, ariaInvalid: undefined, ariaDescribedby: undefined }));\nconst frame = computed(() =>\n props.bare\n ? {}\n : {\n id: props.id,\n label: props.label,\n hideLabel: props.hideLabel,\n hint: props.hint,\n error: props.error,\n required: props.required,\n optional: props.optional,\n },\n);\nconst listName = computed(() => (props.bare ? (props.ariaLabel ?? props.label) : props.label));\n\nconst multiple = computed(() => props.multiple);\n// Free text is for one value; with `multiple` it is ignored.\nconst free = computed(() => props.freeform && !props.multiple);\nconst all = computed(() => normalizeOptions(props.options));\nconst values = computed<string[]>(() => (multiple.value && Array.isArray(model.value) ? model.value : []));\nconst single = computed(() => (typeof model.value === \"string\" ? model.value : \"\"));\nconst rootValue = computed(() => (multiple.value ? values.value : single.value));\n\nfunction labelOf(v: string): string {\n return all.value.find((o) => o.value === v)?.label ?? (free.value ? v : \"\");\n}\nconst resting = () => (multiple.value ? \"\" : labelOf(single.value));\n\nconst text = ref(resting());\nconst typing = ref(false);\nconst wantOpen = defineModel<boolean>(\"open\", { default: false });\nconst anchor = ref<{ $el: HTMLElement } | null>(null);\nconst query = computed(() => (typing.value ? text.value.trim().toLowerCase() : \"\"));\n\nconst shown = computed(() => {\n const q = query.value;\n if (props.filter) return all.value.filter((o) => props.filter!(o, q));\n return all.value.filter(\n (o) => !q || o.label.toLowerCase().includes(q) || (o.description ?? \"\").toLowerCase().includes(q),\n );\n});\nconst sections = computed(() => sectionOptions(shown.value));\nconst hasList = computed(() => shown.value.length > 0 || !!props.loading || !free.value);\nconst open = computed(() => wantOpen.value && hasList.value && !props.disabled);\nconst announce = computed(() =>\n open.value && !shown.value.length ? (props.loading ? t(\"searching\") : props.emptyText || t(\"noMatches\")) : \"\",\n);\nconst hasValue = computed(() => (multiple.value ? values.value.length > 0 : !!text.value));\n\nwatch(rootValue, () => {\n const rest = resting();\n if (rest !== text.value) {\n text.value = rest;\n typing.value = false;\n }\n});\nwatch(all, () => {\n if (!typing.value && !open.value) text.value = resting();\n});\n\nconst listId = ref<string | undefined>();\nconst content = ref<{ $el: HTMLElement } | null>(null);\nonMounted(() => {\n if (!open.value) return;\n let tries = 0;\n const read = () => {\n listId.value = content.value?.$el?.id || undefined;\n if (!listId.value && tries++ < 10) requestAnimationFrame(read);\n };\n void nextTick(read);\n});\n\nconst inputEl = () => anchor.value?.$el?.querySelector(\"input\") ?? null;\nconst focusInput = () => inputEl()?.focus();\n\nfunction isSelected(value: string): boolean {\n return multiple.value ? values.value.includes(value) : free.value ? single.value === value : single.value === value;\n}\nconst itemValue = (o: { value: string; label: string }) => (free.value ? o.label : o.value);\n\nfunction onPick(v: unknown) {\n typing.value = false;\n if (multiple.value) {\n model.value = Array.isArray(v) ? (v as string[]) : [];\n text.value = \"\";\n emit(\"inputChange\", \"\");\n return;\n }\n const next = typeof v === \"string\" ? v : \"\";\n model.value = next;\n text.value = free.value ? next : labelOf(next);\n emit(\"inputChange\", text.value);\n}\n\nfunction onInput(e: Event) {\n const v = (e.target as HTMLInputElement).value;\n text.value = v;\n typing.value = true;\n wantOpen.value = true;\n emit(\"inputChange\", v);\n if (free.value) model.value = v;\n}\n\nfunction remove(v: string) {\n model.value = values.value.filter((x) => x !== v);\n}\n\nfunction clear() {\n model.value = multiple.value ? [] : \"\";\n text.value = \"\";\n typing.value = false;\n emit(\"inputChange\", \"\");\n focusInput();\n}\n\nfunction onKeydown(e: KeyboardEvent) {\n if (e.key === \"Escape\" && !open.value && text.value) {\n e.preventDefault();\n clear();\n } else if (e.key === \"Backspace\" && multiple.value && !text.value && values.value.length) {\n remove(values.value[values.value.length - 1]!);\n }\n}\n\nfunction keepCaretKeys(e: KeyboardEvent) {\n if (e.key === \"Home\" || e.key === \"End\") e.stopImmediatePropagation();\n}\n\nfunction onBlur(e: FocusEvent) {\n const next = e.relatedTarget as Element | null;\n if (next && (anchor.value?.$el?.contains(next) || next.closest?.(\".e-popover\"))) return;\n wantOpen.value = false;\n typing.value = false;\n if (!free.value) text.value = resting();\n}\n\nfunction onWrapDown(e: MouseEvent) {\n if (e.target === e.currentTarget && !props.disabled) {\n e.preventDefault();\n focusInput();\n }\n}\n\ntype FieldSlot = { id: string; ariaInvalid: \"true\" | undefined; ariaDescribedby: string | undefined };\nfunction inputBind(field: FieldSlot) {\n return {\n id: field.id,\n required: props.required && !(multiple.value && values.value.length) ? true : undefined,\n placeholder: multiple.value && values.value.length ? \"\" : props.placeholder,\n \"aria-invalid\": field.ariaInvalid,\n \"aria-label\": props.bare ? listName.value : undefined,\n autocomplete: \"off\",\n ...(listId.value ? { \"aria-controls\": listId.value } : {}),\n ...(shown.value.length ? {} : { \"aria-activedescendant\": undefined }),\n ...attrs.input(field.ariaDescribedby),\n };\n}\n\ndefineExpose({\n input: computed(() => inputEl()),\n focus: focusInput,\n});\n</script>\n\n<template>\n <component :is=\"bare ? Bare : EField\" v-bind=\"{ ...attrs.wrapper(), ...frame }\">\n <template #default=\"field\">\n <ComboboxRoot\n class=\"e-combo-root\"\n :model-value=\"rootValue\"\n :multiple=\"multiple\"\n :open=\"open\"\n :disabled=\"disabled\"\n ignore-filter\n @update:model-value=\"onPick\"\n @update:open=\"wantOpen = $event\"\n >\n <ComboboxAnchor\n ref=\"anchor\"\n class=\"e-input-wrap e-combo\"\n :class=\"{ 'e-combo--multi': multiple }\"\n :data-invalid=\"error && !bare ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n @mousedown=\"onWrapDown\"\n @focusout=\"onBlur\"\n >\n <div class=\"e-combo-main\">\n <template v-if=\"multiple\">\n <span v-for=\"v in values\" :key=\"v\" class=\"e-tag\">\n {{ labelOf(v) }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n class=\"e-tag-x\"\n :aria-label=\"t('removeItem', { label: labelOf(v) })\"\n @click=\"remove(v)\"\n >\n <EIcon name=\"x\" small />\n </button>\n </span>\n </template>\n <ComboboxInput\n class=\"e-input e-combo-input\"\n :model-value=\"text\"\n :display-value=\"(v: unknown) => (typeof v === 'string' ? (free ? v : labelOf(v)) : '')\"\n :disabled=\"disabled\"\n v-bind=\"inputBind(field)\"\n @update:model-value=\"text = $event\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @keydown.capture=\"keepCaretKeys\"\n />\n </div>\n <template v-if=\"name\">\n <input v-for=\"(v, k) in multiple ? values : [single]\" :key=\"k\" type=\"hidden\" :name=\"name\" :value=\"v\" />\n </template>\n <div class=\"e-combo-tail\">\n <button\n v-if=\"hasValue && clearable && !disabled\"\n type=\"button\"\n class=\"e-combo-btn\"\n :aria-label=\"t('clear')\"\n @mousedown.prevent\n @click=\"clear\"\n >\n <EIcon name=\"x\" />\n </button>\n <ComboboxTrigger\n v-if=\"!free\"\n class=\"e-combo-btn\"\n :aria-label=\"t('showOptions')\"\n :disabled=\"disabled\"\n @mousedown.prevent\n >\n <EIcon name=\"chevron-down\" bold />\n </ComboboxTrigger>\n </div>\n </ComboboxAnchor>\n <span class=\"e-sr\" role=\"status\">{{ announce }}</span>\n <ComboboxPortal :to=\"portal\">\n <ComboboxContent\n ref=\"content\"\n position=\"popper\"\n align=\"start\"\n :side-offset=\"6\"\n :collision-padding=\"8\"\n class=\"e-popover e-listpanel e-root\"\n :aria-label=\"listName\"\n :aria-busy=\"loading ? 'true' : undefined\"\n >\n <ComboboxViewport>\n <template v-if=\"shown.length\">\n <template v-for=\"(section, i) in sections\" :key=\"i\">\n <div v-if=\"section.group\" class=\"e-opt-set\" role=\"group\" :aria-labelledby=\"`${groupId}-g${i}`\">\n <div :id=\"`${groupId}-g${i}`\" class=\"e-opt-group\">{{ section.group }}</div>\n <EComboboxOption\n v-for=\"o in section.options\"\n :key=\"o.value\"\n :option=\"o\"\n :value=\"itemValue(o)\"\n :selected=\"isSelected(itemValue(o))\"\n :query=\"query\"\n />\n </div>\n <template v-else>\n <EComboboxOption\n v-for=\"o in section.options\"\n :key=\"o.value\"\n :option=\"o\"\n :value=\"itemValue(o)\"\n :selected=\"isSelected(itemValue(o))\"\n :query=\"query\"\n />\n </template>\n </template>\n </template>\n <div v-else class=\"e-opt-status\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n <ESpinner v-if=\"loading\" :label=\"t('searching')\" />\n <template v-else>{{ emptyText || t(\"noMatches\") }}</template>\n </div>\n </ComboboxViewport>\n </ComboboxContent>\n </ComboboxPortal>\n </ComboboxRoot>\n </template>\n </component>\n</template>\n\n<style>\n@layer e.controls {\n .e-combo-main {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n align-self: stretch;\n gap: var(--e-space-1);\n min-width: 0;\n }\n\n .e-combo-tail {\n display: flex;\n flex: none;\n align-items: center;\n align-self: center;\n }\n\n .e-combo--multi {\n padding: 3px var(--e-space-1) 3px var(--e-space-2);\n gap: var(--e-space-1);\n }\n\n .e-combo--multi .e-input {\n height: calc(var(--e-control-height) - 9px);\n align-self: center;\n padding-inline: var(--e-space-2);\n }\n\n .e-combo-main .e-tag:not(:has(.e-tag-x)) {\n padding-inline-end: var(--e-space-3);\n }\n\n .e-tag {\n display: inline-flex;\n align-items: center;\n gap: var(--e-space-1);\n height: var(--e-space-8);\n padding: 0 var(--e-space-1) 0 var(--e-space-3);\n border-radius: var(--e-radius-pill);\n background: var(--e-surface-tint);\n box-shadow: inset 0 0 0 var(--e-stroke-card) var(--e-primary);\n color: var(--e-ink);\n font: 500 var(--e-text-sm)/1 var(--e-font-sans);\n }\n\n .e-tag-x::after {\n content: \"\";\n position: absolute;\n inset: calc((var(--e-tap) - var(--e-space-6)) / -2);\n }\n\n .e-tag-x {\n position: relative;\n display: inline-grid;\n place-items: center;\n width: var(--e-space-6);\n height: var(--e-space-6);\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--e-primary);\n cursor: pointer;\n }\n\n .e-tag-x:hover {\n background: var(--e-wash-hover);\n box-shadow: inset 0 0 0 var(--e-stroke-card) var(--e-primary);\n }\n\n .e-tag-x:active {\n background: var(--e-wash-press);\n }\n\n .e-tag-x:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n @media (forced-colors: active) {\n .e-tag {\n outline: var(--e-stroke-card) solid CanvasText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BA,IAAM2C,IAAQC,GAIRC,IAAOH,GAKPI,IAAQ9C,EAA8B4C,GAAA,YAAC,GAEvCI,IAAIC,EAAY,GAChBC,KAASC,EAAgB,GACzBC,IAAQC,GAAc,GACtBC,IAAUC,EAAO,GACjBC,KAASD,QAAaZ,EAAM,EAAE,GAE9Bc,MAA6B,GAAG,EAAE,eACtCC,GAAE,OAAON,EAAM,QAAQ,GAAGO,EAAM,UAAU;GAAE,IAAIH,GAAO;GAAO,aAAa,KAAA;GAAW,iBAAiB,KAAA;EAAU,CAAC,CAAC,GAC/GI,KAAQC,QACZlB,EAAM,OACF,CAAC,IACD;GACE,IAAIA,EAAM;GACV,OAAOA,EAAM;GACb,WAAWA,EAAM;GACjB,MAAMA,EAAM;GACZ,OAAOA,EAAM;GACb,UAAUA,EAAM;GAChB,UAAUA,EAAM;EAClB,CACN,GACMmB,IAAWD,QAAgBlB,EAAM,OAAQA,EAAM,aAAaA,EAAM,QAASA,EAAM,KAAM,GAEvFoB,IAAWF,QAAelB,EAAM,QAAQ,GAExCqB,IAAOH,QAAelB,EAAM,YAAY,CAACA,EAAM,QAAQ,GACvDsB,IAAMJ,QAAeK,GAAiBvB,EAAM,OAAO,CAAC,GACpDwB,IAASN,QAA0BE,EAAS,SAAS,MAAM,QAAQjB,EAAM,KAAK,IAAIA,EAAM,QAAQ,CAAC,CAAE,GACnGsB,IAASP,QAAgB,OAAOf,EAAM,SAAU,WAAWA,EAAM,QAAQ,EAAG,GAC5EuB,IAAYR,QAAgBE,EAAS,QAAQI,EAAO,QAAQC,EAAO,KAAM;EAE/E,SAASE,EAAQ,GAAmB;GAClC,OAAOL,EAAI,MAAM,MAAM,MAAMM,EAAE,UAAUC,CAAC,CAAC,EAAE,UAAUR,EAAK,QAAQQ,IAAI;EAC1E;EACA,IAAMC,UAAiBV,EAAS,QAAQ,KAAKO,EAAQF,EAAO,KAAK,GAE3DM,IAAOC,EAAIF,EAAQ,CAAC,GACpBG,IAASD,EAAI,EAAK,GAClBE,IAAW7E,EAAoB4C,GAAC,MAA0B,GAC1DkC,IAASH,EAAiC,IAAI,GAC9CI,IAAQlB,QAAgBe,EAAO,QAAQF,EAAK,MAAM,KAAK,CAAC,CAAC,YAAY,IAAI,EAAG,GAE5EM,IAAQnB,QAAe;GAC3B,IAAMoB,IAAIF,EAAM;GAEhB,OADIpC,EAAM,SAAesB,EAAI,MAAM,QAAQ,MAAMtB,EAAM,OAAQ4B,GAAGU,CAAC,CAAC,IAC7DhB,EAAI,MAAM,QACd,MAAM,CAACgB,KAAKV,EAAE,MAAM,YAAY,CAAC,CAAC,SAASU,CAAC,MAAMV,EAAE,eAAe,GAAA,CAAI,YAAY,CAAC,CAAC,SAASU,CAAC,CAClG;EACF,CAAC,GACKC,KAAWrB,QAAesB,GAAeH,EAAM,KAAK,CAAC,GACrDI,KAAUvB,QAAemB,EAAM,MAAM,SAAS,KAAK,CAAC,CAACrC,EAAM,WAAW,CAACqB,EAAK,KAAK,GACjFqB,IAAOxB,QAAegB,EAAS,SAASO,GAAQ,SAAS,CAACzC,EAAM,QAAQ,GACxE2C,KAAWzB,QACfwB,EAAK,SAAS,CAACL,EAAM,MAAM,SAAUrC,EAAM,UAAUK,EAAE,WAAW,IAAIL,EAAM,aAAaK,EAAE,WAAW,IAAK,EAC7G,GACMuC,KAAW1B,QAAgBE,EAAS,QAAQI,EAAO,MAAM,SAAS,IAAI,CAAC,CAACO,EAAK,KAAM;EASzF,AAPAc,EAAMnB,SAAiB;GACrB,IAAMoB,IAAOhB,EAAQ;GACrB,AAAIgB,MAASf,EAAK,UAChB,EAAK,QAAQe,GACb,EAAO,QAAQ;EAEnB,CAAC,GACDD,EAAMvB,SAAW;GACf,AAAI,CAACW,EAAO,SAAS,CAACS,EAAK,UAAO,EAAK,QAAQZ,EAAQ;EACzD,CAAC;EAED,IAAMiB,IAASf,EAAwB,GACjCgB,IAAUhB,EAAiC,IAAI;EACrD,SAAgB;GACd,IAAI,CAACU,EAAK,OAAO;GACjB,IAAIO,IAAQ,GACNC,UAAa;IAEjB,AADA,EAAO,QAAQF,EAAQ,OAAO,KAAK,MAAM,KAAA,GACrC,CAACD,EAAO,SAAS,MAAU,MAAI,sBAAsBG,CAAI;GAC/D;GACA,GAAcA,CAAI;EACpB,CAAC;EAED,IAAMC,UAAgBhB,EAAO,OAAO,KAAK,cAAc,OAAO,KAAK,MAC7DiB,UAAmBD,EAAQ,CAAC,EAAE,MAAM;EAE1C,SAASE,EAAW,GAAwB;GAC1C,OAAOjC,EAAS,QAAQI,EAAO,MAAM,SAAS8B,CAAK,KAAIjC,EAAK,OAAQI,EAAO,UAAU6B;EACvF;EACA,IAAMC,KAAa,MAAyClC,EAAK,QAAQO,EAAE,QAAQA,EAAE;EAErF,SAAS4B,GAAO,GAAY;GAE1B,IADA,EAAO,QAAQ,IACXpC,EAAS,OAAO;IAGlB,AAFA,EAAM,QAAQ,MAAM,QAAQS,CAAC,IAAKA,IAAiB,CAAC,GACpD,EAAK,QAAQ,IACb3B,EAAK,eAAe,EAAE;IACtB;GACF;GACA,IAAMuD,IAAO,OAAO5B,KAAM,WAAWA,IAAI;GAGzC,AAFA,EAAM,QAAQ4B,GACd,EAAK,QAAQpC,EAAK,QAAQoC,IAAO9B,EAAQ8B,CAAI,GAC7CvD,EAAK,eAAe6B,EAAK,KAAK;EAChC;EAEA,SAAS2B,GAAQ,GAAU;GACzB,IAAM7B,IAAK,EAAE,OAA4B;GAKzC,AAJA,EAAK,QAAQA,GACb,EAAO,QAAQ,IACf,EAAS,QAAQ,IACjB3B,EAAK,eAAe2B,CAAC,GACjBR,EAAK,UAAO,EAAM,QAAQQ;EAChC;EAEA,SAAS8B,GAAO,GAAW;GACzB,EAAM,QAAQnC,EAAO,MAAM,QAAQ,MAAMoC,MAAM/B,CAAC;EAClD;EAEA,SAASgC,IAAQ;GAKf,AAJA,EAAM,QAAQzC,EAAS,QAAQ,CAAC,IAAI,IACpC,EAAK,QAAQ,IACb,EAAO,QAAQ,IACflB,EAAK,eAAe,EAAE,GACtBkD,EAAW;EACb;EAEA,SAASU,GAAU,GAAkB;GACnC,AAAI,EAAE,QAAQ,YAAY,CAACpB,EAAK,SAASX,EAAK,SAC5C,EAAE,eAAe,GACjB8B,EAAM,KACG,EAAE,QAAQ,eAAezC,EAAS,SAAS,CAACW,EAAK,SAASP,EAAO,MAAM,UAChFmC,GAAOnC,EAAO,MAAMA,EAAO,MAAM,SAAS,EAAG;EAEjD;EAEA,SAASuC,GAAc,GAAkB;GACvC,CAAI,EAAE,QAAQ,UAAU,EAAE,QAAQ,UAAO,EAAE,yBAAyB;EACtE;EAEA,SAASC,GAAO,GAAe;GAC7B,IAAMP,IAAO,EAAE;GACf,AAAIA,MAAStB,EAAO,OAAO,KAAK,SAASsB,CAAI,KAAKA,EAAK,UAAU,YAAY,OAC7E,EAAS,QAAQ,IACjB,EAAO,QAAQ,IACVpC,EAAK,UAAO,EAAK,QAAQS,EAAQ;EACxC;EAEA,SAASmC,GAAW,GAAe;GACjC,AAAI,EAAE,WAAW,EAAE,iBAAiB,CAACjE,EAAM,aACzC,EAAE,eAAe,GACjBoD,EAAW;EAEf;EAGA,SAASc,GAAU,GAAkB;GACnC,OAAO;IACL,IAAIC,EAAM;IACV,UAAUnE,EAAM,YAAY,EAAEoB,EAAS,SAASI,EAAO,MAAM,UAAU,KAAO,KAAA;IAC9E,aAAaJ,EAAS,SAASI,EAAO,MAAM,SAAS,KAAKxB,EAAM;IAChE,gBAAgBmE,EAAM;IACtB,cAAcnE,EAAM,OAAOmB,EAAS,QAAQ,KAAA;IAC5C,cAAc;IACd,GAAI4B,EAAO,QAAQ,EAAE,iBAAiBA,EAAO,MAAM,IAAI,CAAC;IACxD,GAAIV,EAAM,MAAM,SAAS,CAAC,IAAI,EAAE,yBAAyB,KAAA,EAAU;IACnE,GAAG5B,EAAM,MAAM0D,EAAM,eAAe;GACtC;EACF;E,OAEArE,EAAa;GACX,OAAOoB,QAAeiC,EAAQ,CAAC;GAC/B,OAAOC;EACT,CAAC,I,UAIC9F,EAAA,GAAAC,EAwHYC,GAxHIyC,EAAA,OAAOa,KAAOrD,EAAM,GAAAC,GAAAC,GAAA;GAAA,GAAeC,EAAA6C,CAAA,CAAK,CAAC,QAAO;GAAA,GAAOQ,GAAA;EAAK,CAAA,CAAA,GAAA;GAC/D,SAAOpD,GAAE,MAAK,CACvBC,EAoHeF,EAAAgH,EAAA,GAAA;IAnHb,OAAM;IACL,eAAalD,EAAA;IACb,UAAUN,EAAA;IACV,MAAMsB,EAAA;IACN,UAAUzC,EAAA;IACX,iBAAA;IACC,uBAAoBuD;IACpB,iBAAW,AAAAqB,EAAA,QAAA,MAAE,EAAA,QAAWC;;IAEzB,SAAAjH,QA4DiB;KA5DjBC,EA4DiBF,EAAAmH,EAAA,GAAA;MA3DX,SAAA;MAAJ,KAAI5C;MACJ,OAAKpE,GAAA,CAAC,wBAAsB,EAAA,kBACAqD,EAAA,MAAQ,CAAA,CAAA;MACnC,gBAAcnB,EAAA,SAAK,CAAKA,EAAA,OAAI,KAAQ,KAAA;MACpC,iBAAeA,EAAA,WAAQ,KAAQ,KAAA;MAC/B,aAAWgE;MACX,YAAUD;;MAEX,SAAAnG,QA0BM;OA1BNG,EA0BM,OA1BNgB,IA0BM,CAzBYoC,EAAA,SACd9D,EAAA,EAAA,GAAAW,EAWOC,GAAA,EAAA,KAAA,EAAA,GAAAC,EAXWqD,EAAA,QAAL,OAAblE,EAAA,GAAAW,EAWO,QAAA;QAXoB,KAAK4D;QAAG,OAAM;O,IACpCzD,EAAAC,EAAAsD,EAAQE,CAAC,CAAA,IAAI,KAChB,CAAA,GACS5B,EAAA,W,aADT3C,EAAA,GAAAW,EAQS,UAAA;;QANP,MAAK;QACL,OAAM;QACL,cAAYL,EAAAyC,CAAA,CAAC,CAAA,cAAA,EAAA,OAAwBsB,EAAQE,CAAC,EAAA,CAAA;QAC9C,UAAK,MAAE8B,GAAO9B,CAAC;O,IAEhB/D,EAAwBQ,GAAA;QAAjB,MAAK;QAAI,OAAA;O,qCAItBR,EAUEF,EAAA4H,EAAA,GAVFhH,GAUE;QATA,OAAM;QACL,eAAauD,EAAA;QACb,kBAAgB,MAAU,OAAaF,KAAC,WAAiBR,EAAA,QAAOQ,IAAIF,EAAQE,CAAC,IAAA;QAC7E,UAAU5B,EAAA;OACH,GAAAiE,GAAUC,CAAK,GAAA;QACtB,uBAAkB,AAAAU,EAAA,QAAA,MAAE,EAAA,QAAOC;QACpB;QACE;QACQ,kBAAAf;;;;;;OAGN9D,EAAA,QACd3C,EAAA,EAAA,GAAAW,EAAuGC,GAAA,EAAA,KAAA,EAAA,GAAAC,EAA/EiD,EAAA,QAAWI,EAAA,QAAM,CAAIC,EAAA,KAAM,IAApC,GAAG,OAAlBnE,EAAA,GAAAW,EAAuG,SAAA;QAAhD,KAAKyH;QAAG,MAAK;QAAU,MAAMzF,EAAA;QAAO,OAAO4B;;OAEpG7D,EAoBM,OApBNmB,IAoBM,CAlBIyD,GAAA,SAAY3C,EAAA,aAAS,CAAKA,EAAA,YADlC3C,EAAA,GAAAW,EASS,UAAA;;QAPP,MAAK;QACL,OAAM;QACL,cAAYL,EAAAyC,CAAA,CAAC,CAAA,OAAA;QACb,aAAS,AAAAwE,EAAA,OAAApG,QAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;QACjB,SAAOoF;O,IAER/F,EAAkBQ,GAAA,EAAX,MAAK,IAAG,CAAA,C,yBAGR+C,EAAA,Q,aADT/D,EAAA,GAAAC,EAQkBK,EAAAgI,EAAA,GAAA;;QANhB,OAAM;QACL,cAAYhI,EAAAyC,CAAA,CAAC,CAAA,aAAA;QACb,UAAUJ,EAAA;QACV,aAAS,AAAA4E,EAAA,OAAApG,QAAV,CAAA,GAAkB,CAAA,SAAA,CAAA;;QAElB,SAAAZ,QAAkC,CAAlCC,EAAkCQ,GAAA;SAA3B,MAAK;SAAe,MAAA;;;;;;;;;;;KAIjCN,EAAsD,QAAtDqB,IAAsDhB,EAAlBsE,GAAA,KAAQ,GAAA,CAAA;KAC5C7E,EA2CiBF,EAAAiI,EAAA,GAAA,EA3CA,IAAIjI,EAAA2C,EAAA,EAAM,GAAA;MACzB,SAAA1C,QAyCkB,CAzClBC,EAyCkBF,EAAAkI,EAAA,GAAA;OAxCZ,SAAA;OAAJ,KAAI9C;OACJ,UAAS;OACT,OAAM;OACL,eAAa;OACb,qBAAmB;OACpB,OAAM;OACL,cAAY7B,EAAA;OACZ,aAAWlB,EAAA,UAAO,SAAY,KAAA;;OAE/B,SAAApC,QA8BmB,CA9BnBC,EA8BmBF,EAAAmI,EAAA,GAAA,MAAA;QA7BjB,SAAAlI,QAwBW,CAxBKwE,EAAA,MAAM,UACpB/E,EAAA,EAAA,GAAAW,EAsBWC,GAAA,EAAA,KAAA,EAAA,GAAAC,EAtBsBoE,GAAA,QAAf,GAAS,OAAsBjF,EAAA,GAAAW,EAAAC,GAAA,EAAA,KAAA8H,EAAC,GAAA,CACrCC,EAAQ,SAAnB3I,EAAA,GAAAW,EAUM,OAAA;;SAVoB,OAAM;SAAY,MAAK;SAAS,mBAAe,GAAKL,EAAA+C,CAAA,EAAO,IAAKqF;Q,IACxFhI,EAA2E,OAAA;SAArE,IAAE,GAAKJ,EAAA+C,CAAA,EAAO,IAAKqF;SAAK,OAAM;QAAiB,GAAA3H,EAAA4H,EAAQ,KAAK,GAAA,GAAA1G,EAAA,IAClEjC,EAAA,EAAA,GAAAW,EAOEC,GAAA,MAAAC,EANY8H,EAAQ,UAAb,OADT3I,EAAA,GAAAC,EAOEmB,GAAA;SALC,KAAKkD,EAAE;SACP,QAAQA;SACR,OAAO2B,EAAU3B,CAAC;SAClB,UAAUyB,EAAWE,EAAU3B,CAAC,CAAA;SAChC,OAAOQ,EAAA;;;;;;Q,yBAIV9E,EAAA,EAAA,GAAAW,EAOEC,GAAA,EAAA,KAAA,EAAA,GAAAC,EANY8H,EAAQ,UAAb,OADT3I,EAAA,GAAAC,EAOEmB,GAAA;SALC,KAAKkD,EAAE;SACP,QAAQA;SACR,OAAO2B,EAAU3B,CAAC;SAClB,UAAUyB,EAAWE,EAAU3B,CAAC,CAAA;SAChC,OAAOQ,EAAA;;;;;;Q,8BAKhB9E,EAAA,GAAAW,EAGM,OAHNuB,IAGM,CAFYS,EAAA,WAAhB3C,EAAA,GAAAC,EAAmDoB,IAAA;;SAAzB,OAAOf,EAAAyC,CAAA,CAAC,CAAA,WAAA;Q,2BAClC/C,EAAA,GAAAW,EAA6DC,GAAA,EAAA,KAAA,EAAA,GAAA,CAAzCE,EAAAC,EAAA4B,EAAA,aAAarC,EAAAyC,CAAA,CAAC,CAAA,WAAA,CAAA,GAAA,CAAA,C"}
1
+ {"version":3,"file":"EComboboxBase.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_resolveDynamicComponent","EField","_normalizeProps","_guardReactiveProps","_unref","_withCtx","_createVNode","_normalizeClass","_createElementVNode","_createElementBlock","_Fragment","_renderList","_createTextVNode","_toDisplayString","EIcon","_createCommentVNode","_mergeProps","_withModifiers","EComboboxOption","ESpinner","EIcon_default","EField_default","ESpinner_default","EComboboxOption_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","EComboboxBase_vue_vue_type_script_setup_true_lang_default","\"modelValue\"","\"modelModifiers\"","\"open\"","\"openModifiers\"","__expose","__emit","props","__props","emit","model","useModel","t","useMessages","portal","usePortalTarget","attrs","useFieldAttrs","groupId","useUid","bareId","Bare","h","slots","frame","computed","listName","multiple","free","all","normalizeOptions","values","single","rootValue","labelOf","o","v","resting","text","ref","typing","wantOpen","anchor","query","shown","q","sections","sectionOptions","hasList","open","announce","hasValue","watch","rest","listId","content","tries","read","inputEl","focusInput","isSelected","value","itemValue","onPick","next","onInput","remove","x","clear","onKeydown","keepCaretKeys","onBlur","onWrapDown","inputBind","field","openBlock","createBlock","resolveDynamicComponent","normalizeProps","guardReactiveProps","unref","withCtx","createVNode","ComboboxRoot","_cache","$event","ComboboxAnchor","normalizeClass","createElementVNode","createElementBlock","Fragment","renderList","createTextVNode","toDisplayString","createCommentVNode","ComboboxInput","mergeProps","k","withModifiers","ComboboxTrigger","ComboboxPortal","ComboboxContent","ComboboxViewport","i","section"],"sources":["../../../src/components/Combobox/EComboboxBase.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, h, nextTick, onMounted, ref, watch, type FunctionalComponent } from \"vue\";\nimport {\n ComboboxAnchor,\n ComboboxContent,\n ComboboxInput,\n ComboboxPortal,\n ComboboxRoot,\n ComboboxTrigger,\n ComboboxViewport,\n} from \"reka-ui\";\nimport EField from \"../Field/EField.vue\";\nimport EIcon from \"../Icon/EIcon.vue\";\nimport ESpinner from \"../Spinner/ESpinner.vue\";\nimport EComboboxOption from \"./EComboboxOption.vue\";\nimport { normalizeOptions, sectionOptions } from \"../Select/options.js\";\nimport type { EComboboxProps } from \"./types.js\";\nimport { useMessages, usePortalTarget } from \"../../config.js\";\nimport { useFieldAttrs } from \"../../composables/useFieldAttrs.js\";\nimport { useUid } from \"../../composables/useUid.js\";\nimport \"../../styles/base.css\";\nimport \"../TextField/input.css\";\nimport \"../Select/panel.css\";\nimport \"./combo.css\";\n\ndefineOptions({ inheritAttrs: false });\n\nconst props = withDefaults(defineProps<EComboboxProps>(), {\n clearable: true,\n});\n\nconst emit = defineEmits<{\n /** The text in the input changed, by typing or by choosing. Use it to fetch options from a server. */\n inputChange: [text: string];\n}>();\n\nconst model = defineModel<string | string[]>();\n\nconst t = useMessages();\nconst portal = usePortalTarget();\nconst attrs = useFieldAttrs();\nconst groupId = useUid();\nconst bareId = useUid(() => props.id);\n\nconst Bare: FunctionalComponent = (_, { slots }) =>\n h(\"div\", attrs.wrapper(), slots.default?.({ id: bareId.value, ariaInvalid: undefined, ariaDescribedby: undefined }));\nconst frame = computed(() =>\n props.bare\n ? {}\n : {\n id: props.id,\n label: props.label,\n hideLabel: props.hideLabel,\n hint: props.hint,\n error: props.error,\n required: props.required,\n optional: props.optional,\n },\n);\nconst listName = computed(() => (props.bare ? (props.ariaLabel ?? props.label) : props.label));\n\nconst multiple = computed(() => props.multiple);\n// Free text is for one value; with `multiple` it is ignored.\nconst free = computed(() => props.freeform && !props.multiple);\nconst all = computed(() => normalizeOptions(props.options));\nconst values = computed<string[]>(() => (multiple.value && Array.isArray(model.value) ? model.value : []));\nconst single = computed(() => (typeof model.value === \"string\" ? model.value : \"\"));\nconst rootValue = computed(() => (multiple.value ? values.value : single.value));\n\nfunction labelOf(v: string): string {\n return all.value.find((o) => o.value === v)?.label ?? (free.value ? v : \"\");\n}\nconst resting = () => (multiple.value ? \"\" : labelOf(single.value));\n\nconst text = ref(resting());\nconst typing = ref(false);\nconst wantOpen = defineModel<boolean>(\"open\", { default: false });\nconst anchor = ref<{ $el: HTMLElement } | null>(null);\nconst query = computed(() => (typing.value ? text.value.trim().toLowerCase() : \"\"));\n\nconst shown = computed(() => {\n const q = query.value;\n if (props.filter) return all.value.filter((o) => props.filter!(o, q));\n return all.value.filter(\n (o) => !q || o.label.toLowerCase().includes(q) || (o.description ?? \"\").toLowerCase().includes(q),\n );\n});\nconst sections = computed(() => sectionOptions(shown.value));\nconst hasList = computed(() => shown.value.length > 0 || !!props.loading || !free.value);\nconst open = computed(() => wantOpen.value && hasList.value && !props.disabled);\nconst announce = computed(() =>\n open.value && !shown.value.length ? (props.loading ? t(\"searching\") : props.emptyText || t(\"noMatches\")) : \"\",\n);\nconst hasValue = computed(() => (multiple.value ? values.value.length > 0 : !!text.value));\n\nwatch(rootValue, () => {\n const rest = resting();\n if (rest !== text.value) {\n text.value = rest;\n typing.value = false;\n }\n});\nwatch(all, () => {\n if (!typing.value && !open.value) text.value = resting();\n});\n\nconst listId = ref<string | undefined>();\nconst content = ref<{ $el: HTMLElement } | null>(null);\nonMounted(() => {\n if (!open.value) return;\n let tries = 0;\n const read = () => {\n listId.value = content.value?.$el?.id || undefined;\n if (!listId.value && tries++ < 10) requestAnimationFrame(read);\n };\n void nextTick(read);\n});\n\nconst inputEl = () => anchor.value?.$el?.querySelector(\"input\") ?? null;\nconst focusInput = () => inputEl()?.focus();\n\nfunction isSelected(value: string): boolean {\n return multiple.value ? values.value.includes(value) : free.value ? single.value === value : single.value === value;\n}\nconst itemValue = (o: { value: string; label: string }) => (free.value ? o.label : o.value);\n\nfunction onPick(v: unknown) {\n typing.value = false;\n if (multiple.value) {\n model.value = Array.isArray(v) ? (v as string[]) : [];\n text.value = \"\";\n emit(\"inputChange\", \"\");\n return;\n }\n const next = typeof v === \"string\" ? v : \"\";\n model.value = next;\n text.value = free.value ? next : labelOf(next);\n emit(\"inputChange\", text.value);\n}\n\nfunction onInput(e: Event) {\n const v = (e.target as HTMLInputElement).value;\n text.value = v;\n typing.value = true;\n wantOpen.value = true;\n emit(\"inputChange\", v);\n if (free.value) model.value = v;\n}\n\nfunction remove(v: string) {\n model.value = values.value.filter((x) => x !== v);\n}\n\nfunction clear() {\n model.value = multiple.value ? [] : \"\";\n text.value = \"\";\n typing.value = false;\n emit(\"inputChange\", \"\");\n focusInput();\n}\n\nfunction onKeydown(e: KeyboardEvent) {\n if (e.key === \"Escape\" && !open.value && text.value) {\n e.preventDefault();\n clear();\n } else if (e.key === \"Backspace\" && multiple.value && !text.value && values.value.length) {\n remove(values.value[values.value.length - 1]!);\n }\n}\n\nfunction keepCaretKeys(e: KeyboardEvent) {\n if (e.key === \"Home\" || e.key === \"End\") e.stopImmediatePropagation();\n}\n\nfunction onBlur(e: FocusEvent) {\n const next = e.relatedTarget as Element | null;\n if (next && (anchor.value?.$el?.contains(next) || next.closest?.(\".e-popover\"))) return;\n wantOpen.value = false;\n typing.value = false;\n if (!free.value) text.value = resting();\n}\n\nfunction onWrapDown(e: MouseEvent) {\n if (e.target === e.currentTarget && !props.disabled) {\n e.preventDefault();\n focusInput();\n }\n}\n\ntype FieldSlot = { id: string; ariaInvalid: \"true\" | undefined; ariaDescribedby: string | undefined };\nfunction inputBind(field: FieldSlot) {\n return {\n id: field.id,\n required: props.required && !(multiple.value && values.value.length) ? true : undefined,\n placeholder: multiple.value && values.value.length ? \"\" : props.placeholder,\n \"aria-invalid\": field.ariaInvalid,\n \"aria-label\": props.bare ? listName.value : undefined,\n autocomplete: \"off\",\n ...(listId.value ? { \"aria-controls\": listId.value } : {}),\n ...(shown.value.length ? {} : { \"aria-activedescendant\": undefined }),\n ...attrs.input(field.ariaDescribedby),\n };\n}\n\ndefineExpose({\n input: computed(() => inputEl()),\n focus: focusInput,\n});\n</script>\n\n<template>\n <component :is=\"bare ? Bare : EField\" v-bind=\"{ ...attrs.wrapper(), ...frame }\">\n <template #default=\"field\">\n <ComboboxRoot\n class=\"e-combo-root\"\n :model-value=\"rootValue\"\n :multiple=\"multiple\"\n :open=\"open\"\n :disabled=\"disabled\"\n ignore-filter\n @update:model-value=\"onPick\"\n @update:open=\"wantOpen = $event\"\n >\n <ComboboxAnchor\n ref=\"anchor\"\n class=\"e-input-wrap e-combo\"\n :class=\"{ 'e-combo--multi': multiple }\"\n :data-invalid=\"error && !bare ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n @mousedown=\"onWrapDown\"\n @focusout=\"onBlur\"\n >\n <div class=\"e-combo-main\">\n <template v-if=\"multiple\">\n <span v-for=\"v in values\" :key=\"v\" class=\"e-tag\">\n {{ labelOf(v) }}\n <button\n v-if=\"!disabled\"\n type=\"button\"\n class=\"e-tag-x\"\n :aria-label=\"t('removeItem', { label: labelOf(v) })\"\n @click=\"remove(v)\"\n >\n <EIcon name=\"x\" small />\n </button>\n </span>\n </template>\n <ComboboxInput\n class=\"e-input e-combo-input\"\n :model-value=\"text\"\n :display-value=\"(v: unknown) => (typeof v === 'string' ? (free ? v : labelOf(v)) : '')\"\n :disabled=\"disabled\"\n v-bind=\"inputBind(field)\"\n @update:model-value=\"text = $event\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @keydown.capture=\"keepCaretKeys\"\n />\n </div>\n <template v-if=\"name\">\n <input v-for=\"(v, k) in multiple ? values : [single]\" :key=\"k\" type=\"hidden\" :name=\"name\" :value=\"v\" />\n </template>\n <div class=\"e-combo-tail\">\n <button\n v-if=\"hasValue && clearable && !disabled\"\n type=\"button\"\n class=\"e-combo-btn\"\n :aria-label=\"t('clear')\"\n @mousedown.prevent\n @click=\"clear\"\n >\n <EIcon name=\"x\" />\n </button>\n <ComboboxTrigger\n v-if=\"!free\"\n class=\"e-combo-btn\"\n :aria-label=\"t('showOptions')\"\n :disabled=\"disabled\"\n @mousedown.prevent\n >\n <EIcon name=\"chevron-down\" bold />\n </ComboboxTrigger>\n </div>\n </ComboboxAnchor>\n <span class=\"e-sr\" role=\"status\">{{ announce }}</span>\n <ComboboxPortal :to=\"portal\">\n <ComboboxContent\n ref=\"content\"\n position=\"popper\"\n align=\"start\"\n :side-offset=\"6\"\n :collision-padding=\"8\"\n class=\"e-popover e-listpanel e-root\"\n :aria-label=\"listName\"\n :aria-busy=\"loading ? 'true' : undefined\"\n >\n <ComboboxViewport>\n <template v-if=\"shown.length\">\n <template v-for=\"(section, i) in sections\" :key=\"i\">\n <div v-if=\"section.group\" class=\"e-opt-set\" role=\"group\" :aria-labelledby=\"`${groupId}-g${i}`\">\n <div :id=\"`${groupId}-g${i}`\" class=\"e-opt-group\">{{ section.group }}</div>\n <EComboboxOption\n v-for=\"o in section.options\"\n :key=\"o.value\"\n :option=\"o\"\n :value=\"itemValue(o)\"\n :selected=\"isSelected(itemValue(o))\"\n :query=\"query\"\n />\n </div>\n <template v-else>\n <EComboboxOption\n v-for=\"o in section.options\"\n :key=\"o.value\"\n :option=\"o\"\n :value=\"itemValue(o)\"\n :selected=\"isSelected(itemValue(o))\"\n :query=\"query\"\n />\n </template>\n </template>\n </template>\n <div v-else class=\"e-opt-status\" role=\"option\" aria-disabled=\"true\" aria-selected=\"false\">\n <ESpinner v-if=\"loading\" :label=\"t('searching')\" />\n <template v-else>{{ emptyText || t(\"noMatches\") }}</template>\n </div>\n </ComboboxViewport>\n </ComboboxContent>\n </ComboboxPortal>\n </ComboboxRoot>\n </template>\n </component>\n</template>\n\n<style>\n@layer e.controls {\n .e-combo-main {\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n align-self: stretch;\n gap: var(--e-space-1);\n min-width: 0;\n }\n\n .e-combo-tail {\n display: flex;\n flex: none;\n align-items: center;\n align-self: center;\n }\n\n .e-combo--multi {\n padding: calc(3px - var(--e-stroke-edge)) calc(var(--e-space-1) - var(--e-stroke-edge)) calc(3px - var(--e-stroke-edge)) calc(var(--e-space-2) - var(--e-stroke-edge));\n gap: var(--e-space-1);\n }\n\n .e-combo--multi .e-input {\n height: calc(var(--e-control-height) - 9px);\n align-self: center;\n padding-inline: var(--e-space-2);\n }\n\n .e-combo-main .e-tag:not(:has(.e-tag-x)) {\n padding-inline-end: var(--e-space-3);\n }\n\n .e-tag {\n display: inline-flex;\n align-items: center;\n gap: var(--e-space-1);\n height: var(--e-space-8);\n padding: 0 var(--e-space-1) 0 var(--e-space-3);\n border-radius: var(--e-radius-pill);\n background: var(--e-surface-tint);\n box-shadow: inset 0 0 0 var(--e-stroke-card) var(--e-primary);\n color: var(--e-ink);\n font: 500 var(--e-text-sm)/1 var(--e-font-sans);\n }\n\n .e-tag-x::after {\n content: \"\";\n position: absolute;\n inset: calc((var(--e-tap) - var(--e-space-6)) / -2);\n }\n\n .e-tag-x {\n position: relative;\n display: inline-grid;\n place-items: center;\n width: var(--e-space-6);\n height: var(--e-space-6);\n padding: 0;\n border: 0;\n border-radius: 50%;\n background: transparent;\n color: var(--e-primary);\n cursor: pointer;\n }\n\n .e-tag-x:hover {\n background: var(--e-wash-hover);\n box-shadow: inset 0 0 0 var(--e-stroke-card) var(--e-primary);\n }\n\n .e-tag-x:active {\n background: var(--e-wash-press);\n }\n\n .e-tag-x:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n @media (forced-colors: active) {\n .e-tag {\n outline: var(--e-stroke-card) solid CanvasText;\n }\n }\n}\n</style>\n"],"mappings":"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"}