origam 2.17.1 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/CHANGELOG.md +690 -1
  2. package/dist/src/assets/css/main.css +1 -1
  3. package/dist/src/assets/css/tokens/dark.css +119 -20
  4. package/dist/src/assets/css/tokens/light.css +46 -10
  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 +2843 -10
  9. package/dist/src/assets/scss/tokens/_light.scss +46 -10
  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 +21 -3
  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/Chart/chart-cartesian.interface.d.ts +6 -2
  163. package/dist/src/interfaces/Commons/activator.interface.d.ts +3 -2
  164. package/dist/src/interfaces/Commons/adjacent.interface.d.ts +29 -0
  165. package/dist/src/interfaces/Commons/group.interface.d.ts +13 -2
  166. package/dist/src/interfaces/Commons/ripple.interface.d.ts +16 -0
  167. package/dist/src/interfaces/Commons/scroll.interface.d.ts +3 -2
  168. package/dist/src/interfaces/DataTable/data-table-header.interface.d.ts +2 -2
  169. package/dist/src/interfaces/DatePicker/date-picker-month.interface.d.ts +2 -1
  170. package/dist/src/interfaces/Menu/menu.interface.d.ts +28 -1
  171. package/dist/src/interfaces/OtpInputField/otp-input-field.interface.d.ts +21 -1
  172. package/dist/src/interfaces/RatingField/rating-field-item.interface.d.ts +16 -1
  173. package/dist/src/interfaces/index.cjs +11 -0
  174. package/dist/src/interfaces/index.d.ts +1 -0
  175. package/dist/src/interfaces/index.js +1 -0
  176. package/dist/src/themes/origam.theme.cjs +8 -14
  177. package/dist/src/themes/origam.theme.js +6 -8
  178. package/dist/src/types/Commons/color.type.d.ts +4 -3
  179. package/dist/src/types/Commons/commons.type.d.ts +33 -0
  180. package/dist/src/types/Commons/theme.type.d.ts +2 -1
  181. package/dist/src/types/Sheet/sheet.type.d.ts +2 -1
  182. package/dist/src/types/index.cjs +22 -0
  183. package/dist/src/types/index.d.ts +2 -0
  184. package/dist/src/types/index.js +2 -0
  185. package/dist/src/types/tokens.type.d.ts +1 -1
  186. package/dist/src/utils/Commons/a11y.util.cjs +35 -0
  187. package/dist/src/utils/Commons/a11y.util.d.ts +63 -0
  188. package/dist/src/utils/Commons/a11y.util.js +33 -0
  189. package/dist/src/utils/Commons/clickOutside.util.cjs +5 -1
  190. package/dist/src/utils/Commons/clickOutside.util.js +5 -1
  191. package/dist/src/utils/Commons/color.util.cjs +10 -5
  192. package/dist/src/utils/Commons/color.util.d.ts +34 -5
  193. package/dist/src/utils/Commons/color.util.js +9 -5
  194. package/dist/src/utils/Commons/goTo.util.cjs +31 -14
  195. package/dist/src/utils/Commons/goTo.util.d.ts +1 -1
  196. package/dist/src/utils/Commons/goTo.util.js +31 -16
  197. package/dist/src/utils/Commons/location.util.cjs +18 -3
  198. package/dist/src/utils/Commons/location.util.js +18 -3
  199. package/dist/src/utils/Commons/ripple.util.cjs +5 -1
  200. package/dist/src/utils/Commons/ripple.util.js +5 -1
  201. package/dist/src/utils/index.cjs +11 -0
  202. package/dist/src/utils/index.d.ts +1 -0
  203. package/dist/src/utils/index.js +1 -0
  204. package/package.json +13 -2
  205. package/dist/src/types/Commons/locale.type.cjs +0 -1
  206. package/dist/src/types/Commons/locale.type.d.ts +0 -0
  207. package/dist/src/types/Commons/locale.type.js +0 -0
@@ -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,
@@ -14,13 +14,32 @@ import type { IAdjacentInnerProps } from '../../interfaces/Commons/adjacent.inte
14
14
  * `click:appendInner` only ever fired from a literal DOM click inside
15
15
  * the zone, never from a keyboard activation of an ancestor. See the
16
16
  * long comment on `useAdjacent` for the full reasoning; mirrored here
