@eos-ui/vue 0.4.0 → 0.5.1

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 (98) hide show
  1. package/README.md +4 -4
  2. package/dist/component-names.js +1 -1
  3. package/dist/component-names.js.map +1 -1
  4. package/dist/components/Actions/EActions.js.map +1 -1
  5. package/dist/components/Actions/EActions.vue.d.ts +1 -1
  6. package/dist/components/Actions/EActions.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/components/Avatar/EAvatar.js.map +1 -1
  8. package/dist/components/Avatar/EAvatar.vue.d.ts +1 -1
  9. package/dist/components/Avatar/EAvatar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  10. package/dist/components/Button/EButton.js.map +1 -1
  11. package/dist/components/Button/EButton.vue.d.ts +2 -0
  12. package/dist/components/Button/EButton.vue_vue_type_script_setup_true_lang.js +64 -29
  13. package/dist/components/Button/EButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  14. package/dist/components/Calendar/ECalendar.js.map +1 -1
  15. package/dist/components/Calendar/ECalendar.vue.d.ts +1 -1
  16. package/dist/components/Calendar/ECalendar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  17. package/dist/components/Checkbox/ECheckbox.js.map +1 -1
  18. package/dist/components/Checkbox/ECheckbox.vue.d.ts +1 -1
  19. package/dist/components/Checkbox/ECheckbox.vue_vue_type_script_setup_true_lang.js.map +1 -1
  20. package/dist/components/Combobox/EComboboxBase.js.map +1 -1
  21. package/dist/components/Combobox/EComboboxBase.vue_vue_type_script_setup_true_lang.js +4 -8
  22. package/dist/components/Combobox/EComboboxBase.vue_vue_type_script_setup_true_lang.js.map +1 -1
  23. package/dist/components/Combobox/types.d.ts +2 -2
  24. package/dist/components/DataGrid/EDataGrid.js.map +1 -1
  25. package/dist/components/DataGrid/EDataGrid.vue.d.ts +1 -1
  26. package/dist/components/DataGrid/EDataGrid.vue_vue_type_script_setup_true_lang.js +1 -0
  27. package/dist/components/DataGrid/EDataGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  28. package/dist/components/DescriptionList/EDescriptionList.js.map +1 -1
  29. package/dist/components/DescriptionList/EDescriptionList.vue_vue_type_script_setup_true_lang.js +2 -2
  30. package/dist/components/DescriptionList/EDescriptionList.vue_vue_type_script_setup_true_lang.js.map +1 -1
  31. package/dist/components/Dialog/EDialog.js.map +1 -1
  32. package/dist/components/Dialog/EDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
  33. package/dist/components/Drawer/EDrawer.js.map +1 -1
  34. package/dist/components/Drawer/EDrawer.vue_vue_type_script_setup_true_lang.js.map +1 -1
  35. package/dist/components/EmptyState/EEmptyState.js.map +1 -1
  36. package/dist/components/EmptyState/EEmptyState.vue.d.ts +1 -1
  37. package/dist/components/EmptyState/EEmptyState.vue_vue_type_script_setup_true_lang.js.map +1 -1
  38. package/dist/components/Grid/EGrid.js.map +1 -1
  39. package/dist/components/Grid/EGrid.vue.d.ts +1 -1
  40. package/dist/components/Grid/EGrid.vue_vue_type_script_setup_true_lang.js.map +1 -1
  41. package/dist/components/IconButton/EIconButton.js.map +1 -1
  42. package/dist/components/IconButton/EIconButton.vue_vue_type_script_setup_true_lang.js.map +1 -1
  43. package/dist/components/Inline/EInline.js.map +1 -1
  44. package/dist/components/Inline/EInline.vue.d.ts +1 -1
  45. package/dist/components/Inline/EInline.vue_vue_type_script_setup_true_lang.js.map +1 -1
  46. package/dist/components/Kbd/EKbd.js.map +1 -1
  47. package/dist/components/Kbd/EKbd.vue_vue_type_script_setup_true_lang.js.map +1 -1
  48. package/dist/components/NavList/ENavList.js.map +1 -1
  49. package/dist/components/NavList/ENavList.vue_vue_type_script_setup_true_lang.js.map +1 -1
  50. package/dist/components/Notice/ENotice.js.map +1 -1
  51. package/dist/components/Notice/ENotice.vue_vue_type_script_setup_true_lang.js.map +1 -1
  52. package/dist/components/OtpField/EOtpField.js.map +1 -1
  53. package/dist/components/OtpField/EOtpField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  54. package/dist/components/PageHeader/EPageHeader.js.map +1 -1
  55. package/dist/components/PageHeader/EPageHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
  56. package/dist/components/Pagination/EPagination.js.map +1 -1
  57. package/dist/components/Pagination/EPagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
  58. package/dist/components/PasswordField/EPasswordField.js.map +1 -1
  59. package/dist/components/PasswordField/EPasswordField.vue_vue_type_script_setup_true_lang.js.map +1 -1
  60. package/dist/components/SearchBar/ESearchBar.js.map +1 -1
  61. package/dist/components/SearchBar/ESearchBar.vue.d.ts +1 -1
  62. package/dist/components/SearchBar/ESearchBar.vue_vue_type_script_setup_true_lang.js.map +1 -1
  63. package/dist/components/Segmented/ESegmented.js.map +1 -1
  64. package/dist/components/Segmented/ESegmented.vue_vue_type_script_setup_true_lang.js.map +1 -1
  65. package/dist/components/Select/ESelectControl.js.map +1 -1
  66. package/dist/components/Select/ESelectControl.vue_vue_type_script_setup_true_lang.js.map +1 -1
  67. package/dist/components/SignaturePad/ESignaturePad.js.map +1 -1
  68. package/dist/components/SignaturePad/ESignaturePad.vue_vue_type_script_setup_true_lang.js.map +1 -1
  69. package/dist/components/Stack/EStack.js.map +1 -1
  70. package/dist/components/Stack/EStack.vue.d.ts +1 -1
  71. package/dist/components/Stack/EStack.vue_vue_type_script_setup_true_lang.js.map +1 -1
  72. package/dist/components/Stamp/EStamp.js.map +1 -1
  73. package/dist/components/Stamp/EStamp.vue.d.ts +2 -2
  74. package/dist/components/Stamp/EStamp.vue_vue_type_script_setup_true_lang.js +2 -2
  75. package/dist/components/Stamp/EStamp.vue_vue_type_script_setup_true_lang.js.map +1 -1
  76. package/dist/components/Stepper/EStepper.js.map +1 -1
  77. package/dist/components/Stepper/EStepper.vue_vue_type_script_setup_true_lang.js.map +1 -1
  78. package/dist/components/Surface/ESurface.js.map +1 -1
  79. package/dist/components/Surface/ESurface.vue.d.ts +1 -1
  80. package/dist/components/Surface/ESurface.vue_vue_type_script_setup_true_lang.js.map +1 -1
  81. package/dist/components/Switch/ESwitch.js.map +1 -1
  82. package/dist/components/Switch/ESwitch.vue_vue_type_script_setup_true_lang.js.map +1 -1
  83. package/dist/components/Table/ETable.js +8 -0
  84. package/dist/components/Table/ETable.js.map +1 -0
  85. package/dist/components/Table/ETable.vue.d.ts +25 -0
  86. package/dist/components/Table/ETable.vue_vue_type_script_setup_true_lang.js +28 -0
  87. package/dist/components/Table/ETable.vue_vue_type_script_setup_true_lang.js.map +1 -0
  88. package/dist/components/Table/index.d.ts +1 -0
  89. package/dist/components/Tabs/ETabs.js.map +1 -1
  90. package/dist/components/Tabs/ETabs.vue.d.ts +10 -2
  91. package/dist/components/Tabs/ETabs.vue_vue_type_script_setup_true_lang.js +11 -3
  92. package/dist/components/Tabs/ETabs.vue_vue_type_script_setup_true_lang.js.map +1 -1
  93. package/dist/components/Upload/EUpload.js.map +1 -1
  94. package/dist/components/Upload/EUpload.vue_vue_type_script_setup_true_lang.js.map +1 -1
  95. package/dist/index.d.ts +1 -0
  96. package/dist/index.js +10 -9
  97. package/dist/style.css +555 -179
  98. package/package.json +3 -2
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Accessible Vue 3 components with a token-based theme system. High contrast and consistent by default, rebrandable with a few lines.
4
4
 
