origam 2.17.1 → 2.18.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 (215) hide show
  1. package/CHANGELOG.md +895 -0
  2. package/dist/src/assets/css/main.css +1 -1
  3. package/dist/src/assets/css/tokens/dark.css +193 -26
  4. package/dist/src/assets/css/tokens/light.css +78 -11
  5. package/dist/src/assets/locales/en.json +21 -6
  6. package/dist/src/assets/locales/fr.json +21 -6
  7. package/dist/src/assets/scss/main.scss +10 -2
  8. package/dist/src/assets/scss/tokens/_dark.scss +2914 -13
  9. package/dist/src/assets/scss/tokens/_light.scss +78 -11
  10. package/dist/src/components/Alert/OrigamAlert.vue +6 -6
  11. package/dist/src/components/Avatar/OrigamAvatar.vue +15 -2
  12. package/dist/src/components/Badge/OrigamBadge.vue +7 -7
  13. package/dist/src/components/Breadcrumb/OrigamBreadcrumbItem.vue +23 -4
  14. package/dist/src/components/Btn/OrigamBtn.vue +22 -16
  15. package/dist/src/components/Btn/OrigamBtnGroup.vue +1 -1
  16. package/dist/src/components/Calendar/OrigamCalendar.vue +1 -1
  17. package/dist/src/components/Card/OrigamCard.vue +2 -0
  18. package/dist/src/components/Card/OrigamCardHeader.vue +7 -7
  19. package/dist/src/components/Carousel/OrigamCarousel.vue +14 -1
  20. package/dist/src/components/Chart/OrigamChartBoxPlot.vue +1 -1
  21. package/dist/src/components/Chart/OrigamChartBullet.vue +3 -2
  22. package/dist/src/components/Chart/OrigamChartCandlestick.vue +2 -2
  23. package/dist/src/components/Chart/OrigamChartCartesian.vue +49 -4
  24. package/dist/src/components/Chart/OrigamChartLegend.vue +39 -18
  25. package/dist/src/components/Chart/OrigamChartPareto.vue +7 -1
  26. package/dist/src/components/Chart/OrigamChartPictorial.vue +2 -2
  27. package/dist/src/components/Chart/OrigamChartRadar.vue +3 -1
  28. package/dist/src/components/Chart/OrigamChartSparkline.vue +3 -1
  29. package/dist/src/components/Chart/OrigamChartStreamgraph.vue +2 -1
  30. package/dist/src/components/Checkbox/OrigamCheckbox.vue +2 -0
  31. package/dist/src/components/Checkbox/OrigamCheckboxGroup.vue +36 -11
  32. package/dist/src/components/Chip/OrigamChip.vue +19 -4
  33. package/dist/src/components/Code/OrigamCode.vue +20 -3
  34. package/dist/src/components/ColorPickerField/OrigamColorPickerField.vue +30 -5
  35. package/dist/src/components/CommandPalette/OrigamCommandPalette.vue +3 -3
  36. package/dist/src/components/ConfirmWrapper/OrigamConfirmWrapper.vue +6 -6
  37. package/dist/src/components/ContextualMenu/OrigamContextualMenu.vue +0 -4
  38. package/dist/src/components/DataList/OrigamDataList.vue +2 -0
  39. package/dist/src/components/DataList/OrigamDataText.vue +6 -6
  40. package/dist/src/components/DataList/OrigamDataTitle.vue +6 -6
  41. package/dist/src/components/DataTable/OrigamDataTableHeaderCell.vue +1 -1
  42. package/dist/src/components/DataTable/OrigamDataTableHeadersCell.vue +4 -1
  43. package/dist/src/components/DatePicker/OrigamDatePicker.vue +2 -0
  44. package/dist/src/components/DatePicker/OrigamDatePickerHeader.vue +6 -6
  45. package/dist/src/components/DatePickerField/OrigamDatePickerField.vue +21 -1
  46. package/dist/src/components/Dialog/OrigamDialog.vue +25 -0
  47. package/dist/src/components/Dialog/OrigamDialogConfirmation.vue +6 -0
  48. package/dist/src/components/ExpansionPanel/OrigamExpansionPanel.vue +2 -0
  49. package/dist/src/components/ExpansionPanel/OrigamExpansionPanelHeader.vue +6 -6
  50. package/dist/src/components/Field/OrigamField.vue +47 -15
  51. package/dist/src/components/FileField/OrigamFileField.vue +5 -1
  52. package/dist/src/components/Icon/OrigamSvgIcon.vue +3 -1
  53. package/dist/src/components/Img/OrigamImg.vue +9 -2
  54. package/dist/src/components/InfiniteScroll/OrigamInfiniteScroll.vue +34 -18
  55. package/dist/src/components/InlineEdit/OrigamInlineEdit.vue +46 -5
  56. package/dist/src/components/Input/OrigamInput.vue +6 -6
  57. package/dist/src/components/List/OrigamListGroup.vue +4 -0
  58. package/dist/src/components/List/OrigamListItem.vue +68 -4
  59. package/dist/src/components/Masonry/OrigamMasonry.vue +18 -2
  60. package/dist/src/components/Menu/OrigamMenu.vue +79 -9
  61. package/dist/src/components/NumberField/OrigamNumberField.vue +13 -3
  62. package/dist/src/components/OtpInputField/OrigamOtpInputField.vue +35 -11
  63. package/dist/src/components/PasswordField/OrigamPasswordField.vue +5 -1
  64. package/dist/src/components/Radio/OrigamRadio.vue +2 -0
  65. package/dist/src/components/Radio/OrigamRadioGroup.vue +36 -11
  66. package/dist/src/components/RatingField/OrigamRatingField.vue +58 -7
  67. package/dist/src/components/RatingField/OrigamRatingFieldItem.vue +78 -30
  68. package/dist/src/components/Select/OrigamSelect.vue +44 -21
  69. package/dist/src/components/SliderField/OrigamSliderField.vue +20 -10
  70. package/dist/src/components/Snackbar/OrigamSnackbarGroup.vue +1 -1
  71. package/dist/src/components/Switch/OrigamSwitch.vue +2 -0
  72. package/dist/src/components/Tabs/OrigamTab.vue +7 -4
  73. package/dist/src/components/Tabs/OrigamTabPanel.vue +4 -2
  74. package/dist/src/components/Tabs/OrigamTabs.vue +7 -5
  75. package/dist/src/components/TextField/OrigamTextField.vue +5 -1
  76. package/dist/src/components/TextareaField/OrigamTextareaField.vue +5 -1
  77. package/dist/src/components/Transition/OrigamExpandX.vue +19 -3
  78. package/dist/src/components/Transition/OrigamExpandY.vue +19 -3
  79. package/dist/src/components/Transition/OrigamTranslateScale.vue +26 -4
  80. package/dist/src/components/Video/OrigamVideo.vue +3 -2
  81. package/dist/src/components/Window/OrigamWindow.vue +20 -3
  82. package/dist/src/composables/Commons/accessibleCommand.composable.cjs +26 -0
  83. package/dist/src/composables/Commons/accessibleCommand.composable.d.ts +78 -0
  84. package/dist/src/composables/Commons/accessibleCommand.composable.js +20 -0
  85. package/dist/src/composables/Commons/activator.composable.cjs +10 -1
  86. package/dist/src/composables/Commons/activator.composable.js +11 -2
  87. package/dist/src/composables/Commons/adjacent.composable.cjs +17 -0
  88. package/dist/src/composables/Commons/adjacent.composable.d.ts +12 -0
  89. package/dist/src/composables/Commons/adjacent.composable.js +17 -0
  90. package/dist/src/composables/Commons/adjacentInner.composable.cjs +20 -0
  91. package/dist/src/composables/Commons/adjacentInner.composable.d.ts +24 -5
  92. package/dist/src/composables/Commons/adjacentInner.composable.js +20 -0
  93. package/dist/src/composables/Commons/audio.composable.cjs +14 -1
  94. package/dist/src/composables/Commons/audio.composable.js +14 -1
  95. package/dist/src/composables/Commons/backButton.composable.cjs +3 -1
  96. package/dist/src/composables/Commons/backButton.composable.js +3 -1
  97. package/dist/src/composables/Commons/border.composable.d.ts +13 -0
  98. package/dist/src/composables/Commons/colorEffect.composable.cjs +58 -46
  99. package/dist/src/composables/Commons/colorEffect.composable.d.ts +10 -5
  100. package/dist/src/composables/Commons/colorEffect.composable.js +70 -46
  101. package/dist/src/composables/Commons/createLayout.composable.cjs +21 -12
  102. package/dist/src/composables/Commons/createLayout.composable.js +21 -12
  103. package/dist/src/composables/Commons/delay.composable.d.ts +16 -0
  104. package/dist/src/composables/Commons/dimension.composable.d.ts +11 -0
  105. package/dist/src/composables/Commons/elevation.composable.cjs +6 -2
  106. package/dist/src/composables/Commons/elevation.composable.d.ts +37 -1
  107. package/dist/src/composables/Commons/elevation.composable.js +7 -2
  108. package/dist/src/composables/Commons/goTo.composable.cjs +4 -2
  109. package/dist/src/composables/Commons/goTo.composable.js +5 -3
  110. package/dist/src/composables/Commons/group.composable.cjs +14 -14
  111. package/dist/src/composables/Commons/group.composable.js +14 -14
  112. package/dist/src/composables/Commons/hotkey.composable.d.ts +18 -7
  113. package/dist/src/composables/Commons/hydration.composable.d.ts +8 -0
  114. package/dist/src/composables/Commons/link.composable.d.ts +20 -0
  115. package/dist/src/composables/Commons/locationStrategies.composable.d.ts +17 -0
  116. package/dist/src/composables/Commons/message.composable.d.ts +19 -5
  117. package/dist/src/composables/Commons/position.composable.d.ts +17 -6
  118. package/dist/src/composables/Commons/refs.composable.d.ts +11 -5
  119. package/dist/src/composables/Commons/rounded.composable.d.ts +11 -1
  120. package/dist/src/composables/Commons/scrolling.composable.cjs +15 -12
  121. package/dist/src/composables/Commons/scrolling.composable.js +15 -12
  122. package/dist/src/composables/Commons/size.composable.d.ts +15 -0
  123. package/dist/src/composables/Commons/ssrBoot.composable.cjs +9 -1
  124. package/dist/src/composables/Commons/ssrBoot.composable.js +10 -2
  125. package/dist/src/composables/Commons/stack.composable.cjs +13 -1
  126. package/dist/src/composables/Commons/stack.composable.js +13 -1
  127. package/dist/src/composables/Commons/theme-props-resolver.composable.cjs +41 -32
  128. package/dist/src/composables/Commons/theme-props-resolver.composable.js +41 -32
  129. package/dist/src/composables/Commons/validation.composable.cjs +3 -3
  130. package/dist/src/composables/Commons/validation.composable.js +3 -3
  131. package/dist/src/composables/Commons/virtual.composable.cjs +24 -8
  132. package/dist/src/composables/Commons/virtual.composable.js +24 -8
  133. package/dist/src/composables/Masonry/masonry.composable.cjs +18 -11
  134. package/dist/src/composables/Masonry/masonry.composable.js +18 -11
  135. package/dist/src/composables/Parallax/parallax.composable.cjs +1 -1
  136. package/dist/src/composables/Parallax/parallax.composable.js +1 -1
  137. package/dist/src/composables/index.cjs +36 -0
  138. package/dist/src/composables/index.d.ts +3 -0
  139. package/dist/src/composables/index.js +3 -0
  140. package/dist/src/consts/Chart/chart-cartesian.const.cjs +5 -2
  141. package/dist/src/consts/Chart/chart-cartesian.const.d.ts +42 -0
  142. package/dist/src/consts/Chart/chart-cartesian.const.js +3 -0
  143. package/dist/src/consts/Commons/elevation.const.cjs +5 -1
  144. package/dist/src/consts/Commons/elevation.const.d.ts +52 -2
  145. package/dist/src/consts/Commons/elevation.const.js +4 -0
  146. package/dist/src/consts/Commons/ripple.const.cjs +13 -3
  147. package/dist/src/consts/Commons/ripple.const.js +13 -3
  148. package/dist/src/consts/RatingField/rating-field.const.cjs +10 -0
  149. package/dist/src/consts/RatingField/rating-field.const.d.ts +36 -0
  150. package/dist/src/consts/RatingField/rating-field.const.js +12 -0
  151. package/dist/src/consts/index.cjs +11 -0
  152. package/dist/src/consts/index.d.ts +1 -0
  153. package/dist/src/consts/index.js +1 -0
  154. package/dist/src/directives/ClickOutside/clickOutside.directive.cjs +2 -0
  155. package/dist/src/directives/ClickOutside/clickOutside.directive.js +2 -0
  156. package/dist/src/directives/Ripple/ripple.directive.cjs +2 -0
  157. package/dist/src/directives/Ripple/ripple.directive.js +2 -0
  158. package/dist/src/enums/Commons/color.enum.cjs +0 -1
  159. package/dist/src/enums/Commons/color.enum.d.ts +14 -5
  160. package/dist/src/enums/Commons/color.enum.js +0 -1
  161. package/dist/src/enums/Sheet/sheet.enum.d.ts +1 -1
  162. package/dist/src/interfaces/Btn/btn.interface.d.ts +7 -10
  163. package/dist/src/interfaces/Chart/chart-cartesian.interface.d.ts +6 -2
  164. package/dist/src/interfaces/Commons/activator.interface.d.ts +3 -2
  165. package/dist/src/interfaces/Commons/adjacent.interface.d.ts +29 -0
  166. package/dist/src/interfaces/Commons/group.interface.d.ts +13 -2
  167. package/dist/src/interfaces/Commons/ripple.interface.d.ts +16 -0
  168. package/dist/src/interfaces/Commons/scroll.interface.d.ts +3 -2
  169. package/dist/src/interfaces/DataTable/data-table-header.interface.d.ts +2 -2
  170. package/dist/src/interfaces/DatePicker/date-picker-month.interface.d.ts +2 -1
  171. package/dist/src/interfaces/Menu/menu.interface.d.ts +28 -1
  172. package/dist/src/interfaces/OtpInputField/otp-input-field.interface.d.ts +21 -1
  173. package/dist/src/interfaces/RatingField/rating-field-item.interface.d.ts +16 -1
  174. package/dist/src/interfaces/index.cjs +11 -0
  175. package/dist/src/interfaces/index.d.ts +1 -0
  176. package/dist/src/interfaces/index.js +1 -0
  177. package/dist/src/nuxt/module.cjs +2 -1
  178. package/dist/src/nuxt/module.js +2 -1
  179. package/dist/src/origam.cjs +1 -2
  180. package/dist/src/origam.js +1 -2
  181. package/dist/src/themes/origam.theme.cjs +8 -14
  182. package/dist/src/themes/origam.theme.js +6 -8
  183. package/dist/src/types/Commons/color.type.d.ts +4 -3
  184. package/dist/src/types/Commons/commons.type.d.ts +33 -0
  185. package/dist/src/types/Commons/theme.type.d.ts +2 -1
  186. package/dist/src/types/Sheet/sheet.type.d.ts +2 -1
  187. package/dist/src/types/index.cjs +22 -0
  188. package/dist/src/types/index.d.ts +2 -0
  189. package/dist/src/types/index.js +2 -0
  190. package/dist/src/types/tokens.type.d.ts +1 -1
  191. package/dist/src/utils/Commons/a11y.util.cjs +35 -0
  192. package/dist/src/utils/Commons/a11y.util.d.ts +63 -0
  193. package/dist/src/utils/Commons/a11y.util.js +33 -0
  194. package/dist/src/utils/Commons/clickOutside.util.cjs +5 -1
  195. package/dist/src/utils/Commons/clickOutside.util.js +5 -1
  196. package/dist/src/utils/Commons/color.util.cjs +10 -15
  197. package/dist/src/utils/Commons/color.util.d.ts +34 -28
  198. package/dist/src/utils/Commons/color.util.js +9 -16
  199. package/dist/src/utils/Commons/goTo.util.cjs +31 -14
  200. package/dist/src/utils/Commons/goTo.util.d.ts +1 -1
  201. package/dist/src/utils/Commons/goTo.util.js +31 -16
  202. package/dist/src/utils/Commons/location.util.cjs +18 -3
  203. package/dist/src/utils/Commons/location.util.js +18 -3
  204. package/dist/src/utils/Commons/ripple.util.cjs +5 -1
  205. package/dist/src/utils/Commons/ripple.util.js +5 -1
  206. package/dist/src/utils/index.cjs +11 -0
  207. package/dist/src/utils/index.d.ts +1 -0
  208. package/dist/src/utils/index.js +1 -0
  209. package/package.json +13 -2
  210. package/dist/src/consts/Btn/btn.const.cjs +0 -7
  211. package/dist/src/consts/Btn/btn.const.d.ts +0 -32
  212. package/dist/src/consts/Btn/btn.const.js +0 -1
  213. package/dist/src/types/Commons/locale.type.cjs +0 -1
  214. package/dist/src/types/Commons/locale.type.d.ts +0 -0
  215. package/dist/src/types/Commons/locale.type.js +0 -0