17
- * for the inner zone. `isClearClickable` stays permanently true when
18
- * `hasClear` is — the clear zone only renders (`v-show="dirty"`) when
19
- * there is something to clear, so it is unconditionally actionable
20
- * whenever visible, unlike prependInner/appendInner whose
21
- * actionability depends on whether the consumer wired a listener.
17
+ * for the inner zone.
18
+ *
19
+ * @description
20
+ * ⛔ Cette banniere a longtemps decrit un `isClearClickable` — il
21
+ * n'existe NULLE PART dans le code, ni ici ni ailleurs dans
22
+ * `packages/ds/src` (verifie par recherche : la seule occurrence du depot
23
+ * etait cette phrase). Le generateur de `packages/docs/composables/Commons.md`
24
+ * recopie les bannieres, donc la doc publiee nommait un symbole
25
+ * inexistant — le defaut #493 exactement. La zone « clear » n'expose que
26
+ * `hasClear` et le handler `clickClear` ; elle ne passe par
27
+ * `useAccessibleCommand` ni par aucun test de clicabilite, parce qu'elle
28
+ * ne rend (`v-show="dirty"`) que lorsqu'il y a quelque chose a effacer.
29
+ *
30
+ * @description
31
+ * ⚠️ `hasPrependInner` / `hasAppendInner` / `hasClear` ne sont PAS des
32
+ * booleens : ils rendent la FONCTION de slot quand le slot correspondant
33
+ * existe (`slots.prependInner || …`), sinon le booleen du media, et
34
+ * `hasClear` rend `undefined` quand ni `clearable` ni le slot `clear` ne
35
+ * sont fournis. Les trois sont a consommer en verite/faussete, jamais en
36
+ * comparaison stricte a `true`/`false`. `useAdjacent`, lui, normalise
37
+ * (`!!slots.prepend || …`) et rend de vrais booleens — les deux jumeaux
38
+ * ne se comportent pas pareil sur ce point.
22
39
  ********************************************************/
23
40
  export declare function useAdjacentInner(props: IAdjacentInnerProps): {
41
+ prependInnerCommandAttrs: import("vue").ComputedRef<Record<string, unknown>>;
42
+ appendInnerCommandAttrs: import("vue").ComputedRef<Record<string, unknown>>;
24
43
  hasPrependInnerMedia: import("vue").ComputedRef<boolean>;
25
44
  hasPrependInner: import("vue").ComputedRef<boolean | import("vue").Slot<any>>;
26
45
  hasAppendInnerMedia: import("vue").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 useAdjacentInner(props) {
6
7
  const vm = getCurrentInstance("OrigamAdjacentInner");
@@ -35,19 +36,38 @@ export function useAdjacentInner(props) {
35
36
  const isAppendInnerClickable = computed(() => {
36
37
  return hasEvent(vm.attrs, "click:appendInner") || hasEvent(vm.vnode.props ?? {}, "click:appendInner");
37
38
  });
39
+ const ownsKey = (e) => e.target === e.currentTarget;
38
40
  const onKeydownPrependInner = (e) => {
39
41
  if (!isPrependInnerClickable.value) return;
42
+ if (!ownsKey(e)) return;
40
43
  if (e.key !== KEYBOARD_VALUES.ENTER && e.key !== KEYBOARD_VALUES.EMPTY) return;
41
44
  e.preventDefault();
42
45
  onClickPrependInner(e);
43
46
  };
44
47
  const onKeydownAppendInner = (e) => {
45
48
  if (!isAppendInnerClickable.value) return;
49
+ if (!ownsKey(e)) return;
46
50
  if (e.key !== KEYBOARD_VALUES.ENTER && e.key !== KEYBOARD_VALUES.EMPTY) return;
47
51
  e.preventDefault();
48
52
  onClickAppendInner(e);
49
53
  };
54
+ const prependInnerCommandAttrs = useAccessibleCommand({
55
+ component: vm.type?.__name ?? "Origam",
56
+ zone: "prependInner",
57
+ prop: "prependInnerAriaLabel",
58
+ active: isPrependInnerClickable,
59
+ label: () => props.prependInnerAriaLabel
60
+ });
61
+ const appendInnerCommandAttrs = useAccessibleCommand({
62
+ component: vm.type?.__name ?? "Origam",
63
+ zone: "appendInner",
64
+ prop: "appendInnerAriaLabel",
65
+ active: isAppendInnerClickable,
66
+ label: () => props.appendInnerAriaLabel
67
+ });
50
68
  return {
69
+ prependInnerCommandAttrs,
70
+ appendInnerCommandAttrs,
51
71
  hasPrependInnerMedia,
52
72
  hasPrependInner,
53
73
  hasAppendInnerMedia,
@@ -6,18 +6,31 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useAudio = useAudio;
7
7
  var _vue = require("vue");
8
8
  var _audio = require("../../consts/Audio/audio.const.cjs");
9
+ var _commons = require("../../utils/Commons/commons.util.cjs");
9
10
  function useAudio(props) {
10
11
  const analyser = (0, _vue.ref)(null);
11
12
  const audioArray = (0, _vue.shallowRef)(null);
12
13
  const audioRef = (0, _vue.ref)();
13
14
  const wasPlayed = (0, _vue.ref)(false);
14
15
  const isPlaying = (0, _vue.ref)(false);
16
+ let frame = -1;
17
+ let disposed = false;
15
18
  const getSongData = () => {
19
+ if (disposed) return;
16
20
  if (isPlaying.value && audioArray.value) {
17
21
  analyser.value?.getByteFrequencyData(audioArray.value);
18
- requestAnimationFrame(getSongData);
22
+ frame = requestAnimationFrame(getSongData);
23
+ } else {
24
+ frame = -1;
19
25
  }
20
26
  };
27
+ (0, _commons.tryOnScopeDispose)(() => {
28
+ disposed = true;
29
+ if (frame !== -1) {
30
+ cancelAnimationFrame(frame);
31
+ frame = -1;
32
+ }
33
+ });
21
34
  const onPlay = () => {
22
35
  if (!wasPlayed.value) {
23
36
  onAudio();