5
- Documentation, live examples and a theme playground: https://eos.dame.gg
5
+ [Documentation, live examples and a theme playground](https://eos.dame.gg)
6
6
 
7
7
  ```bash
8
8
  npm install @eos-ui/vue
@@ -40,9 +40,9 @@ const email = ref("");
40
40
  - One stylesheet (about 19 kB gzipped), imported once. The JavaScript has no CSS imports, so server rendering needs no bundler setup.
41
41
  - Everything sits in the cascade layers `e.*`, so your own CSS wins without specificity fights.
42
42
  - Words, locale, currency, text direction and icons are plugin options.
43
- - `defineTheme()` (re-exported from `@eos-ui/tokens`) builds a theme from `brand`, `accent` and other inputs and checks its contrast.
44
- - Icons: a built-in Phosphor set, or Lucide, Tabler, Heroicons, Phosphor (Vue), Iconify or your own set (`@eos-ui/vue/icons`).
43
+ - `defineTheme()` (re-exported from [`@eos-ui/tokens`](../tokens)) builds a theme from `brand`, `accent` and other inputs and checks its contrast.
44
+ - Icons: a built-in Phosphor set, or Lucide, Tabler, Heroicons, Phosphor (Vue), Iconify or your own set (`@eos-ui/vue/icons`; see [Bring your own icons](src/icons/README.md)).
45
45
  - `EosResolver` from `@eos-ui/vue/resolver` auto-imports components for `unplugin-vue-components`.
46
46
  - Components work without the plugin, in English and US dollars.
47
47
 
48
- Source, issues and contributing: https://github.com/Dame-G/eos. MIT licensed.
48
+ [Source, issues and contributing](https://github.com/Dame-G/eos). MIT licensed.
@@ -1,5 +1,5 @@
1
1
  //#region src/component-names.ts
2
- var e = /* @__PURE__ */ new Set(/* @__PURE__ */ "EActions.EAppFooter.EAppHeader.EAppShell.EAvatar.EBreadcrumb.EButton.ECalendar.ECheckbox.ECodeBlock.EColorField.ECombobox.ECurrencyField.EDataGrid.EDatePicker.EDefinition.EDescriptionList.EDialog.EDisclosure.EDivider.EDrawer.EEmptyState.EExpandableRow.EField.EFieldset.EGrid.EHeading.EHighlight.EIcon.EIconButton.EInline.EKbd.EKicker.ELink.EMenu.ENavList.ENotice.ENumberField.EOtpField.EPageHeader.EPagination.EPasswordField.EPhoneField.EProgress.ERadioGroup.ERangePicker.ESearchBar.ESearchResults.ESegmented.ESelect.ESignatureField.ESignaturePad.ESkeleton.ESkipLink.ESpinner.EStack.EStamp.EStepper.ESurface.ESwitch.ETabs.EText.ETextField.ETextarea.EToast.EToastProvider.ETooltip.EUpload.EVisuallyHidden".split("."));
2
+ var e = /* @__PURE__ */ new Set(/* @__PURE__ */ "EActions.EAppFooter.EAppHeader.EAppShell.EAvatar.EBreadcrumb.EButton.ECalendar.ECheckbox.ECodeBlock.EColorField.ECombobox.ECurrencyField.EDataGrid.EDatePicker.EDefinition.EDescriptionList.EDialog.EDisclosure.EDivider.EDrawer.EEmptyState.EExpandableRow.EField.EFieldset.EGrid.EHeading.EHighlight.EIcon.EIconButton.EInline.EKbd.EKicker.ELink.EMenu.ENavList.ENotice.ENumberField.EOtpField.EPageHeader.EPagination.EPasswordField.EPhoneField.EProgress.ERadioGroup.ERangePicker.ESearchBar.ESearchResults.ESegmented.ESelect.ESignatureField.ESignaturePad.ESkeleton.ESkipLink.ESpinner.EStack.EStamp.EStepper.ESurface.ESwitch.ETable.ETabs.EText.ETextField.ETextarea.EToast.EToastProvider.ETooltip.EUpload.EVisuallyHidden".split("."));
3
3
  //#endregion
4
4
  export { e as componentNames };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"component-names.js","names":["componentNames"],"sources":["../src/component-names.ts"],"sourcesContent":["// Generated by scripts/gen-index.mjs. Do not edit.\nexport const componentNames: ReadonlySet<string> = new Set([\"EActions\",\"EAppFooter\",\"EAppHeader\",\"EAppShell\",\"EAvatar\",\"EBreadcrumb\",\"EButton\",\"ECalendar\",\"ECheckbox\",\"ECodeBlock\",\"EColorField\",\"ECombobox\",\"ECurrencyField\",\"EDataGrid\",\"EDatePicker\",\"EDefinition\",\"EDescriptionList\",\"EDialog\",\"EDisclosure\",\"EDivider\",\"EDrawer\",\"EEmptyState\",\"EExpandableRow\",\"EField\",\"EFieldset\",\"EGrid\",\"EHeading\",\"EHighlight\",\"EIcon\",\"EIconButton\",\"EInline\",\"EKbd\",\"EKicker\",\"ELink\",\"EMenu\",\"ENavList\",\"ENotice\",\"ENumberField\",\"EOtpField\",\"EPageHeader\",\"EPagination\",\"EPasswordField\",\"EPhoneField\",\"EProgress\",\"ERadioGroup\",\"ERangePicker\",\"ESearchBar\",\"ESearchResults\",\"ESegmented\",\"ESelect\",\"ESignatureField\",\"ESignaturePad\",\"ESkeleton\",\"ESkipLink\",\"ESpinner\",\"EStack\",\"EStamp\",\"EStepper\",\"ESurface\",\"ESwitch\",\"ETabs\",\"EText\",\"ETextField\",\"ETextarea\",\"EToast\",\"EToastProvider\",\"ETooltip\",\"EUpload\",\"EVisuallyHidden\"]);\n"],"mappings":";AACA,IAAaA,oBAAsC,IAAI,IAAI,2tBAA00B,CAAC"}
1
+ {"version":3,"file":"component-names.js","names":["componentNames"],"sources":["../src/component-names.ts"],"sourcesContent":["// Generated by scripts/gen-index.mjs. Do not edit.\nexport const componentNames: ReadonlySet<string> = new Set([\"EActions\",\"EAppFooter\",\"EAppHeader\",\"EAppShell\",\"EAvatar\",\"EBreadcrumb\",\"EButton\",\"ECalendar\",\"ECheckbox\",\"ECodeBlock\",\"EColorField\",\"ECombobox\",\"ECurrencyField\",\"EDataGrid\",\"EDatePicker\",\"EDefinition\",\"EDescriptionList\",\"EDialog\",\"EDisclosure\",\"EDivider\",\"EDrawer\",\"EEmptyState\",\"EExpandableRow\",\"EField\",\"EFieldset\",\"EGrid\",\"EHeading\",\"EHighlight\",\"EIcon\",\"EIconButton\",\"EInline\",\"EKbd\",\"EKicker\",\"ELink\",\"EMenu\",\"ENavList\",\"ENotice\",\"ENumberField\",\"EOtpField\",\"EPageHeader\",\"EPagination\",\"EPasswordField\",\"EPhoneField\",\"EProgress\",\"ERadioGroup\",\"ERangePicker\",\"ESearchBar\",\"ESearchResults\",\"ESegmented\",\"ESelect\",\"ESignatureField\",\"ESignaturePad\",\"ESkeleton\",\"ESkipLink\",\"ESpinner\",\"EStack\",\"EStamp\",\"EStepper\",\"ESurface\",\"ESwitch\",\"ETable\",\"ETabs\",\"EText\",\"ETextField\",\"ETextarea\",\"EToast\",\"EToastProvider\",\"ETooltip\",\"EUpload\",\"EVisuallyHidden\"]);\n"],"mappings":";AACA,IAAaA,oBAAsC,IAAI,IAAI,kuBAAm1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"EActions.js","names":["_sfc_main","EActions_vue_vue_type_script_setup_true_lang_default","EActions_default"],"sources":["../../../src/components/Actions/EActions.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport \"../../styles/base.css\";\n\nwithDefaults(\n defineProps<{\n /** The element to render, `div` by default. Use `footer` for a bar at the end of a card. */\n as?: string;\n /** Puts the group on a tinted footer bar with a rule above, for actions that end a card or an overlay. Buttons stack full width up to 32rem. Leave it off for the next step on a page. */\n bar?: boolean;\n /** Names the group for screen readers (for example \"Record actions\"): renders `role=\"group\"` with `aria-label`. Use it for buttons that belong together, such as a filter row. */\n label?: string;\n }>(),\n { as: \"div\" },\n);\n\ndefineSlots<{\n /** The Buttons, in the order of the content, the main action first. */\n default(): unknown;\n}>();\n</script>\n\n<template>\n <component\n :is=\"as\"\n class=\"e-actions\"\n :class=\"bar && 'e-actions--bar'\"\n :role=\"label ? 'group' : undefined\"\n :aria-label=\"label\"\n >\n <slot />\n </component>\n</template>\n\n<style>\n@layer e.blocks {\n .e-actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--e-space-2);\n }\n\n .e-actions--bar {\n padding: var(--e-space-3) var(--e-space-4);\n border-top: var(--e-stroke-hair) solid var(--e-border);\n background: var(--e-surface-tint);\n }\n\n @media (max-width: 32rem) {\n .e-actions--bar > .e-btn {\n flex: 1 1 100%;\n }\n }\n\n @media print {\n .e-actions {\n display: none;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"EActions.js","names":["_sfc_main","EActions_vue_vue_type_script_setup_true_lang_default","EActions_default"],"sources":["../../../src/components/Actions/EActions.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport \"../../styles/base.css\";\n\nwithDefaults(\n defineProps<{\n /** The element to render. Use `footer` for a bar at the end of a card. */\n as?: string;\n /** Puts the group on a tinted footer bar with a rule above, for actions that end a card or an overlay. Buttons stack full width up to 32rem. Leave it off for the next step on a page. */\n bar?: boolean;\n /** Names the group for screen readers (for example \"Record actions\"): renders `role=\"group\"` with `aria-label`. Use it for buttons that belong together, such as a filter row. */\n label?: string;\n }>(),\n { as: \"div\" },\n);\n\ndefineSlots<{\n /** The Buttons, in the order of the content, the main action first. */\n default(): unknown;\n}>();\n</script>\n\n<template>\n <component\n :is=\"as\"\n class=\"e-actions\"\n :class=\"bar && 'e-actions--bar'\"\n :role=\"label ? 'group' : undefined\"\n :aria-label=\"label\"\n >\n <slot />\n </component>\n</template>\n\n<style>\n@layer e.blocks {\n .e-actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--e-space-2);\n }\n\n .e-actions--bar {\n padding: var(--e-space-3) var(--e-space-4);\n border-top: var(--e-stroke-hair) solid var(--e-border);\n background: var(--e-surface-tint);\n }\n\n @media (max-width: 32rem) {\n .e-actions--bar > .e-btn {\n flex: 1 1 100%;\n }\n }\n\n @media print {\n .e-actions {\n display: none;\n }\n }\n}\n</style>\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  type __VLS_Props = {
2
- /** The element to render, `div` by default. Use `footer` for a bar at the end of a card. */
2
+ /** The element to render. Use `footer` for a bar at the end of a card. */
3
3
  as?: string;
4
4
  /** Puts the group on a tinted footer bar with a rule above, for actions that end a card or an overlay. Buttons stack full width up to 32rem. Leave it off for the next step on a page. */
5
5
  bar?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"EActions.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeClass","_withCtx","_renderSlot","EActions_vue_vue_type_script_setup_true_lang_default","openBlock","createBlock","resolveDynamicComponent","__props","normalizeClass","withCtx","renderSlot","_ctx"],"sources":["../../../src/components/Actions/EActions.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport \"../../styles/base.css\";\n\nwithDefaults(\n defineProps<{\n /** The element to render, `div` by default. Use `footer` for a bar at the end of a card. */\n as?: string;\n /** Puts the group on a tinted footer bar with a rule above, for actions that end a card or an overlay. Buttons stack full width up to 32rem. Leave it off for the next step on a page. */\n bar?: boolean;\n /** Names the group for screen readers (for example \"Record actions\"): renders `role=\"group\"` with `aria-label`. Use it for buttons that belong together, such as a filter row. */\n label?: string;\n }>(),\n { as: \"div\" },\n);\n\ndefineSlots<{\n /** The Buttons, in the order of the content, the main action first. */\n default(): unknown;\n}>();\n</script>\n\n<template>\n <component\n :is=\"as\"\n class=\"e-actions\"\n :class=\"bar && 'e-actions--bar'\"\n :role=\"label ? 'group' : undefined\"\n :aria-label=\"label\"\n >\n <slot />\n </component>\n</template>\n\n<style>\n@layer e.blocks {\n .e-actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--e-space-2);\n }\n\n .e-actions--bar {\n padding: var(--e-space-3) var(--e-space-4);\n border-top: var(--e-stroke-hair) solid var(--e-border);\n background: var(--e-surface-tint);\n }\n\n @media (max-width: 32rem) {\n .e-actions--bar > .e-btn {\n flex: 1 1 100%;\n }\n }\n\n @media print {\n .e-actions {\n display: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;E,kBAsBEA,EAAA,GAAAC,EAQYC,EAPLQ,EAAA,EAAE,GAAA;GACP,OAAKP,EAAA,CAAC,aACEO,EAAA,OAAG,gBAAA,CAAA;GACV,MAAMA,EAAA,QAAK,UAAa,KAAA;GACxB,cAAYA,EAAA;;GAEb,SAAAN,QAAQ,CAARC,EAAQS,EAAA,QAAA,SAAA,C"}