@@ -27,6 +27,7 @@
27
27
  import { computed, inject, ref, StyleValue, watchEffect } from "vue";
28
28
  import { useGroupItem } from "../../composables/Commons/groupItem.composable";
29
29
  import { useLazy } from "../../composables/Commons/lazy.composable";
30
+ import { getUid } from "../../utils/Commons/getCurrentInstance.util";
30
31
  import { useProps } from "../../composables/Commons/props.composable";
31
32
  import { useStyle } from "../../composables/Commons/style.composable";
32
33
  import {
@@ -54,7 +55,8 @@ const panelsCtx = inject(ORIGAM_TAB_PANELS_CTX_KEY, null);
54
55
  if (!groupItem) {
55
56
  throw new Error("[Origam] <OrigamTabPanel> must be used inside an <OrigamTabPanels>");
56
57
  }
57
- const panelDomId = computed(() => props.id || `origam-tab-panel-${groupItem.id}`);
58
+ const uid = getUid();
59
+ const panelDomId = computed(() => props.id || `origam-tab-panel-${uid}`);
58
60
  watchEffect(() => {
59
61
  const self = groupItem.group.items.value.find((item) => item.id === groupItem.id);
60
62
  if (self) self.domId = panelDomId.value;
@@ -64,7 +66,7 @@ const tabLabelledBy = computed(() => {
64
66
  if (!tabsGroup) return void 0;
65
67
  const tab = tabsGroup.items.value.find((item) => item.value === groupItem.value.value);
66
68
  if (!tab) return void 0;
67
- return tab.domId || `origam-tab-${tab.id}`;
69
+ return tab.domId;
68
70
  });
69
71
  const isShown = computed(() => groupItem.isSelected.value);
70
72
  const { hasContent } = useLazy({ eager: !!props.eager }, isShown);
@@ -85,7 +85,9 @@ const slotDefaults = computed(() => ({
85
85
  const ariaOrientation = computed(() => props.direction === DIRECTION.VERTICAL ? "vertical" : "horizontal");
86
86
  const focusTab = (id2) => {
87
87
  if (!rootRef.value) return;
88
- const target = rootRef.value.querySelector(`[data-origam-tab-id="${id2}"]`);
88
+ const domId = items.value.find((item) => item.id === id2)?.domId;
89
+ if (!domId) return;
90
+ const target = rootRef.value.querySelector(`[id=${JSON.stringify(domId)}]`);
89
91
  target?.focus();
90
92
  };
91
93
  const focusFirstNonDisabled = (offset) => {
@@ -109,12 +111,12 @@ const handleKeydown = (event) => {
109
111
  const currentId = selected.value[0];
110
112
  if (event.key === prevKey) {
111
113
  event.preventDefault();
112
- prev();
113
- if (selected.value[0] != null) focusTab(selected.value[0]);
114
+ const movedTo = prev();
115
+ if (movedTo != null) focusTab(movedTo);
114
116
  } else if (event.key === nextKey) {
115
117
  event.preventDefault();
116
- next();
117
- if (selected.value[0] != null) focusTab(selected.value[0]);
118
+ const movedTo = next();
119
+ if (movedTo != null) focusTab(movedTo);
118
120
  } else if (event.key === "Home") {
119
121
  event.preventDefault();
120
122
  focusFirstNonDisabled(1);
@@ -245,6 +245,8 @@ const props = defineProps({
245
245
  prependInnerIcon: { type: null, required: false },
246
246
  clearIcon: { type: null, required: false, default: MDI_ICONS.CLOSE_CIRCLE_OUTLINE },
247
247
  clearable: { type: Boolean, required: false },
248
+ prependInnerAriaLabel: { type: String, required: false },
249
+ appendInnerAriaLabel: { type: String, required: false },
248
250
  border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
249
251
  borderTop: { type: [Boolean, Number, String], required: false },
250
252
  borderLeft: { type: [Boolean, Number, String], required: false },
@@ -312,7 +314,9 @@ const props = defineProps({
312
314
  appendAvatar: { type: String, required: false },
313
315
  appendIcon: { type: null, required: false },
314
316
  prependAvatar: { type: String, required: false },
315
- prependIcon: { type: null, required: false }
317
+ prependIcon: { type: null, required: false },
318
+ prependAriaLabel: { type: String, required: false },
319
+ appendAriaLabel: { type: String, required: false }
316
320
  });
317
321
  const emits = defineEmits(["click:control", "mousedown:control", "valid", "complete", "update:focused", "click:appendInner", "click:prependInner", "click:clear", "update:modelValue", "click:append", "click:prepend"]);
318
322
  defineSlots();
@@ -332,6 +332,8 @@ const props = defineProps({
332
332
  prependInnerIcon: { type: null, required: false },
333
333
  clearIcon: { type: null, required: false, default: MDI_ICONS.CLOSE_CIRCLE_OUTLINE },
334
334
  clearable: { type: Boolean, required: false },
335
+ prependInnerAriaLabel: { type: String, required: false },
336
+ appendInnerAriaLabel: { type: String, required: false },
335
337
  border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true },
336
338
  borderTop: { type: [Boolean, Number, String], required: false },
337
339
  borderLeft: { type: [Boolean, Number, String], required: false },
@@ -399,7 +401,9 @@ const props = defineProps({
399
401
  appendAvatar: { type: String, required: false },
400
402
  appendIcon: { type: null, required: false },
401
403
  prependAvatar: { type: String, required: false },
402
- prependIcon: { type: null, required: false }
404
+ prependIcon: { type: null, required: false },
405
+ prependAriaLabel: { type: String, required: false },
406
+ appendAriaLabel: { type: String, required: false }
403
407
  });
404
408
  const emits = defineEmits(["update:height", "click:control", "mousedown:control", "format", "update:focused", "click:appendInner", "click:prependInner", "click:clear", "update:modelValue", "click:append", "click:prepend"]);
405
409
  defineSlots();
@@ -15,7 +15,7 @@
15
15
  </template>
16
16
 
17
17
  <script lang="ts" setup>
18
- import { camelize, computed, Transition, TransitionGroup } from "vue";
18
+ import { camelize, computed, onBeforeUnmount, Transition, TransitionGroup } from "vue";
19
19
  import { useProps } from "../../composables/Commons/props.composable";
20
20
  import { TRANSITION_MODE } from "../../enums/Transition/transition.enum";
21
21
  const props = defineProps({
@@ -29,6 +29,22 @@ const props = defineProps({
29
29
  const { filterProps } = useProps(props);
30
30
  defineEmits([]);
31
31
  defineSlots();
32
+ let disposed = false;
33
+ const frames = /* @__PURE__ */ new Set();
34
+ const scheduleFrame = (cb) => {
35
+ if (disposed) return;
36
+ const id = requestAnimationFrame(() => {
37
+ frames.delete(id);
38
+ if (disposed) return;
39
+ cb();
40
+ });
41
+ frames.add(id);
42
+ };
43
+ onBeforeUnmount(() => {
44
+ disposed = true;
45
+ for (const id of frames) cancelAnimationFrame(id);
46
+ frames.clear();
47
+ });
32
48
  const tag = computed(() => props.group ? TransitionGroup : Transition);
33
49
  const rootProps = computed(() => {
34
50
  const bind = {
@@ -88,7 +104,7 @@ const handleEnter = (el) => {
88
104
  if (expandedParentClass && element._parent) {
89
105
  element._parent.classList.add(expandedParentClass);
90
106
  }
91
- requestAnimationFrame(() => {
107
+ scheduleFrame(() => {
92
108
  element.style[sizeProperty] = offset;
93
109
  });
94
110
  };
@@ -128,7 +144,7 @@ const handleLeave = (el) => {
128
144
  if (props.hideOnLeave) {
129
145
  element.style.setProperty("display", "none", "important");
130
146
  } else {
131
- requestAnimationFrame(() => element.style[sizeProperty] = "0");
147
+ scheduleFrame(() => element.style[sizeProperty] = "0");
132
148
  }
133
149
  };
134
150
  const handleAfterLeave = (el) => {
@@ -15,7 +15,7 @@
15
15
  </template>
16
16
 
17
17
  <script lang="ts" setup>
18
- import { camelize, computed, Transition, TransitionGroup } from "vue";
18
+ import { camelize, computed, onBeforeUnmount, Transition, TransitionGroup } from "vue";
19
19
  import { useProps } from "../../composables/Commons/props.composable";
20
20
  import { TRANSITION_MODE } from "../../enums/Transition/transition.enum";
21
21
  const props = defineProps({
@@ -29,6 +29,22 @@ const props = defineProps({
29
29
  const { filterProps } = useProps(props);
30
30
  defineEmits([]);
31
31
  defineSlots();
32
+ let disposed = false;
33
+ const frames = /* @__PURE__ */ new Set();
34
+ const scheduleFrame = (cb) => {
35
+ if (disposed) return;
36
+ const id = requestAnimationFrame(() => {
37
+ frames.delete(id);
38
+ if (disposed) return;
39
+ cb();
40
+ });
41
+ frames.add(id);
42
+ };
43
+ onBeforeUnmount(() => {
44
+ disposed = true;
45
+ for (const id of frames) cancelAnimationFrame(id);
46
+ frames.clear();
47
+ });
32
48
  const tag = computed(() => props.group ? TransitionGroup : Transition);
33
49
  const rootProps = computed(() => {
34
50
  const bind = {
@@ -88,7 +104,7 @@ const handleEnter = (el) => {
88
104
  if (expandedParentClass && element._parent) {
89
105
  element._parent.classList.add(expandedParentClass);
90
106
  }
91
- requestAnimationFrame(() => {
107
+ scheduleFrame(() => {
92
108
  element.style[sizeProperty] = offset;
93
109
  });
94
110
  };
@@ -128,7 +144,7 @@ const handleLeave = (el) => {
128
144
  if (props.hideOnLeave) {
129
145
  element.style.setProperty("display", "none", "important");
130
146
  } else {
131
- requestAnimationFrame(() => element.style[sizeProperty] = "0");
147
+ scheduleFrame(() => element.style[sizeProperty] = "0");
132
148
  }
133
149
  };
134
150
  const handleAfterLeave = (el) => {
@@ -8,7 +8,7 @@
8
8
  </template>
9
9
 
10
10
  <script lang="ts" setup>
11
- import { computed } from "vue";
11
+ import { computed, onBeforeUnmount } from "vue";
12
12
  import { useProps } from "../../composables/Commons/props.composable";
13
13
  import { EASING } from "../../enums/Transition/transition.enum";
14
14
  import { animate } from "../../utils/Commons/animation.util";
@@ -22,6 +22,26 @@ const props = defineProps({
22
22
  const { filterProps } = useProps(props);
23
23
  defineEmits([]);
24
24
  defineSlots();
25
+ let disposed = false;
26
+ const frames = /* @__PURE__ */ new Set();
27
+ const pending = /* @__PURE__ */ new Set();
28
+ const nextFrame = () => new Promise((resolve) => {
29
+ if (disposed) return resolve();
30
+ pending.add(resolve);
31
+ const id = requestAnimationFrame(() => {
32
+ frames.delete(id);
33
+ pending.delete(resolve);
34
+ resolve();
35
+ });
36
+ frames.add(id);
37
+ });
38
+ onBeforeUnmount(() => {
39
+ disposed = true;
40
+ for (const id of frames) cancelAnimationFrame(id);
41
+ frames.clear();
42
+ for (const resolve of pending) resolve();
43
+ pending.clear();
44
+ });
25
45
  const hasTarget = computed(() => {
26
46
  return !!props.target;
27
47
  });
@@ -36,8 +56,9 @@ const handleBeforeEnter = (el) => {
36
56
  el.style.visibility = "hidden";
37
57
  };
38
58
  const handleEnter = async (el, done) => {
39
- await new Promise((resolve) => requestAnimationFrame(resolve));
40
- await new Promise((resolve) => requestAnimationFrame(resolve));
59
+ await nextFrame();
60
+ await nextFrame();
61
+ if (disposed) return;
41
62
  el.style.visibility = "";
42
63
  const { x, y, sx, sy, speed } = getDimensions(props.target, el);
43
64
  const animation = animate(el, [
@@ -67,7 +88,8 @@ const handleBeforeLeave = (el) => {
67
88
  el.style.pointerEvents = "none";
68
89
  };
69
90
  const handleLeave = async (el, done) => {
70
- await new Promise((resolve) => requestAnimationFrame(resolve));
91
+ await nextFrame();
92
+ if (disposed) return;
71
93
  const { x, y, sx, sy, speed } = getDimensions(props.target, el);
72
94
  const animation = animate(el, [
73
95
  {},
@@ -576,11 +576,12 @@ const pipSupported = computed(() => {
576
576
  const showPosterOverlay = computed(() => {
577
577
  return Boolean(props.poster) && state.paused.value && state.currentTime.value === 0 && !state.error.value;
578
578
  });
579
+ const genericErrorMessage = computed(() => t("origam.media.playback_error"));
579
580
  const errorMessage = computed(() => {
580
581
  const err = state.error.value;
581
- if (!err) return "Playback error";
582
+ if (!err) return genericErrorMessage.value;
582
583
  if ("message" in err && err.message) return err.message;
583
- return "Playback error";
584
+ return genericErrorMessage.value;
584
585
  });
585
586
  const captionsLabelKey = computed(() => {
586
587
  return captionsEnabled.value ? "origam.video.disable_captions" : "origam.video.enable_captions";
@@ -6,8 +6,7 @@
6
6
  v-touch="touchOptions"
7
7
  :class="windowClasses"
8
8
  :style="windowStyles"
9
- aria-roledescription="carousel"
10
- role="region"
9
+ v-bind="landmarkAttrs"
11
10
  >
12
11
  <p
13
12
  class="origam-window__live-region"
@@ -78,7 +77,7 @@
78
77
  </template>
79
78
 
80
79
  <script lang="ts" setup>
81
- import { computed, provide, ref, shallowRef, StyleValue, watch } from "vue";
80
+ import { computed, provide, ref, shallowRef, StyleValue, useAttrs, watch } from "vue";
82
81
  import OrigamBtn from "../Btn/OrigamBtn.vue";
83
82
  import OrigamSpacer from "../Grids/OrigamSpacer.vue";
84
83
  import { useBorder } from "../../composables/Commons/border.composable";
@@ -91,6 +90,7 @@ import { useProps } from "../../composables/Commons/props.composable";
91
90
  import { useRounded } from "../../composables/Commons/rounded.composable";
92
91
  import { useStyle } from "../../composables/Commons/style.composable";
93
92
  import { ORIGAM_WINDOW_GROUP_KEY, ORIGAM_WINDOW_KEY } from "../../consts/Window/window.const";
93
+ import { warnMissingLandmarkName } from "../../utils/Commons/a11y.util";
94
94
  import vTouch from "../../directives/Touch/touch.directive";
95
95
  import { AXIS } from "../../enums/Commons/drag.enum";
96
96
  import { DIRECTION } from "../../enums/Commons/direction.enum";
@@ -154,6 +154,23 @@ defineEmits(["update:modelValue"]);
154
154
  defineSlots();
155
155
  const { filterProps } = useProps(props);
156
156
  const { t } = useLocale();
157
+ const attrs = useAttrs();
158
+ const hasAccessibleName = computed(() => {
159
+ const label = attrs["aria-label"];
160
+ const labelledBy = attrs["aria-labelledby"];
161
+ return !!(typeof label === "string" ? label.trim() : label) || !!(typeof labelledBy === "string" ? labelledBy.trim() : labelledBy);
162
+ });
163
+ const landmarkAttrs = computed(() => {
164
+ const roleDescription = t("origam.carousel.role_description");
165
+ const attributes = {};
166
+ if (!hasAccessibleName.value) {
167
+ warnMissingLandmarkName("OrigamWindow", "region", roleDescription);
168
+ return attributes;
169
+ }
170
+ attributes.role = "region";
171
+ attributes["aria-roledescription"] = roleDescription;
172
+ return attributes;
173
+ });
157
174
  const group = useGroup(props, ORIGAM_WINDOW_GROUP_KEY);
158
175
  const rootRef = ref();
159
176
  const isReversed = shallowRef(false);
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useAccessibleCommand = useAccessibleCommand;
7
+ var _vue = require("vue");
8
+ var _locale = require("./locale.composable.cjs");
9
+ var _a11y = require("../../utils/Commons/a11y.util.cjs");
10
+ function useAccessibleCommand(options) {
11
+ const locale = (0, _locale.useLocale)(false);
12
+ return (0, _vue.computed)(() => {
13
+ if (!options.active.value) return {};
14
+ const raw = options.label();
15
+ const name = raw ? locale ? locale.t(raw) : raw : "";
16
+ if (!name) {
17
+ (0, _a11y.warnMissingAccessibleName)(options.component, options.zone, options.prop);
18
+ return {};
19
+ }
20
+ return {
21
+ role: "button",
22
+ tabindex: 0,
23
+ "aria-label": name
24
+ };
25
+ });
26
+ }
@@ -0,0 +1,78 @@
1
+ import type { ComputedRef, Ref } from 'vue';
2
+ /*********************************************************
3
+ * useAccessibleCommand
4
+ *
5
+ * @description
6
+ * ⛔ issues #747 / #653 / #660 — the ONE place the design system decides
7
+ * whether a non-native element may claim `role="button"`.
8
+ *
9
+ * The three tickets are three readings of the same defect: the DS puts an
10
+ * ARIA claim on an element it has no name for. `useAdjacent` /
11
+ * `useAdjacentInner` promote the prepend/append zone to `role="button"` +
12
+ * `tabindex="0"` the moment a consumer attaches `click:prepend` /
13
+ * `click:append` (#443) — but neither hook, nor any of the 13 templates
14
+ * that bind them, ever had a channel through which a name could arrive.
15
+ * Measured against axe-core in Chromium, that produced **54
16
+ * `aria-command-name` nodes (impact `serious`, WCAG 2.1 4.1.2 level A)
17
+ * across 17 components** on untouched `develop`, every one of them
18
+ * announced to a screen reader as "button" and nothing else.
19
+ *
20
+ * @description
21
+ * **The rule this hook encodes: the DS never emits an ARIA role it cannot
22
+ * name, and it never invents the name.**
23
+ *
24
+ * - A name IS available → `role="button"` + `tabindex="0"` + `aria-label`.
25
+ * The zone is a real, reachable, announceable control.
26
+ * - No name → the returned object is EMPTY: no role, no tab stop. The
27
+ * `@click` listener the template binds is untouched and still fires on
28
+ * mouse, exactly as it did before #443 added the role; what disappears is
29
+ * the false claim, not a working feature. A dev-only warning names the
30
+ * prop to add.
31
+ *
32
+ * @description
33
+ * ⛔ The rejected third option was to keep the role and fabricate a
34
+ * default label ("Prepend action", or an i18n key resolving to it). It
35
+ * would silence axe while telling a screen-reader user strictly nothing
36
+ * about what the control does — the failure mode #622 already shipped
37
+ * once (an auto-label that overwrote a visible `<label for>`), and the
38
+ * reason #653 chose a warning over a fabricated string on the icon family.
39
+ * "No ARIA is better than bad ARIA" is the same principle
40
+ * `useIconAccessibility` applies when it refuses to announce a glyph as a
41
+ * control it cannot operate.
42
+ *
43
+ * @description
44
+ * ⛔ A NATIVE control cannot use this escape hatch — a `<button>` is a
45
+ * button whether or not anyone named it. `OrigamBtn`'s icon-only mode
46
+ * therefore keeps rendering its `<button>` and only warns; see
47
+ * `warnMissingAccessibleName` and `OrigamBtn.vue`.
48
+ *
49
+ * @description
50
+ * `label` is resolved through `useLocale().t`, matching the existing
51
+ * `closeLabel` contract on Alert / Chip / Dialog: an i18n key resolves,
52
+ * and any other string is returned verbatim by the builtin adapter — so
53
+ * a consumer may pass either. `useLocale(false)` (non-strict) is used on
54
+ * purpose: this hook runs inside 13 components, several of which are
55
+ * mounted in unit tests without `createOrigam()` installed, and a strict
56
+ * `useLocale()` would throw there.
57
+ *
58
+ * @description
59
+ * ADR-005: the label is read INSIDE the returned `computed`, never in the
60
+ * `setup()` body, so a value coming from a theme's `components` block is
61
+ * seen at render time rather than snapshotted too early.
62
+ *
63
+ * @description
64
+ * OPTIONS. `component` and `zone` name the offender in the dev warning
65
+ * (`OrigamCardHeader` / `prepend`); `prop` names the prop that fixes it
66
+ * (`prependAriaLabel`). `active` is true when the zone is meant to behave as
67
+ * a command — raw clickability for most consumers, clickability AND
68
+ * not-a-link for the three `useLink` ones, whose `<a>` root forbids a
69
+ * descendant tab stop. `label` is a GETTER, not a value, precisely so the
70
+ * read stays inside the computed.
71
+ ********************************************************/
72
+ export declare function useAccessibleCommand(options: {
73
+ component: string;
74
+ zone: string;
75
+ prop: string;
76
+ active: Ref<boolean> | ComputedRef<boolean>;
77
+ label: () => string | undefined;
78
+ }): ComputedRef<Record<string, unknown>>;
@@ -0,0 +1,20 @@
1
+ import { computed } from "vue";
2
+ import { useLocale } from "./locale.composable.js";
3
+ import { warnMissingAccessibleName } from "../../utils/Commons/a11y.util.js";
4
+ export function useAccessibleCommand(options) {
5
+ const locale = useLocale(false);
6
+ return computed(() => {
7
+ if (!options.active.value) return {};
8
+ const raw = options.label();
9
+ const name = raw ? locale ? locale.t(raw) : raw : "";
10
+ if (!name) {
11
+ warnMissingAccessibleName(options.component, options.zone, options.prop);
12
+ return {};
13
+ }
14
+ return {
15
+ role: "button",
16
+ tabindex: 0,
17
+ "aria-label": name
18
+ };
19
+ });
20
+ }
@@ -158,15 +158,24 @@ function useActivator(props, {
158
158
  isActive.value = false;
159
159
  }
160
160
  });
161
+ let cursorResetTimer;
161
162
  (0, _vue.watch)(isActive, val => {
162
163
  if (!val) {
163
- setTimeout(() => {
164
+ clearTimeout(cursorResetTimer);
165
+ cursorResetTimer = setTimeout(() => {
166
+ cursorResetTimer = void 0;
164
167
  cursorTarget.value = void 0;
165
168
  });
166
169
  }
167
170
  }, {
168
171
  flush: "post"
169
172
  });
173
+ (0, _commons2.tryOnScopeDispose)(() => {
174
+ if (cursorResetTimer !== void 0) {
175
+ clearTimeout(cursorResetTimer);
176
+ cursorResetTimer = void 0;
177
+ }
178
+ });
170
179
  const activatorRef = (0, _vue.ref)();
171
180
  (0, _vue.watchEffect)(() => {
172
181
  if (!activatorRef.value) return;
@@ -3,7 +3,7 @@ import { useDelay } from "./delay.composable.js";
3
3
  import { IN_BROWSER } from "../../consts/Commons/commons.const.js";
4
4
  import { ORIGAM_MENU_KEY } from "../../consts/Menu/menu.const.js";
5
5
  import { activator, getTargetActivator } from "../../utils/Commons/activator.util.js";
6
- import { matchesSelector, refElement } from "../../utils/Commons/commons.util.js";
6
+ import { matchesSelector, refElement, tryOnScopeDispose } from "../../utils/Commons/commons.util.js";
7
7
  import { getCurrentInstance } from "../../utils/Commons/getCurrentInstance.util.js";
8
8
  export function useActivator(props, { isActive, isTop }) {
9
9
  const vm = getCurrentInstance("useActivator");
@@ -146,13 +146,22 @@ export function useActivator(props, { isActive, isTop }) {
146
146
  isActive.value = false;
147
147
  }
148
148
  });
149
+ let cursorResetTimer;
149
150
  watch(isActive, (val) => {
150
151
  if (!val) {
151
- setTimeout(() => {
152
+ clearTimeout(cursorResetTimer);
153
+ cursorResetTimer = setTimeout(() => {
154
+ cursorResetTimer = void 0;
152
155
  cursorTarget.value = void 0;
153
156
  });
154
157
  }
155
158
  }, { flush: "post" });
159
+ tryOnScopeDispose(() => {
160
+ if (cursorResetTimer !== void 0) {
161
+ clearTimeout(cursorResetTimer);
162
+ cursorResetTimer = void 0;
163
+ }
164
+ });
156
165
  const activatorRef = ref();
157
166
  watchEffect(() => {
158
167
  if (!activatorRef.value) return;
@@ -7,6 +7,7 @@ exports.useAdjacent = useAdjacent;
7
7
  var _vue = require("vue");
8
8
  var _hotkey = require("../../enums/Commons/hotkey.enum.cjs");
9
9
  var _commons = require("../../utils/Commons/commons.util.cjs");
10
+ var _accessibleCommand = require("./accessibleCommand.composable.cjs");
10
11
  var _getCurrentInstance = require("../../utils/Commons/getCurrentInstance.util.cjs");
11
12
  function useAdjacent(props, prependIcon, appendIcon) {
12
13
  const vm = (0, _getCurrentInstance.getCurrentInstance)("OrigamAdjacent");
@@ -49,7 +50,23 @@ function useAdjacent(props, prependIcon, appendIcon) {
49
50
  e.preventDefault();
50
51
  onClickAppend(e);
51
52
  };
53
+ const prependCommandAttrs = (0, _accessibleCommand.useAccessibleCommand)({
54
+ component: vm.type?.__name ?? "Origam",
55
+ zone: "prepend",
56
+ prop: "prependAriaLabel",
57
+ active: isPrependClickable,
58
+ label: () => props.prependAriaLabel
59
+ });
60
+ const appendCommandAttrs = (0, _accessibleCommand.useAccessibleCommand)({
61
+ component: vm.type?.__name ?? "Origam",
62
+ zone: "append",
63
+ prop: "appendAriaLabel",
64
+ active: isAppendClickable,
65
+ label: () => props.appendAriaLabel
66
+ });
52
67
  return {
68
+ prependCommandAttrs,
69
+ appendCommandAttrs,
53
70
  hasPrependMedia,
54
71
  hasPrepend,
55
72
  hasAppendMedia,
@@ -29,8 +29,20 @@ import type { IAdjacentProps } from '../../interfaces/Commons/adjacent.interface
29
29
  * consumer actually attached a `click:prepend`/`click:append`
30
30
  * listener — a decorative icon with nobody listening stays exactly
31
31
  * as inert as before, no spurious tab stop.
32
+ *
33
+ * @description
34
+ * ⛔ issue #747 — being CLICKABLE was never sufficient. `role="button"`
35
+ * with no accessible name is a WCAG 2.1 4.1.2 failure, and it was the
36
+ * shipped behaviour of every consumer of this hook: axe-core measured
37
+ * **54 `aria-command-name` nodes (`serious`) across 17 components** on
38
+ * untouched `develop`. `prependCommandAttrs` / `appendCommandAttrs`
39
+ * replace the raw `:role` / `:tabindex` bindings the templates used to
40
+ * write by hand — they emit the role AND the name together, or neither.
41
+ * See `useAccessibleCommand` for why no default label is fabricated.
32
42
  ********************************************************/
33
43
  export declare function useAdjacent(props: IAdjacentProps, prependIcon?: Ref | ComputedRef, appendIcon?: Ref | ComputedRef): {
44
+ prependCommandAttrs: ComputedRef<Record<string, unknown>>;
45
+ appendCommandAttrs: ComputedRef<Record<string, unknown>>;
34
46
  hasPrependMedia: ComputedRef<boolean>;
35
47
  hasPrepend: ComputedRef<boolean>;
36
48
  hasAppendMedia: ComputedRef<boolean>;
@@ -1,6 +1,7 @@
1
1
  import { computed, useSlots } from "vue";
2
2
  import { KEYBOARD_VALUES } from "../../enums/Commons/hotkey.enum.js";
3
3
  import { hasEvent } from "../../utils/Commons/commons.util.js";
4
+ import { useAccessibleCommand } from "./accessibleCommand.composable.js";
4
5
  import { getCurrentInstance } from "../../utils/Commons/getCurrentInstance.util.js";
5
6
  export function useAdjacent(props, prependIcon, appendIcon) {
6
7
  const vm = getCurrentInstance("OrigamAdjacent");
@@ -43,7 +44,23 @@ export function useAdjacent(props, prependIcon, appendIcon) {
43
44
  e.preventDefault();
44
45
  onClickAppend(e);
45
46
  };
47
+ const prependCommandAttrs = useAccessibleCommand({
48
+ component: vm.type?.__name ?? "Origam",
49
+ zone: "prepend",
50
+ prop: "prependAriaLabel",
51
+ active: isPrependClickable,
52
+ label: () => props.prependAriaLabel
53
+ });
54
+ const appendCommandAttrs = useAccessibleCommand({
55
+ component: vm.type?.__name ?? "Origam",
56
+ zone: "append",
57
+ prop: "appendAriaLabel",
58
+ active: isAppendClickable,
59
+ label: () => props.appendAriaLabel
60
+ });
46
61
  return {
62
+ prependCommandAttrs,
63
+ appendCommandAttrs,
47
64
  hasPrependMedia,
48
65
  hasPrepend,
49
66
  hasAppendMedia,
@@ -7,6 +7,7 @@ exports.useAdjacentInner = useAdjacentInner;
7
7
  var _vue = require("vue");
8
8
  var _hotkey = require("../../enums/Commons/hotkey.enum.cjs");
9
9
  var _commons = require("../../utils/Commons/commons.util.cjs");
10
+ var _accessibleCommand = require("./accessibleCommand.composable.cjs");
10
11
  var _getCurrentInstance = require("../../utils/Commons/getCurrentInstance.util.cjs");
11
12
  function useAdjacentInner(props) {
12
13
  const vm = (0, _getCurrentInstance.getCurrentInstance)("OrigamAdjacentInner");
@@ -41,19 +42,38 @@ function useAdjacentInner(props) {
41
42
  const isAppendInnerClickable = (0, _vue.computed)(() => {
42
43
  return (0, _commons.hasEvent)(vm.attrs, "click:appendInner") || (0, _commons.hasEvent)(vm.vnode.props ?? {}, "click:appendInner");
43
44
  });
45
+ const ownsKey = e => e.target === e.currentTarget;
44
46
  const onKeydownPrependInner = e => {
45
47
  if (!isPrependInnerClickable.value) return;
48
+ if (!ownsKey(e)) return;
46
49
  if (e.key !== _hotkey.KEYBOARD_VALUES.ENTER && e.key !== _hotkey.KEYBOARD_VALUES.EMPTY) return;
47
50
  e.preventDefault();
48
51
  onClickPrependInner(e);
49
52
  };
50
53
  const onKeydownAppendInner = e => {
51
54
  if (!isAppendInnerClickable.value) return;
55
+ if (!ownsKey(e)) return;
52
56
  if (e.key !== _hotkey.KEYBOARD_VALUES.ENTER && e.key !== _hotkey.KEYBOARD_VALUES.EMPTY) return;
53
57
  e.preventDefault();
54
58
  onClickAppendInner(e);
55
59
  };
60
+ const prependInnerCommandAttrs = (0, _accessibleCommand.useAccessibleCommand)({
61
+ component: vm.type?.__name ?? "Origam",
62
+ zone: "prependInner",
63
+ prop: "prependInnerAriaLabel",
64
+ active: isPrependInnerClickable,
65
+ label: () => props.prependInnerAriaLabel
66
+ });
67
+ const appendInnerCommandAttrs = (0, _accessibleCommand.useAccessibleCommand)({
68
+ component: vm.type?.__name ?? "Origam",
69
+ zone: "appendInner",
70
+ prop: "appendInnerAriaLabel",
71
+ active: isAppendInnerClickable,
72
+ label: () => props.appendInnerAriaLabel
73
+ });
56
74
  return {
75
+ prependInnerCommandAttrs,
76
+ appendInnerCommandAttrs,
57
77
  hasPrependInnerMedia,
58
78
  hasPrependInner,
59
79
  hasAppendInnerMedia,