1
+ {"version":3,"file":"EActions.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","_resolveDynamicComponent","_normalizeClass","_withCtx","_renderSlot","EActions_vue_vue_type_script_setup_true_lang_default","openBlock","createBlock","resolveDynamicComponent","__props","normalizeClass","withCtx","renderSlot","_ctx"],"sources":["../../../src/components/Actions/EActions.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport \"../../styles/base.css\";\n\nwithDefaults(\n defineProps<{\n /** The element to render. Use `footer` for a bar at the end of a card. */\n as?: string;\n /** Puts the group on a tinted footer bar with a rule above, for actions that end a card or an overlay. Buttons stack full width up to 32rem. Leave it off for the next step on a page. */\n bar?: boolean;\n /** Names the group for screen readers (for example \"Record actions\"): renders `role=\"group\"` with `aria-label`. Use it for buttons that belong together, such as a filter row. */\n label?: string;\n }>(),\n { as: \"div\" },\n);\n\ndefineSlots<{\n /** The Buttons, in the order of the content, the main action first. */\n default(): unknown;\n}>();\n</script>\n\n<template>\n <component\n :is=\"as\"\n class=\"e-actions\"\n :class=\"bar && 'e-actions--bar'\"\n :role=\"label ? 'group' : undefined\"\n :aria-label=\"label\"\n >\n <slot />\n </component>\n</template>\n\n<style>\n@layer e.blocks {\n .e-actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--e-space-2);\n }\n\n .e-actions--bar {\n padding: var(--e-space-3) var(--e-space-4);\n border-top: var(--e-stroke-hair) solid var(--e-border);\n background: var(--e-surface-tint);\n }\n\n @media (max-width: 32rem) {\n .e-actions--bar > .e-btn {\n flex: 1 1 100%;\n }\n }\n\n @media print {\n .e-actions {\n display: none;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;E,kBAsBEA,EAAA,GAAAC,EAQYC,EAPLQ,EAAA,EAAE,GAAA;GACP,OAAKP,EAAA,CAAC,aACEO,EAAA,OAAG,gBAAA,CAAA;GACV,MAAMA,EAAA,QAAK,UAAa,KAAA;GACxB,cAAYA,EAAA;;GAEb,SAAAN,QAAQ,CAARC,EAAQS,EAAA,QAAA,SAAA,C"}
@@ -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`. Default `span`. */\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 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-border-strong);\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 .e-avatar--button {\n position: relative;\n padding: 0;\n cursor: pointer;\n transition: border-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-avatar--button:hover {\n border-color: var(--e-ink);\n\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: 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":""}
@@ -7,7 +7,7 @@ type __VLS_Props = {
7
7
  small?: boolean;
8
8
  /** 64px, for a profile or practitioner on an appointment card. The default is 44px. */
9
9
  large?: boolean;
10
- /** `button` renders a `button` with `type="button"`, a pointer cursor and a focus ring, named by `name`, such as the `trigger` of an `EMenu`. Default `span`. */
10
+ /** `button` renders a `button` with `type="button"`, a pointer cursor and a focus ring, named by `name`, such as the `trigger` of an `EMenu`. */
11
11
  as?: "span" | "button";
12
12
  };
13
13
  declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
@@ -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`. Default `span`. */\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 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-border-strong);\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 .e-avatar--button {\n position: relative;\n padding: 0;\n cursor: pointer;\n transition: border-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-avatar--button:hover {\n border-color: var(--e-ink);\n\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: 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 +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 }>(),\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) 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']\"\n :target=\"external ? '_blank' : undefined\"\n :rel=\"external ? 'noreferrer' : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click.capture=\"blockWhenDisabled\"\n @auxclick.capture=\"blockWhenDisabled\"\n >\n <EIcon v-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']\"\n :disabled=\"disabled\"\n >\n <EIcon v-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 /* The face is a whole rounded box and the slab is an offset copy of it showing underneath, in the colour of the face's own edge. The margin gives back the room the slab takes, so the button is still one control height tall, and pressing sinks the face onto the slab. */\n --e-lift: var(--e-depth);\n\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--e-space-2);\n height: calc(var(--e-control-height) - var(--e-lift));\n margin-block-end: var(--e-lift);\n padding: 0 var(--e-space-4);\n border: var(--e-stroke-edge) solid var(--e-slab);\n border-radius: var(--e-radius-md);\n background: var(--e-fill);\n box-shadow: 0 var(--e-lift) 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 transform var(--e-duration-tap) var(--e-easing-out),\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 background: var(--e-hover);\n }\n\n .e-btn:active {\n background: var(--e-press);\n box-shadow: 0 0 0 0 var(--e-slab);\n transform: translateY(var(--e-lift));\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 background: color-mix(in srgb, var(--e-surface), var(--e-shade-hover));\n border-color: var(--e-ink);\n\n }\n\n .e-btn--outline:active {\n background: color-mix(in srgb, var(--e-surface), var(--e-shade-press));\n border-color: var(--e-ink);\n\n }\n\n .e-btn--quiet {\n border-color: transparent;\n\n --e-lift: 0px;\n\n background: transparent;\n color: var(--e-ink);\n box-shadow: none;\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 border-color: var(--e-wash-ring);\n background: var(--e-wash-hover);\n text-decoration-color: currentcolor;\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):active {\n border-color: var(--e-ink);\n background: var(--e-wash-press);\n transform: none;\n }\n\n .e-btn .e-icon {\n margin-inline-start: calc(-0.5 * var(--e-space-1));\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\n border-color: var(--e-primary);\n background: 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 border: var(--e-stroke-edge) dashed var(--e-border-strong);\n outline: 0;\n box-shadow: none;\n transform: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-btn {\n transition: 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 border-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 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":""}
@@ -14,6 +14,8 @@ type __VLS_Props = {
14
14
  href?: string;
15
15
  /** With `href`: opens in a new tab. */
16
16
  external?: boolean;
17
+ /** 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. */
18
+ loading?: boolean;
17
19
  };
18
20
  type __VLS_Slots = {
19
21
  /** The label: a verb that says what happens, like "Pay $162.40". */
@@ -1,14 +1,29 @@
1
1
  /* empty css */
2
2
  import e from "../Icon/EIcon.js";
3
- import { createBlock as t, createCommentVNode as n, createElementBlock as r, defineComponent as i, normalizeClass as a, openBlock as o, renderSlot as s } from "vue";
3
+ import { createBlock as t, createCommentVNode as n, createElementBlock as r, createElementVNode as i, defineComponent as a, normalizeClass as o, openBlock as s, renderSlot as c } from "vue";
4
4
  //#region src/components/Button/EButton.vue?vue&type=script&setup=true&lang.ts
5
- var c = [
5
+ var l = [
6
6
  "href",
7
7
  "target",
8
8
  "rel",
9
9
  "aria-disabled",
10
+ "aria-busy",
10
11
  "tabindex"
11
- ], l = ["type", "disabled"], u = /*@__PURE__*/ i({
12
+ ], u = {
13
+ key: 0,
14
+ class: "e-btn-spinner",
15
+ viewBox: "0 0 24 24",
16
+ "aria-hidden": "true"
17
+ }, d = [
18
+ "type",
19
+ "disabled",
20
+ "aria-busy"
21
+ ], f = {
22
+ key: 0,
23
+ class: "e-btn-spinner",
24
+ viewBox: "0 0 24 24",
25
+ "aria-hidden": "true"
26
+ }, p = /*@__PURE__*/ a({
12
27
  __name: "EButton",
13
28
  props: {
14
29
  variant: { default: "primary" },
@@ -17,38 +32,58 @@ var c = [
17
32
  disabled: { type: Boolean },
18
33
  type: { default: "button" },
19
34
  href: {},
20
- external: { type: Boolean }
35
+ external: { type: Boolean },
36
+ loading: { type: Boolean }
21
37
  },
22
- setup(i) {
23
- let u = i;
24
- function d(e) {
25
- u.disabled && (e.preventDefault(), e.stopImmediatePropagation());
38
+ setup(a) {
39
+ let p = a;
40
+ function m(e) {
41
+ (p.disabled || p.loading) && (e.preventDefault(), e.stopImmediatePropagation());
26
42
  }
27
- return (u, f) => i.href ? (o(), r("a", {
43
+ return (p, h) => a.href ? (s(), r("a", {
28
44
  key: 0,
29
- href: i.href,
30
- class: a(["e-btn", [i.variant !== "primary" && `e-btn--${i.variant}`, i.block && "e-btn--block"]]),
31
- target: i.external ? "_blank" : void 0,
32
- rel: i.external ? "noreferrer" : void 0,
33
- "aria-disabled": i.disabled ? "true" : void 0,
34
- tabindex: i.disabled ? -1 : void 0,
35
- onClickCapture: d,
36
- onAuxclickCapture: d
37
- }, [i.icon ? (o(), t(e, {
38
- key: 0,
39
- name: i.icon
40
- }, null, 8, ["name"])) : n("", !0), s(u.$slots, "default")], 42, c)) : (o(), r("button", {
45
+ href: a.href,
46
+ class: o(["e-btn", [
47
+ a.variant !== "primary" && `e-btn--${a.variant}`,
48
+ a.block && "e-btn--block",
49
+ a.loading && "e-btn--loading"
50
+ ]]),
51
+ target: a.external ? "_blank" : void 0,
52
+ rel: a.external ? "noreferrer" : void 0,
53
+ "aria-disabled": a.disabled ? "true" : void 0,
54
+ "aria-busy": a.loading ? "true" : void 0,
55
+ tabindex: a.disabled ? -1 : void 0,
56
+ onClickCapture: m,
57
+ onAuxclickCapture: m
58
+ }, [a.loading ? (s(), r("svg", u, [...h[0] ||= [i("circle", {
59
+ cx: "12",
60
+ cy: "12",
61
+ r: "9"
62
+ }, null, -1)]])) : a.icon ? (s(), t(e, {
41
63
  key: 1,
42
- type: i.type,
43
- class: a(["e-btn", [i.variant !== "primary" && `e-btn--${i.variant}`, i.block && "e-btn--block"]]),
44
- disabled: i.disabled
45
- }, [i.icon ? (o(), t(e, {
46
- key: 0,
47
- name: i.icon
48
- }, null, 8, ["name"])) : n("", !0), s(u.$slots, "default")], 10, l));
64
+ name: a.icon
65
+ }, null, 8, ["name"])) : n("", !0), c(p.$slots, "default")], 42, l)) : (s(), r("button", {
66
+ key: 1,
67
+ type: a.type,
68
+ class: o(["e-btn", [
69
+ a.variant !== "primary" && `e-btn--${a.variant}`,
70
+ a.block && "e-btn--block",
71
+ a.loading && "e-btn--loading"
72
+ ]]),
73
+ disabled: a.disabled,
74
+ "aria-busy": a.loading ? "true" : void 0,
75
+ onClickCapture: m
76
+ }, [a.loading ? (s(), r("svg", f, [...h[1] ||= [i("circle", {
77
+ cx: "12",
78
+ cy: "12",
79
+ r: "9"
80
+ }, null, -1)]])) : a.icon ? (s(), t(e, {
81
+ key: 1,
82
+ name: a.icon
83
+ }, null, 8, ["name"])) : n("", !0), c(p.$slots, "default")], 42, d));
49
84
  }
50
85
  });
51
86
  //#endregion
52
- export { u as default };
87
+ export { p as default };
53
88
 
54
89
  //# sourceMappingURL=EButton.vue_vue_type_script_setup_true_lang.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EButton.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeClass","_createBlock","EIcon","_createCommentVNode","_renderSlot","EIcon_default","_hoisted_1","_hoisted_2","EButton_vue_vue_type_script_setup_true_lang_default","props","__props","blockWhenDisabled","event","openBlock","createElementBlock","normalizeClass","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 }>(),\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) 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']\"\n :target=\"external ? '_blank' : undefined\"\n :rel=\"external ? 'noreferrer' : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : undefined\"\n @click.capture=\"blockWhenDisabled\"\n @auxclick.capture=\"blockWhenDisabled\"\n >\n <EIcon v-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']\"\n :disabled=\"disabled\"\n >\n <EIcon v-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 /* The face is a whole rounded box and the slab is an offset copy of it showing underneath, in the colour of the face's own edge. The margin gives back the room the slab takes, so the button is still one control height tall, and pressing sinks the face onto the slab. */\n --e-lift: var(--e-depth);\n\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--e-space-2);\n height: calc(var(--e-control-height) - var(--e-lift));\n margin-block-end: var(--e-lift);\n padding: 0 var(--e-space-4);\n border: var(--e-stroke-edge) solid var(--e-slab);\n border-radius: var(--e-radius-md);\n background: var(--e-fill);\n box-shadow: 0 var(--e-lift) 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 transform var(--e-duration-tap) var(--e-easing-out),\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 background: var(--e-hover);\n }\n\n .e-btn:active {\n background: var(--e-press);\n box-shadow: 0 0 0 0 var(--e-slab);\n transform: translateY(var(--e-lift));\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 background: color-mix(in srgb, var(--e-surface), var(--e-shade-hover));\n border-color: var(--e-ink);\n\n }\n\n .e-btn--outline:active {\n background: color-mix(in srgb, var(--e-surface), var(--e-shade-press));\n border-color: var(--e-ink);\n\n }\n\n .e-btn--quiet {\n border-color: transparent;\n\n --e-lift: 0px;\n\n background: transparent;\n color: var(--e-ink);\n box-shadow: none;\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 border-color: var(--e-wash-ring);\n background: var(--e-wash-hover);\n text-decoration-color: currentcolor;\n }\n\n .e-btn--quiet:not([disabled], [aria-disabled=\"true\"]):active {\n border-color: var(--e-ink);\n background: var(--e-wash-press);\n transform: none;\n }\n\n .e-btn .e-icon {\n margin-inline-start: calc(-0.5 * var(--e-space-1));\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\n border-color: var(--e-primary);\n background: 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 border: var(--e-stroke-edge) dashed var(--e-border-strong);\n outline: 0;\n box-shadow: none;\n transform: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-btn {\n transition: 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 border-color: GrayText;\n color: GrayText;\n }\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAKA,IAAMW,IAAQC;EAyBd,SAASC,EAAkB,GAAc;GACvC,AAAKF,EAAM,aACXG,EAAM,eAAe,GACrBA,EAAM,yBAAyB;EACjC;E,iBAKUF,EAAA,QADRZ,EAAA,GAAAC,EAcI,KAAA;;GAZD,MAAMW,EAAA;GACP,OAAKV,EAAA,CAAC,SAAO,CACJU,EAAA,YAAO,aAAA,UAA4BA,EAAA,WAAWA,EAAA,SAAK,cAAA,CAAA,CAAA;GAC3D,QAAQA,EAAA,WAAQ,WAAc,KAAA;GAC9B,KAAKA,EAAA,WAAQ,eAAkB,KAAA;GAC/B,iBAAeA,EAAA,WAAQ,SAAY,KAAA;GACnC,UAAUA,EAAA,WAAQ,KAAQ,KAAA;GACX,gBAAAC;GACG,mBAAAA;E,IAEND,EAAA,QAAbZ,EAAA,GAAAG,EAAkCC,GAAA;;GAAd,MAAMQ,EAAA;E,oCAC1BN,EAAQe,EAAA,QAAA,SAAA,C,cAEVrB,EAAA,GAAAC,EASS,UAAA;;GAPN,MAAMW,EAAA;GACP,OAAKV,EAAA,CAAC,SAAO,CACJU,EAAA,YAAO,aAAA,UAA4BA,EAAA,WAAWA,EAAA,SAAK,cAAA,CAAA,CAAA;GAC3D,UAAUA,EAAA;E,IAEEA,EAAA,QAAbZ,EAAA,GAAAG,EAAkCC,GAAA;;GAAd,MAAMQ,EAAA;E,oCAC1BN,EAAQe,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 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 +1 @@
1
- {"version":3,"file":"ECalendar.js","names":["_sfc_main","ECalendar_vue_vue_type_script_setup_true_lang_default","ECalendar_default"],"sources":["../../../src/components/Calendar/ECalendar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, getCurrentInstance, nextTick, ref, watch } from \"vue\";\nimport EActions from \"../Actions/EActions.vue\";\nimport EButton from \"../Button/EButton.vue\";\nimport EIcon from \"../Icon/EIcon.vue\";\nimport EIconButton from \"../IconButton/EIconButton.vue\";\nimport { useConfig, useMessages } from \"../../config.js\";\nimport { useLocale } from \"../../composables/useLocale.js\";\nimport { useUid } from \"../../composables/useUid.js\";\nimport { addDays, addMonths, compareDays, dayKey, sameDay, startOfDay } from \"./dates.js\";\nimport \"../../styles/base.css\";\n\nexport interface CalendarRange {\n start: Date | null;\n end: Date | null;\n}\n\nconst props = withDefaults(\n defineProps<{\n /** `single` chooses one day (`v-model`); `range` chooses a span (`v-model:start` and `v-model:end`): the first click sets the start, the second the end, and a click before the start restarts. */\n mode?: \"single\" | \"range\";\n /** Days that cannot be chosen or focused, such as days with nothing to book. Arrow keys skip them. */\n disabledDate?: (date: Date) => boolean;\n /** Days that get a dot: a list of dates or a function. Screen readers hear `markLabel`. */\n marked?: Date[] | ((date: Date) => boolean);\n /** What screen readers hear on a marked day. @default times available */\n markLabel?: string;\n /** The earliest day that can be chosen. Earlier days cannot be focused or chosen; navigation stops there. */\n min?: Date;\n /** The latest day that can be chosen. Later days cannot be focused or chosen; navigation stops there. */\n max?: Date;\n /** The month to open on, when nothing is chosen. Changing it moves the view. */\n month?: Date;\n /** `false` hides the Today and Clear buttons. */\n footer?: boolean;\n /** Forces the Clear button on or off. Left out, it shows when a `@clear` listener is attached. */\n clearable?: boolean;\n }>(),\n { mode: \"single\", footer: true, clearable: undefined },\n);\n\nconst emit = defineEmits<{\n /** In range mode, after every click that changes the span. */\n rangeChange: [range: CalendarRange];\n /** The Clear button. It is only shown when a `@clear` listener is attached. */\n clear: [];\n}>();\n\n/** The chosen day (`single` mode). */\nconst value = defineModel<Date | null>({ default: null });\n/** The first day of the span (`range` mode). */\nconst start = defineModel<Date | null>(\"start\", { default: null });\n/** The last day of the span (`range` mode). */\nconst end = defineModel<Date | null>(\"end\", { default: null });\n\ntype View = \"days\" | \"months\" | \"years\";\n\nconst t = useMessages();\nconst config = useConfig();\nconst loc = useLocale();\nconst uid = useUid();\nconst root = ref<HTMLElement | null>(null);\nconst range = computed(() => props.mode === \"range\");\nconst instance = getCurrentInstance();\nconst hasClear = () => props.clearable ?? !!instance?.vnode.props?.onClear;\n\nconst today = startOfDay(new Date());\nconst focus = ref(startOfDay((range.value ? start.value : value.value) || props.month || new Date()));\nconst hover = ref<Date | null>(null);\nconst view = ref<View>(\"days\");\nconst pick = ref(0);\n\nconst cy = computed(() => focus.value.getFullYear());\nconst cm = computed(() => focus.value.getMonth());\nconst yearLow = computed(() => Math.min(cy.value, props.min ? props.min.getFullYear() : today.getFullYear() - 120));\nconst yearHigh = computed(() => Math.max(cy.value, props.max ? props.max.getFullYear() : today.getFullYear() + 20));\nconst years = computed(() => Array.from({ length: yearHigh.value - yearLow.value + 1 }, (_, i) => yearLow.value + i));\n\nfunction off(d: Date): boolean {\n return (\n (!!props.min && compareDays(d, props.min) < 0) ||\n (!!props.max && compareDays(d, props.max) > 0) ||\n !!props.disabledDate?.(d)\n );\n}\nfunction isMarked(d: Date): boolean {\n const m = props.marked;\n if (!m) return false;\n return typeof m === \"function\" ? !!m(d) : m.some((x) => sameDay(x, d));\n}\nfunction monthOff(y: number, m: number): boolean {\n return (\n (!!props.min && compareDays(new Date(y, m + 1, 0, 12), props.min) < 0) ||\n (!!props.max && compareDays(new Date(y, m, 1, 12), props.max) > 0)\n );\n}\nconst yearOff = (y: number) =>\n (!!props.min && y < props.min.getFullYear()) || (!!props.max && y > props.max.getFullYear());\nfunction clamp(d: Date): Date {\n if (props.min && compareDays(d, props.min) < 0) return startOfDay(props.min);\n if (props.max && compareDays(d, props.max) > 0) return startOfDay(props.max);\n return d;\n}\nfunction settle(d: Date, step: number): Date | null {\n let n = d;\n for (let i = 0; i < 400 && off(n); i++) n = addDays(n, step);\n return off(n) ? null : n;\n}\nfunction withMonthYear(y: number, m: number): Date {\n const last = new Date(y, m + 1, 0, 12).getDate();\n return clamp(new Date(y, m, Math.min(focus.value.getDate(), last), 12));\n}\n\nif (off(focus.value)) focus.value = settle(focus.value, 1) ?? settle(focus.value, -1) ?? focus.value;\n\nlet want: string | null = null;\nasync function focusWanted() {\n await nextTick();\n if (!want) return;\n const el = root.value?.querySelector<HTMLElement>(`[id=\"${want}\"]`);\n if (!el) return;\n el.focus();\n if (want.includes(\"-y-\")) el.scrollIntoView?.({ block: \"center\" });\n want = null;\n}\nfunction focusId(id: string) {\n want = id;\n void focusWanted();\n}\nconst dayId = (d: Date) => `${uid.value}-${dayKey(d)}`;\n\nwatch(\n () => props.month?.getTime(),\n () => {\n if (props.month) focus.value = clamp(startOfDay(props.month));\n },\n);\nwatch(\n () => (range.value ? start.value : value.value)?.getTime(),\n () => {\n const chosen = range.value ? start.value : value.value;\n if (chosen && !sameDay(chosen, focus.value)) focus.value = startOfDay(chosen);\n },\n);\n\nconst weeks = computed(() => {\n const first = new Date(cy.value, cm.value, 1, 12);\n const from = addDays(first, -((first.getDay() - loc.weekStart.value + 7) % 7));\n return Array.from({ length: 6 }, (_, w) => Array.from({ length: 7 }, (_, i) => addDays(from, w * 7 + i)));\n});\nconst columns = computed(() => Array.from({ length: 7 }, (_, k) => (loc.weekStart.value + k) % 7));\nconst rangeEnd = computed(() => {\n if (!range.value) return null;\n return end.value || (start.value && hover.value && compareDays(hover.value, start.value) >= 0 ? hover.value : null);\n});\n\nfunction isSelected(d: Date): boolean {\n return range.value ? sameDay(d, start.value) || sameDay(d, end.value) : sameDay(d, value.value);\n}\nfunction inRange(d: Date): boolean {\n return !!(\n range.value &&\n start.value &&\n rangeEnd.value &&\n compareDays(d, start.value) > 0 &&\n compareDays(d, rangeEnd.value) < 0\n );\n}\nfunction dayLabel(d: Date, marked: boolean): string {\n return (\n loc.formatLong(d) +\n (sameDay(d, today) ? \", \" + t(\"todaySuffix\") : \"\") +\n (marked ? \", \" + (props.markLabel || t(\"timesAvailable\")) : \"\")\n );\n}\n\nfunction pickDay(d: Date) {\n if (off(d)) return;\n if (!range.value) {\n value.value = d;\n return;\n }\n const s = start.value;\n if (!s || end.value || compareDays(d, s) < 0) {\n start.value = d;\n end.value = null;\n emit(\"rangeChange\", { start: d, end: null });\n } else {\n end.value = d;\n emit(\"rangeChange\", { start: s, end: d });\n }\n}\nfunction clickDay(d: Date) {\n focus.value = d;\n focusId(dayId(d));\n pickDay(d);\n}\n\nfunction openView(v: \"months\" | \"years\") {\n view.value = v;\n if (v === \"months\") {\n pick.value = cm.value;\n focusId(`${uid.value}-m-${cm.value}`);\n } else {\n pick.value = cy.value;\n focusId(`${uid.value}-y-${cy.value}`);\n }\n}\nfunction backToDays() {\n view.value = \"days\";\n focusId(dayId(focus.value));\n}\nfunction back() {\n if (view.value === \"months\") openView(\"years\");\n else backToDays();\n}\nfunction chooseMonth(m: number) {\n if (monthOff(cy.value, m)) return;\n const nd = withMonthYear(cy.value, m);\n focus.value = nd;\n view.value = \"days\";\n focusId(dayId(nd));\n}\nfunction chooseYear(y: number) {\n if (yearOff(y)) return;\n const nd = withMonthYear(y, cm.value);\n focus.value = nd;\n view.value = \"months\";\n pick.value = nd.getMonth();\n focusId(`${uid.value}-m-${nd.getMonth()}`);\n}\nfunction step(n: number) {\n focus.value = clamp(addMonths(focus.value, n));\n}\n\nfunction sign(): number {\n if (config.dir) return config.dir === \"rtl\" ? -1 : 1;\n return root.value && getComputedStyle(root.value).direction === \"rtl\" ? -1 : 1;\n}\n\nfunction onDayKey(e: KeyboardEvent) {\n const f = focus.value;\n const dow = (f.getDay() - loc.weekStart.value + 7) % 7;\n const s = sign();\n let next: Date;\n let walk: number;\n switch (e.key) {\n case \"ArrowLeft\":\n walk = -s;\n next = addDays(f, walk);\n break;\n case \"ArrowRight\":\n walk = s;\n next = addDays(f, walk);\n break;\n case \"ArrowUp\":\n walk = -7;\n next = addDays(f, walk);\n break;\n case \"ArrowDown\":\n walk = 7;\n next = addDays(f, walk);\n break;\n case \"Home\":\n walk = 1;\n next = addDays(f, -dow);\n break;\n case \"End\":\n walk = -1;\n next = addDays(f, 6 - dow);\n break;\n case \"PageUp\":\n walk = -1;\n next = addMonths(f, e.shiftKey ? -12 : -1);\n break;\n case \"PageDown\":\n walk = 1;\n next = addMonths(f, e.shiftKey ? 12 : 1);\n break;\n default:\n return;\n }\n e.preventDefault();\n const target = settle(next, walk);\n if (!target) return;\n focus.value = target;\n focusId(dayId(target));\n if (range.value && start.value && !end.value) hover.value = target;\n}\n\nfunction onPickKey(e: KeyboardEvent) {\n const months = view.value === \"months\";\n const lo = months ? 0 : yearLow.value;\n const hi = months ? 11 : yearHigh.value;\n const s = sign();\n let next: number | null = null;\n switch (e.key) {\n case \"ArrowLeft\":\n next = pick.value - s;\n break;\n case \"ArrowRight\":\n next = pick.value + s;\n break;\n case \"ArrowUp\":\n next = pick.value - 3;\n break;\n case \"ArrowDown\":\n next = pick.value + 3;\n break;\n case \"Home\":\n next = lo;\n break;\n case \"End\":\n next = hi;\n break;\n case \"PageUp\":\n if (!months) next = pick.value - 12;\n break;\n case \"PageDown\":\n if (!months) next = pick.value + 12;\n break;\n }\n if (next === null) return;\n e.preventDefault();\n next = Math.max(lo, Math.min(hi, next));\n pick.value = next;\n focusId(`${uid.value}-${months ? \"m\" : \"y\"}-${next}`);\n}\n\nfunction onRootKey(e: KeyboardEvent) {\n if (e.key !== \"Escape\" || view.value === \"days\") return;\n e.preventDefault();\n e.stopPropagation();\n backToDays();\n}\n\nfunction goToday() {\n const tc = clamp(today);\n focus.value = tc;\n focusId(dayId(tc));\n if (!range.value && !off(today)) pickDay(today);\n}\n\nconst shortDate = (d: Date) => `${loc.monthsShort.value[d.getMonth()]} ${d.getDate()}`;\nconst help = computed(() => {\n if (!range.value || view.value !== \"days\") return \"\";\n if (!start.value) return t(\"rangeStart\");\n if (!end.value) return t(\"rangeEnd\", { start: shortDate(start.value) });\n return t(\"rangeDone\", {\n start: shortDate(start.value),\n end: shortDate(end.value),\n days: Math.round(compareDays(end.value, start.value) / 864e5) + 1,\n });\n});\n\nconst picking = computed(() => view.value !== \"days\");\nconst prevOff = computed(() => !!props.min && compareDays(new Date(cy.value, cm.value, 0, 12), props.min) < 0);\nconst nextOff = computed(() => !!props.max && compareDays(new Date(cy.value, cm.value + 1, 1, 12), props.max) > 0);\nconst nowYear = today.getFullYear();\nconst nowMonth = today.getMonth();\n\ndefineExpose({\n view,\n focusDay: () => focusId(dayId(focus.value)),\n});\n</script>\n\n<template>\n <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -->\n <div ref=\"root\" class=\"e-cal\" :dir=\"config.dir ?? undefined\" @keydown=\"onRootKey\">\n <div class=\"e-cal-head\">\n <EIconButton\n v-if=\"picking\"\n icon=\"chevron-left\"\n :label=\"t(view === 'months' ? 'backToYears' : 'backToDays')\"\n @click=\"back\"\n />\n <EIconButton v-else icon=\"chevron-left\" :label=\"t('prevMonth')\" :disabled=\"prevOff\" @click=\"step(-1)\" />\n <div class=\"e-cal-title\" aria-live=\"polite\">\n <span v-if=\"picking\" class=\"e-cal-range\">{{\n t(view === \"months\" ? \"chooseAMonth\" : \"chooseAYear\", { year: cy })\n }}</span>\n <button\n v-else\n type=\"button\"\n class=\"e-cal-pick\"\n aria-expanded=\"false\"\n :aria-label=\"t('chooseDateNow', { month: loc.months.value[cm] ?? '', year: cy })\"\n @click=\"openView('years')\"\n >\n {{ loc.months.value[cm] }} {{ cy }}\n <EIcon name=\"chevron-down\" small />\n </button>\n </div>\n <span v-if=\"picking\" class=\"e-cal-gap\" />\n <EIconButton v-else icon=\"chevron-right\" :label=\"t('nextMonth')\" :disabled=\"nextOff\" @click=\"step(1)\" />\n </div>\n\n <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -- the day buttons carry the roving tabindex -->\n <table\n v-if=\"view === 'days'\"\n class=\"e-cal-grid\"\n role=\"grid\"\n :aria-label=\"`${loc.months.value[cm]} ${cy}`\"\n @keydown=\"onDayKey\"\n >\n <thead>\n <tr>\n <th v-for=\"ix in columns\" :key=\"ix\" scope=\"col\" :abbr=\"loc.weekdays.value[ix]\">\n {{ loc.weekdaysShort.value[ix] }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(row, w) in weeks\" :key=\"w\">\n <td\n v-for=\"d in row\"\n :key=\"dayKey(d)\"\n role=\"gridcell\"\n :aria-selected=\"isSelected(d) || inRange(d) ? 'true' : 'false'\"\n :class=\"inRange(d) && 'e-cal-in'\"\n >\n <button\n :id=\"dayId(d)\"\n type=\"button\"\n class=\"e-day\"\n :class=\"[\n d.getMonth() !== cm && 'e-day--out',\n sameDay(d, today) && 'e-day--today',\n isSelected(d) && 'e-day--sel',\n !off(d) && isMarked(d) && 'e-day--mark',\n ]\"\n :tabindex=\"sameDay(d, focus) ? 0 : -1\"\n :disabled=\"off(d)\"\n :aria-label=\"dayLabel(d, !off(d) && isMarked(d))\"\n @click=\"clickDay(d)\"\n @mouseenter=\"range && start && !end && (hover = d)\"\n @focus=\"range && start && !end && (hover = d)\"\n >\n {{ d.getDate() }}\n </button>\n </td>\n </tr>\n </tbody>\n </table>\n\n <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -->\n <div\n v-else-if=\"view === 'months'\"\n class=\"e-cal-cells\"\n role=\"group\"\n :aria-label=\"t('monthsOf', { year: cy })\"\n @keydown=\"onPickKey\"\n >\n <button\n v-for=\"(name, m) in loc.months.value\"\n :id=\"`${uid}-m-${m}`\"\n :key=\"m\"\n type=\"button\"\n class=\"e-cal-cell\"\n :class=\"[m === cm && 'e-day--sel', cy === nowYear && m === nowMonth && 'e-day--today']\"\n :tabindex=\"m === pick ? 0 : -1\"\n :disabled=\"monthOff(cy, m)\"\n :aria-pressed=\"m === cm ? 'true' : 'false'\"\n :aria-current=\"cy === nowYear && m === nowMonth ? 'date' : undefined\"\n @click=\"chooseMonth(m)\"\n >\n <span aria-hidden=\"true\">{{ loc.monthsShort.value[m] }}</span>\n <span class=\"e-sr\">{{ name }} {{ cy }}</span>\n </button>\n </div>\n\n <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -->\n <div\n v-else\n class=\"e-cal-cells e-cal-years\"\n role=\"group\"\n :aria-label=\"t('yearsRange', { from: yearLow, to: yearHigh })\"\n @keydown=\"onPickKey\"\n >\n <button\n v-for=\"y in years\"\n :id=\"`${uid}-y-${y}`\"\n :key=\"y\"\n type=\"button\"\n class=\"e-cal-cell\"\n :class=\"[y === cy && 'e-day--sel', y === nowYear && 'e-day--today']\"\n :tabindex=\"y === pick ? 0 : -1\"\n :disabled=\"yearOff(y)\"\n :aria-pressed=\"y === cy ? 'true' : 'false'\"\n :aria-current=\"y === nowYear ? 'date' : undefined\"\n @click=\"chooseYear(y)\"\n >\n {{ y }}\n </button>\n </div>\n\n <p v-if=\"range\" class=\"e-cal-help\" aria-live=\"polite\">{{ help }}</p>\n\n <EActions v-if=\"footer\" class=\"e-cal-foot\" :class=\"view !== 'days' && 'e-cal-foot--idle'\" :inert=\"view !== 'days'\">\n <EButton variant=\"quiet\" @click=\"goToday\">{{ t(\"today\") }}</EButton>\n <EButton v-if=\"hasClear()\" variant=\"quiet\" @click=\"emit('clear')\">{{ t(\"clear\") }}</EButton>\n </EActions>\n </div>\n</template>\n\n<style>\n@layer e.composites {\n .e-cal {\n width: 20.5rem;\n max-width: 100%;\n font-family: var(--e-font-sans);\n }\n\n .e-cal-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--e-space-2);\n margin-bottom: var(--e-space-2);\n padding-bottom: var(--e-space-2);\n border-bottom: var(--e-stroke-hair) solid var(--e-border);\n }\n\n .e-cal-title {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--e-space-1);\n flex: 1;\n min-width: 0;\n margin: 0;\n font: 600 var(--e-text-lg) / 1.2 var(--e-font-sans);\n text-align: center;\n }\n\n .e-cal-pick {\n display: inline-flex;\n align-items: center;\n gap: var(--e-space-1);\n height: var(--e-control-height);\n padding: 0 var(--e-space-2);\n border: var(--e-stroke-edge) solid transparent;\n border-radius: var(--e-radius-md);\n background: transparent;\n color: var(--e-ink);\n font: 600 var(--e-text-lg) / 1 var(--e-font-sans);\n cursor: pointer;\n transition: background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-cal-pick:hover {\n background: var(--e-surface-hover);\n border-color: var(--e-border-strong);\n\n }\n\n .e-cal-pick:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n .e-cal-pick .e-icon {\n transition: transform var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-cal-pick[aria-expanded=\"true\"] .e-icon {\n transform: rotate(180deg);\n }\n\n .e-cal-range {\n font: 600 var(--e-text-lg) / 1.2 var(--e-font-sans);\n font-variant-numeric: tabular-nums;\n }\n\n .e-cal-gap {\n display: block;\n width: var(--e-tap);\n height: var(--e-tap);\n }\n\n .e-cal-head .e-icon-btn:disabled {\n color: var(--e-muted);\n cursor: not-allowed;\n }\n\n .e-cal-head .e-icon-btn:disabled:hover {\n background: transparent;\n box-shadow: none;\n }\n\n .e-cal-grid {\n width: 100%;\n height: calc(6 * var(--e-tap) + var(--e-space-8) + var(--e-space-4));\n border-collapse: collapse;\n table-layout: fixed;\n }\n\n .e-cal-grid th {\n height: var(--e-space-8);\n font: 600 var(--e-text-sm) / 1 var(--e-font-sans);\n color: var(--e-muted);\n text-align: center;\n }\n\n .e-cal-grid td {\n padding: 1px 3px;\n text-align: center;\n }\n\n .e-cal-in {\n background: color-mix(in srgb, var(--e-primary) 12%, var(--e-surface));\n }\n\n .e-day {\n position: relative;\n width: 100%;\n height: var(--e-tap);\n padding: 0;\n border: var(--e-stroke-edge) solid transparent;\n border-radius: var(--e-radius-md);\n background: transparent;\n color: var(--e-ink);\n font: 500 var(--e-text-sm) / 1 var(--e-font-mono);\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n /* stylelint-disable-next-line selector-not-notation -- the selector stays in this form */\n .e-day:hover:not(:disabled):not(.e-day--sel) {\n background: var(--e-surface-hover);\n border-color: var(--e-border-strong);\n\n }\n\n .e-day: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 .e-day--out {\n color: var(--e-muted);\n font-weight: 400;\n }\n\n .e-day--today {\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-primary);\n }\n\n .e-day--sel {\n background: var(--e-primary);\n border-color: var(--e-primary);\n font-weight: 700;\n color: var(--e-on-primary);\n }\n\n .e-day:disabled {\n color: var(--e-border-strong);\n font-weight: 400;\n cursor: not-allowed;\n opacity: 1;\n }\n\n .e-day--mark::after {\n content: \"\";\n position: absolute;\n inset-inline-start: 50%;\n bottom: 5px;\n width: 5px;\n height: 5px;\n margin-inline-start: -2.5px;\n border-radius: 50%;\n background: var(--e-primary);\n }\n\n .e-day--sel.e-day--mark::after {\n background: var(--e-on-primary);\n }\n\n .e-cal-cells {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n grid-auto-rows: 1fr;\n gap: 6px;\n height: calc(6 * var(--e-tap) + var(--e-space-8) + var(--e-space-4));\n padding-top: var(--e-space-1);\n }\n\n .e-cal-years {\n overflow-y: auto;\n grid-auto-rows: var(--e-tap);\n padding-inline-end: 2px;\n align-content: start;\n }\n\n .e-cal-cell {\n width: 100%;\n height: 100%;\n min-height: var(--e-tap);\n padding: 0;\n border: var(--e-stroke-edge) solid transparent;\n border-radius: var(--e-radius-md);\n background: transparent;\n color: var(--e-ink);\n font: 500 var(--e-text-md) / 1 var(--e-font-mono);\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-cal-years .e-cal-cell {\n height: var(--e-tap);\n }\n\n /* stylelint-disable-next-line selector-not-notation -- the selector stays in this form */\n .e-cal-cell:hover:not(:disabled):not(.e-day--sel) {\n background: var(--e-surface-hover);\n border-color: var(--e-border-strong);\n\n }\n\n .e-cal-cell: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 .e-cal-cell:disabled {\n color: var(--e-border-strong);\n font-weight: 400;\n cursor: not-allowed;\n }\n\n .e-cal-cell.e-day--sel {\n background: var(--e-primary);\n border-color: var(--e-primary);\n font-weight: 700;\n color: var(--e-on-primary);\n }\n\n .e-cal-help {\n min-height: calc(var(--e-text-sm) * 1.4);\n margin: var(--e-space-2) 0 0;\n font: 500 var(--e-text-sm) / 1.4 var(--e-font-sans);\n color: var(--e-muted);\n text-align: center;\n }\n\n .e-cal-foot {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: var(--e-space-2);\n margin-top: var(--e-space-2);\n padding-top: var(--e-space-2);\n border-top: var(--e-stroke-hair) solid var(--e-border);\n }\n\n .e-cal-foot--idle {\n visibility: hidden;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-day,\n .e-cal-pick,\n .e-cal-cell,\n .e-cal-pick .e-icon {\n transition: none;\n }\n }\n\n @media (forced-colors: active) {\n .e-day--sel,\n .e-cal-cell.e-day--sel {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .e-day--mark::after {\n background: CanvasText;\n }\n\n .e-day--sel.e-day--mark::after {\n background: HighlightText;\n }\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"ECalendar.js","names":["_sfc_main","ECalendar_vue_vue_type_script_setup_true_lang_default","ECalendar_default"],"sources":["../../../src/components/Calendar/ECalendar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, getCurrentInstance, nextTick, ref, watch } from \"vue\";\nimport EActions from \"../Actions/EActions.vue\";\nimport EButton from \"../Button/EButton.vue\";\nimport EIcon from \"../Icon/EIcon.vue\";\nimport EIconButton from \"../IconButton/EIconButton.vue\";\nimport { useConfig, useMessages } from \"../../config.js\";\nimport { useLocale } from \"../../composables/useLocale.js\";\nimport { useUid } from \"../../composables/useUid.js\";\nimport { addDays, addMonths, compareDays, dayKey, sameDay, startOfDay } from \"./dates.js\";\nimport \"../../styles/base.css\";\n\nexport interface CalendarRange {\n start: Date | null;\n end: Date | null;\n}\n\nconst props = withDefaults(\n defineProps<{\n /** `single` chooses one day (`v-model`); `range` chooses a span (`v-model:start` and `v-model:end`): the first click sets the start, the second the end, and a click before the start restarts. */\n mode?: \"single\" | \"range\";\n /** Days that cannot be chosen or focused, such as days with nothing to book. Arrow keys skip them. */\n disabledDate?: (date: Date) => boolean;\n /** Days that get a dot: a list of dates or a function. Screen readers hear `markLabel`. */\n marked?: Date[] | ((date: Date) => boolean);\n /** What screen readers hear on a marked day. @default \"times available\" */\n markLabel?: string;\n /** The earliest day that can be chosen. Earlier days cannot be focused or chosen; navigation stops there. */\n min?: Date;\n /** The latest day that can be chosen. Later days cannot be focused or chosen; navigation stops there. */\n max?: Date;\n /** The month to open on, when nothing is chosen. Changing it moves the view. */\n month?: Date;\n /** `false` hides the Today and Clear buttons. */\n footer?: boolean;\n /** Forces the Clear button on or off. Left out, it shows when a `@clear` listener is attached. */\n clearable?: boolean;\n }>(),\n { mode: \"single\", footer: true, clearable: undefined },\n);\n\nconst emit = defineEmits<{\n /** In range mode, after every click that changes the span. */\n rangeChange: [range: CalendarRange];\n /** The Clear button. It is only shown when a `@clear` listener is attached. */\n clear: [];\n}>();\n\n/** The chosen day (`single` mode). */\nconst value = defineModel<Date | null>({ default: null });\n/** The first day of the span (`range` mode). */\nconst start = defineModel<Date | null>(\"start\", { default: null });\n/** The last day of the span (`range` mode). */\nconst end = defineModel<Date | null>(\"end\", { default: null });\n\ntype View = \"days\" | \"months\" | \"years\";\n\nconst t = useMessages();\nconst config = useConfig();\nconst loc = useLocale();\nconst uid = useUid();\nconst root = ref<HTMLElement | null>(null);\nconst range = computed(() => props.mode === \"range\");\nconst instance = getCurrentInstance();\nconst hasClear = () => props.clearable ?? !!instance?.vnode.props?.onClear;\n\nconst today = startOfDay(new Date());\nconst focus = ref(startOfDay((range.value ? start.value : value.value) || props.month || new Date()));\nconst hover = ref<Date | null>(null);\nconst view = ref<View>(\"days\");\nconst pick = ref(0);\n\nconst cy = computed(() => focus.value.getFullYear());\nconst cm = computed(() => focus.value.getMonth());\nconst yearLow = computed(() => Math.min(cy.value, props.min ? props.min.getFullYear() : today.getFullYear() - 120));\nconst yearHigh = computed(() => Math.max(cy.value, props.max ? props.max.getFullYear() : today.getFullYear() + 20));\nconst years = computed(() => Array.from({ length: yearHigh.value - yearLow.value + 1 }, (_, i) => yearLow.value + i));\n\nfunction off(d: Date): boolean {\n return (\n (!!props.min && compareDays(d, props.min) < 0) ||\n (!!props.max && compareDays(d, props.max) > 0) ||\n !!props.disabledDate?.(d)\n );\n}\nfunction isMarked(d: Date): boolean {\n const m = props.marked;\n if (!m) return false;\n return typeof m === \"function\" ? !!m(d) : m.some((x) => sameDay(x, d));\n}\nfunction monthOff(y: number, m: number): boolean {\n return (\n (!!props.min && compareDays(new Date(y, m + 1, 0, 12), props.min) < 0) ||\n (!!props.max && compareDays(new Date(y, m, 1, 12), props.max) > 0)\n );\n}\nconst yearOff = (y: number) =>\n (!!props.min && y < props.min.getFullYear()) || (!!props.max && y > props.max.getFullYear());\nfunction clamp(d: Date): Date {\n if (props.min && compareDays(d, props.min) < 0) return startOfDay(props.min);\n if (props.max && compareDays(d, props.max) > 0) return startOfDay(props.max);\n return d;\n}\nfunction settle(d: Date, step: number): Date | null {\n let n = d;\n for (let i = 0; i < 400 && off(n); i++) n = addDays(n, step);\n return off(n) ? null : n;\n}\nfunction withMonthYear(y: number, m: number): Date {\n const last = new Date(y, m + 1, 0, 12).getDate();\n return clamp(new Date(y, m, Math.min(focus.value.getDate(), last), 12));\n}\n\nif (off(focus.value)) focus.value = settle(focus.value, 1) ?? settle(focus.value, -1) ?? focus.value;\n\nlet want: string | null = null;\nasync function focusWanted() {\n await nextTick();\n if (!want) return;\n const el = root.value?.querySelector<HTMLElement>(`[id=\"${want}\"]`);\n if (!el) return;\n el.focus();\n if (want.includes(\"-y-\")) el.scrollIntoView?.({ block: \"center\" });\n want = null;\n}\nfunction focusId(id: string) {\n want = id;\n void focusWanted();\n}\nconst dayId = (d: Date) => `${uid.value}-${dayKey(d)}`;\n\nwatch(\n () => props.month?.getTime(),\n () => {\n if (props.month) focus.value = clamp(startOfDay(props.month));\n },\n);\nwatch(\n () => (range.value ? start.value : value.value)?.getTime(),\n () => {\n const chosen = range.value ? start.value : value.value;\n if (chosen && !sameDay(chosen, focus.value)) focus.value = startOfDay(chosen);\n },\n);\n\nconst weeks = computed(() => {\n const first = new Date(cy.value, cm.value, 1, 12);\n const from = addDays(first, -((first.getDay() - loc.weekStart.value + 7) % 7));\n return Array.from({ length: 6 }, (_, w) => Array.from({ length: 7 }, (_, i) => addDays(from, w * 7 + i)));\n});\nconst columns = computed(() => Array.from({ length: 7 }, (_, k) => (loc.weekStart.value + k) % 7));\nconst rangeEnd = computed(() => {\n if (!range.value) return null;\n return end.value || (start.value && hover.value && compareDays(hover.value, start.value) >= 0 ? hover.value : null);\n});\n\nfunction isSelected(d: Date): boolean {\n return range.value ? sameDay(d, start.value) || sameDay(d, end.value) : sameDay(d, value.value);\n}\nfunction inRange(d: Date): boolean {\n return !!(\n range.value &&\n start.value &&\n rangeEnd.value &&\n compareDays(d, start.value) > 0 &&\n compareDays(d, rangeEnd.value) < 0\n );\n}\nfunction dayLabel(d: Date, marked: boolean): string {\n return (\n loc.formatLong(d) +\n (sameDay(d, today) ? \", \" + t(\"todaySuffix\") : \"\") +\n (marked ? \", \" + (props.markLabel || t(\"timesAvailable\")) : \"\")\n );\n}\n\nfunction pickDay(d: Date) {\n if (off(d)) return;\n if (!range.value) {\n value.value = d;\n return;\n }\n const s = start.value;\n if (!s || end.value || compareDays(d, s) < 0) {\n start.value = d;\n end.value = null;\n emit(\"rangeChange\", { start: d, end: null });\n } else {\n end.value = d;\n emit(\"rangeChange\", { start: s, end: d });\n }\n}\nfunction clickDay(d: Date) {\n focus.value = d;\n focusId(dayId(d));\n pickDay(d);\n}\n\nfunction openView(v: \"months\" | \"years\") {\n view.value = v;\n if (v === \"months\") {\n pick.value = cm.value;\n focusId(`${uid.value}-m-${cm.value}`);\n } else {\n pick.value = cy.value;\n focusId(`${uid.value}-y-${cy.value}`);\n }\n}\nfunction backToDays() {\n view.value = \"days\";\n focusId(dayId(focus.value));\n}\nfunction back() {\n if (view.value === \"months\") openView(\"years\");\n else backToDays();\n}\nfunction chooseMonth(m: number) {\n if (monthOff(cy.value, m)) return;\n const nd = withMonthYear(cy.value, m);\n focus.value = nd;\n view.value = \"days\";\n focusId(dayId(nd));\n}\nfunction chooseYear(y: number) {\n if (yearOff(y)) return;\n const nd = withMonthYear(y, cm.value);\n focus.value = nd;\n view.value = \"months\";\n pick.value = nd.getMonth();\n focusId(`${uid.value}-m-${nd.getMonth()}`);\n}\nfunction step(n: number) {\n focus.value = clamp(addMonths(focus.value, n));\n}\n\nfunction sign(): number {\n if (config.dir) return config.dir === \"rtl\" ? -1 : 1;\n return root.value && getComputedStyle(root.value).direction === \"rtl\" ? -1 : 1;\n}\n\nfunction onDayKey(e: KeyboardEvent) {\n const f = focus.value;\n const dow = (f.getDay() - loc.weekStart.value + 7) % 7;\n const s = sign();\n let next: Date;\n let walk: number;\n switch (e.key) {\n case \"ArrowLeft\":\n walk = -s;\n next = addDays(f, walk);\n break;\n case \"ArrowRight\":\n walk = s;\n next = addDays(f, walk);\n break;\n case \"ArrowUp\":\n walk = -7;\n next = addDays(f, walk);\n break;\n case \"ArrowDown\":\n walk = 7;\n next = addDays(f, walk);\n break;\n case \"Home\":\n walk = 1;\n next = addDays(f, -dow);\n break;\n case \"End\":\n walk = -1;\n next = addDays(f, 6 - dow);\n break;\n case \"PageUp\":\n walk = -1;\n next = addMonths(f, e.shiftKey ? -12 : -1);\n break;\n case \"PageDown\":\n walk = 1;\n next = addMonths(f, e.shiftKey ? 12 : 1);\n break;\n default:\n return;\n }\n e.preventDefault();\n const target = settle(next, walk);\n if (!target) return;\n focus.value = target;\n focusId(dayId(target));\n if (range.value && start.value && !end.value) hover.value = target;\n}\n\nfunction onPickKey(e: KeyboardEvent) {\n const months = view.value === \"months\";\n const lo = months ? 0 : yearLow.value;\n const hi = months ? 11 : yearHigh.value;\n const s = sign();\n let next: number | null = null;\n switch (e.key) {\n case \"ArrowLeft\":\n next = pick.value - s;\n break;\n case \"ArrowRight\":\n next = pick.value + s;\n break;\n case \"ArrowUp\":\n next = pick.value - 3;\n break;\n case \"ArrowDown\":\n next = pick.value + 3;\n break;\n case \"Home\":\n next = lo;\n break;\n case \"End\":\n next = hi;\n break;\n case \"PageUp\":\n if (!months) next = pick.value - 12;\n break;\n case \"PageDown\":\n if (!months) next = pick.value + 12;\n break;\n }\n if (next === null) return;\n e.preventDefault();\n next = Math.max(lo, Math.min(hi, next));\n pick.value = next;\n focusId(`${uid.value}-${months ? \"m\" : \"y\"}-${next}`);\n}\n\nfunction onRootKey(e: KeyboardEvent) {\n if (e.key !== \"Escape\" || view.value === \"days\") return;\n e.preventDefault();\n e.stopPropagation();\n backToDays();\n}\n\nfunction goToday() {\n const tc = clamp(today);\n focus.value = tc;\n focusId(dayId(tc));\n if (!range.value && !off(today)) pickDay(today);\n}\n\nconst shortDate = (d: Date) => `${loc.monthsShort.value[d.getMonth()]} ${d.getDate()}`;\nconst help = computed(() => {\n if (!range.value || view.value !== \"days\") return \"\";\n if (!start.value) return t(\"rangeStart\");\n if (!end.value) return t(\"rangeEnd\", { start: shortDate(start.value) });\n return t(\"rangeDone\", {\n start: shortDate(start.value),\n end: shortDate(end.value),\n days: Math.round(compareDays(end.value, start.value) / 864e5) + 1,\n });\n});\n\nconst picking = computed(() => view.value !== \"days\");\nconst prevOff = computed(() => !!props.min && compareDays(new Date(cy.value, cm.value, 0, 12), props.min) < 0);\nconst nextOff = computed(() => !!props.max && compareDays(new Date(cy.value, cm.value + 1, 1, 12), props.max) > 0);\nconst nowYear = today.getFullYear();\nconst nowMonth = today.getMonth();\n\ndefineExpose({\n view,\n focusDay: () => focusId(dayId(focus.value)),\n});\n</script>\n\n<template>\n <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -->\n <div ref=\"root\" class=\"e-cal\" :dir=\"config.dir ?? undefined\" @keydown=\"onRootKey\">\n <div class=\"e-cal-head\">\n <EIconButton\n v-if=\"picking\"\n icon=\"chevron-left\"\n :label=\"t(view === 'months' ? 'backToYears' : 'backToDays')\"\n @click=\"back\"\n />\n <EIconButton v-else icon=\"chevron-left\" :label=\"t('prevMonth')\" :disabled=\"prevOff\" @click=\"step(-1)\" />\n <div class=\"e-cal-title\" aria-live=\"polite\">\n <span v-if=\"picking\" class=\"e-cal-range\">{{\n t(view === \"months\" ? \"chooseAMonth\" : \"chooseAYear\", { year: cy })\n }}</span>\n <button\n v-else\n type=\"button\"\n class=\"e-cal-pick\"\n aria-expanded=\"false\"\n :aria-label=\"t('chooseDateNow', { month: loc.months.value[cm] ?? '', year: cy })\"\n @click=\"openView('years')\"\n >\n {{ loc.months.value[cm] }} {{ cy }}\n <EIcon name=\"chevron-down\" small />\n </button>\n </div>\n <span v-if=\"picking\" class=\"e-cal-gap\" />\n <EIconButton v-else icon=\"chevron-right\" :label=\"t('nextMonth')\" :disabled=\"nextOff\" @click=\"step(1)\" />\n </div>\n\n <!-- eslint-disable-next-line vuejs-accessibility/interactive-supports-focus -- the day buttons carry the roving tabindex -->\n <table\n v-if=\"view === 'days'\"\n class=\"e-cal-grid\"\n role=\"grid\"\n :aria-label=\"`${loc.months.value[cm]} ${cy}`\"\n @keydown=\"onDayKey\"\n >\n <thead>\n <tr>\n <th v-for=\"ix in columns\" :key=\"ix\" scope=\"col\" :abbr=\"loc.weekdays.value[ix]\">\n {{ loc.weekdaysShort.value[ix] }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(row, w) in weeks\" :key=\"w\">\n <td\n v-for=\"d in row\"\n :key=\"dayKey(d)\"\n role=\"gridcell\"\n :aria-selected=\"isSelected(d) || inRange(d) ? 'true' : 'false'\"\n :class=\"inRange(d) && 'e-cal-in'\"\n >\n <button\n :id=\"dayId(d)\"\n type=\"button\"\n class=\"e-day\"\n :class=\"[\n d.getMonth() !== cm && 'e-day--out',\n sameDay(d, today) && 'e-day--today',\n isSelected(d) && 'e-day--sel',\n !off(d) && isMarked(d) && 'e-day--mark',\n ]\"\n :tabindex=\"sameDay(d, focus) ? 0 : -1\"\n :disabled=\"off(d)\"\n :aria-label=\"dayLabel(d, !off(d) && isMarked(d))\"\n @click=\"clickDay(d)\"\n @mouseenter=\"range && start && !end && (hover = d)\"\n @focus=\"range && start && !end && (hover = d)\"\n >\n {{ d.getDate() }}\n </button>\n </td>\n </tr>\n </tbody>\n </table>\n\n <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -->\n <div\n v-else-if=\"view === 'months'\"\n class=\"e-cal-cells\"\n role=\"group\"\n :aria-label=\"t('monthsOf', { year: cy })\"\n @keydown=\"onPickKey\"\n >\n <button\n v-for=\"(name, m) in loc.months.value\"\n :id=\"`${uid}-m-${m}`\"\n :key=\"m\"\n type=\"button\"\n class=\"e-cal-cell\"\n :class=\"[m === cm && 'e-day--sel', cy === nowYear && m === nowMonth && 'e-day--today']\"\n :tabindex=\"m === pick ? 0 : -1\"\n :disabled=\"monthOff(cy, m)\"\n :aria-pressed=\"m === cm ? 'true' : 'false'\"\n :aria-current=\"cy === nowYear && m === nowMonth ? 'date' : undefined\"\n @click=\"chooseMonth(m)\"\n >\n <span aria-hidden=\"true\">{{ loc.monthsShort.value[m] }}</span>\n <span class=\"e-sr\">{{ name }} {{ cy }}</span>\n </button>\n </div>\n\n <!-- eslint-disable-next-line vuejs-accessibility/no-static-element-interactions -->\n <div\n v-else\n class=\"e-cal-cells e-cal-years\"\n role=\"group\"\n :aria-label=\"t('yearsRange', { from: yearLow, to: yearHigh })\"\n @keydown=\"onPickKey\"\n >\n <button\n v-for=\"y in years\"\n :id=\"`${uid}-y-${y}`\"\n :key=\"y\"\n type=\"button\"\n class=\"e-cal-cell\"\n :class=\"[y === cy && 'e-day--sel', y === nowYear && 'e-day--today']\"\n :tabindex=\"y === pick ? 0 : -1\"\n :disabled=\"yearOff(y)\"\n :aria-pressed=\"y === cy ? 'true' : 'false'\"\n :aria-current=\"y === nowYear ? 'date' : undefined\"\n @click=\"chooseYear(y)\"\n >\n {{ y }}\n </button>\n </div>\n\n <p v-if=\"range\" class=\"e-cal-help\" aria-live=\"polite\">{{ help }}</p>\n\n <EActions v-if=\"footer\" class=\"e-cal-foot\" :class=\"view !== 'days' && 'e-cal-foot--idle'\" :inert=\"view !== 'days'\">\n <EButton variant=\"quiet\" @click=\"goToday\">{{ t(\"today\") }}</EButton>\n <EButton v-if=\"hasClear()\" variant=\"quiet\" @click=\"emit('clear')\">{{ t(\"clear\") }}</EButton>\n </EActions>\n </div>\n</template>\n\n<style>\n@layer e.composites {\n .e-cal {\n width: 20.5rem;\n max-width: 100%;\n font-family: var(--e-font-sans);\n }\n\n .e-cal-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--e-space-2);\n margin-bottom: var(--e-space-2);\n padding-bottom: var(--e-space-2);\n border-bottom: var(--e-stroke-hair) solid var(--e-border);\n }\n\n .e-cal-title {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--e-space-1);\n flex: 1;\n min-width: 0;\n margin: 0;\n font: 600 var(--e-text-lg) / 1.2 var(--e-font-sans);\n text-align: center;\n }\n\n .e-cal-pick {\n display: inline-flex;\n align-items: center;\n gap: var(--e-space-1);\n height: var(--e-control-height);\n padding: 0 var(--e-space-2);\n border: 0;\n border-radius: var(--e-radius-md);\n background: transparent;\n color: var(--e-ink);\n font: 600 var(--e-text-lg) / 1 var(--e-font-sans);\n cursor: pointer;\n transition: background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-cal-pick:hover {\n background: var(--e-surface-hover);\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-border-strong);\n }\n\n .e-cal-pick:focus-visible {\n outline: var(--e-stroke-focus) solid var(--e-focus-ring);\n outline-offset: var(--e-focus-gap);\n }\n\n .e-cal-pick .e-icon {\n transition: transform var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-cal-pick[aria-expanded=\"true\"] .e-icon {\n transform: rotate(180deg);\n }\n\n .e-cal-range {\n font: 600 var(--e-text-lg) / 1.2 var(--e-font-sans);\n font-variant-numeric: tabular-nums;\n }\n\n .e-cal-gap {\n display: block;\n width: var(--e-tap);\n height: var(--e-tap);\n }\n\n .e-cal-head .e-icon-btn:disabled {\n color: var(--e-muted);\n cursor: not-allowed;\n }\n\n .e-cal-head .e-icon-btn:disabled:hover {\n background: transparent;\n box-shadow: none;\n }\n\n .e-cal-grid {\n width: 100%;\n height: calc(6 * var(--e-tap) + var(--e-space-8) + var(--e-space-4));\n border-collapse: collapse;\n table-layout: fixed;\n }\n\n .e-cal-grid th {\n height: var(--e-space-8);\n font: 600 var(--e-text-sm) / 1 var(--e-font-sans);\n color: var(--e-muted);\n text-align: center;\n }\n\n .e-cal-grid td {\n padding: 1px 3px;\n text-align: center;\n }\n\n .e-cal-in {\n background: color-mix(in srgb, var(--e-primary) 12%, var(--e-surface));\n }\n\n .e-day {\n position: relative;\n width: 100%;\n height: var(--e-tap);\n padding: 0;\n border: 0;\n border-radius: var(--e-radius-md);\n background: transparent;\n color: var(--e-ink);\n font: 500 var(--e-text-sm) / 1 var(--e-font-mono);\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n /* stylelint-disable-next-line selector-not-notation -- the selector stays in this form */\n .e-day:hover:not(:disabled):not(.e-day--sel) {\n background: var(--e-surface-hover);\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-border-strong);\n }\n\n .e-day: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 .e-day--out {\n color: var(--e-muted);\n font-weight: 400;\n }\n\n .e-day--today {\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-primary);\n }\n\n .e-day--sel {\n background: var(--e-primary);\n box-shadow: none;\n font-weight: 700;\n color: var(--e-on-primary);\n }\n\n .e-day:disabled {\n color: var(--e-border-strong);\n font-weight: 400;\n cursor: not-allowed;\n opacity: 1;\n }\n\n .e-day--mark::after {\n content: \"\";\n position: absolute;\n inset-inline-start: 50%;\n bottom: 5px;\n width: 5px;\n height: 5px;\n margin-inline-start: -2.5px;\n border-radius: 50%;\n background: var(--e-primary);\n }\n\n .e-day--sel.e-day--mark::after {\n background: var(--e-on-primary);\n }\n\n .e-cal-cells {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n grid-auto-rows: 1fr;\n gap: 6px;\n height: calc(6 * var(--e-tap) + var(--e-space-8) + var(--e-space-4));\n padding-top: var(--e-space-1);\n }\n\n .e-cal-years {\n overflow-y: auto;\n grid-auto-rows: var(--e-tap);\n padding-inline-end: 2px;\n align-content: start;\n }\n\n .e-cal-cell {\n width: 100%;\n height: 100%;\n min-height: var(--e-tap);\n padding: 0;\n border: 0;\n border-radius: var(--e-radius-md);\n background: transparent;\n color: var(--e-ink);\n font: 500 var(--e-text-md) / 1 var(--e-font-mono);\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n transition: background-color var(--e-duration-tap) var(--e-easing-out);\n }\n\n .e-cal-years .e-cal-cell {\n height: var(--e-tap);\n }\n\n /* stylelint-disable-next-line selector-not-notation -- the selector stays in this form */\n .e-cal-cell:hover:not(:disabled):not(.e-day--sel) {\n background: var(--e-surface-hover);\n box-shadow: inset 0 0 0 var(--e-stroke-edge) var(--e-border-strong);\n }\n\n .e-cal-cell: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 .e-cal-cell:disabled {\n color: var(--e-border-strong);\n font-weight: 400;\n cursor: not-allowed;\n }\n\n .e-cal-cell.e-day--sel {\n background: var(--e-primary);\n box-shadow: none;\n font-weight: 700;\n color: var(--e-on-primary);\n }\n\n .e-cal-help {\n min-height: calc(var(--e-text-sm) * 1.4);\n margin: var(--e-space-2) 0 0;\n font: 500 var(--e-text-sm) / 1.4 var(--e-font-sans);\n color: var(--e-muted);\n text-align: center;\n }\n\n .e-cal-foot {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: var(--e-space-2);\n margin-top: var(--e-space-2);\n padding-top: var(--e-space-2);\n border-top: var(--e-stroke-hair) solid var(--e-border);\n }\n\n .e-cal-foot--idle {\n visibility: hidden;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .e-day,\n .e-cal-pick,\n .e-cal-cell,\n .e-cal-pick .e-icon {\n transition: none;\n }\n }\n\n @media (forced-colors: active) {\n .e-day--sel,\n .e-cal-cell.e-day--sel {\n forced-color-adjust: none;\n background: Highlight;\n color: HighlightText;\n }\n\n .e-day--mark::after {\n background: CanvasText;\n }\n\n .e-day--sel.e-day--mark::after {\n background: HighlightText;\n }\n }\n}\n</style>\n"],"mappings":""}
@@ -9,7 +9,7 @@ type __VLS_Props = {
9
9
  disabledDate?: (date: Date) => boolean;
10
10
  /** Days that get a dot: a list of dates or a function. Screen readers hear `markLabel`. */
11
11
  marked?: Date[] | ((date: Date) => boolean);
12
- /** What screen readers hear on a marked day. @default times available */
12
+ /** What screen readers hear on a marked day. @default "times available" */
13
13
  markLabel?: string;
14
14
  /** The earliest day that can be chosen. Earlier days cannot be focused or chosen; navigation stops there. */
15
15
  min?: Date;