origam 2.17.0 → 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 (213) hide show
  1. package/CHANGELOG.md +744 -1
  2. package/dist/src/assets/css/main.css +1 -1
  3. package/dist/src/assets/css/tokens/dark.css +125 -24
  4. package/dist/src/assets/css/tokens/light.css +49 -12
  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 +2846 -12
  9. package/dist/src/assets/scss/tokens/_light.scss +49 -12
  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 +43 -18
  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 +34 -14
  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 +83 -28
  51. package/dist/src/components/FileField/OrigamFileField.vue +20 -15
  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 +19 -3
  60. package/dist/src/components/Menu/OrigamMenu.vue +79 -9
  61. package/dist/src/components/NumberField/OrigamNumberField.vue +26 -16
  62. package/dist/src/components/OtpInputField/OrigamOtpInputField.vue +48 -24
  63. package/dist/src/components/PasswordField/OrigamPasswordField.vue +20 -15
  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 +57 -34
  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/Switch/OrigamSwitchTrack.vue +20 -0
  73. package/dist/src/components/Tabs/OrigamTab.vue +7 -4
  74. package/dist/src/components/Tabs/OrigamTabPanel.vue +4 -2
  75. package/dist/src/components/Tabs/OrigamTabs.vue +7 -5
  76. package/dist/src/components/TextField/OrigamTextField.vue +20 -15
  77. package/dist/src/components/TextareaField/OrigamTextareaField.vue +20 -15
  78. package/dist/src/components/Transition/OrigamExpandX.vue +19 -3
  79. package/dist/src/components/Transition/OrigamExpandY.vue +19 -3
  80. package/dist/src/components/Transition/OrigamTranslateScale.vue +26 -4
  81. package/dist/src/components/Video/OrigamVideo.vue +3 -2
  82. package/dist/src/components/VirtualScroll/OrigamVirtualScroll.vue +1 -1
  83. package/dist/src/components/Window/OrigamWindow.vue +20 -3
  84. package/dist/src/composables/Commons/accessibleCommand.composable.cjs +26 -0
  85. package/dist/src/composables/Commons/accessibleCommand.composable.d.ts +78 -0
  86. package/dist/src/composables/Commons/accessibleCommand.composable.js +20 -0
  87. package/dist/src/composables/Commons/activator.composable.cjs +10 -1
  88. package/dist/src/composables/Commons/activator.composable.js +11 -2
  89. package/dist/src/composables/Commons/adjacent.composable.cjs +17 -0
  90. package/dist/src/composables/Commons/adjacent.composable.d.ts +12 -0
  91. package/dist/src/composables/Commons/adjacent.composable.js +17 -0
  92. package/dist/src/composables/Commons/adjacentInner.composable.cjs +20 -0
  93. package/dist/src/composables/Commons/adjacentInner.composable.d.ts +24 -5
  94. package/dist/src/composables/Commons/adjacentInner.composable.js +20 -0
  95. package/dist/src/composables/Commons/audio.composable.cjs +14 -1
  96. package/dist/src/composables/Commons/audio.composable.js +14 -1
  97. package/dist/src/composables/Commons/backButton.composable.cjs +3 -1
  98. package/dist/src/composables/Commons/backButton.composable.js +3 -1
  99. package/dist/src/composables/Commons/border.composable.d.ts +13 -0
  100. package/dist/src/composables/Commons/colorEffect.composable.cjs +58 -46
  101. package/dist/src/composables/Commons/colorEffect.composable.d.ts +10 -5
  102. package/dist/src/composables/Commons/colorEffect.composable.js +70 -46
  103. package/dist/src/composables/Commons/createLayout.composable.cjs +21 -12
  104. package/dist/src/composables/Commons/createLayout.composable.js +21 -12
  105. package/dist/src/composables/Commons/delay.composable.d.ts +16 -0
  106. package/dist/src/composables/Commons/dimension.composable.d.ts +11 -0
  107. package/dist/src/composables/Commons/elevation.composable.cjs +6 -2
  108. package/dist/src/composables/Commons/elevation.composable.d.ts +37 -1
  109. package/dist/src/composables/Commons/elevation.composable.js +7 -2
  110. package/dist/src/composables/Commons/goTo.composable.cjs +4 -2
  111. package/dist/src/composables/Commons/goTo.composable.js +5 -3
  112. package/dist/src/composables/Commons/group.composable.cjs +14 -14
  113. package/dist/src/composables/Commons/group.composable.js +14 -14
  114. package/dist/src/composables/Commons/hotkey.composable.d.ts +18 -7
  115. package/dist/src/composables/Commons/hydration.composable.d.ts +8 -0
  116. package/dist/src/composables/Commons/link.composable.d.ts +20 -0
  117. package/dist/src/composables/Commons/locationStrategies.composable.d.ts +17 -0
  118. package/dist/src/composables/Commons/message.composable.d.ts +19 -5
  119. package/dist/src/composables/Commons/position.composable.d.ts +17 -6
  120. package/dist/src/composables/Commons/refs.composable.d.ts +11 -5
  121. package/dist/src/composables/Commons/rounded.composable.d.ts +11 -1
  122. package/dist/src/composables/Commons/scrolling.composable.cjs +15 -12
  123. package/dist/src/composables/Commons/scrolling.composable.js +15 -12
  124. package/dist/src/composables/Commons/size.composable.d.ts +15 -0
  125. package/dist/src/composables/Commons/ssrBoot.composable.cjs +9 -1
  126. package/dist/src/composables/Commons/ssrBoot.composable.js +10 -2
  127. package/dist/src/composables/Commons/stack.composable.cjs +13 -1
  128. package/dist/src/composables/Commons/stack.composable.js +13 -1
  129. package/dist/src/composables/Commons/theme-props-resolver.composable.cjs +41 -32
  130. package/dist/src/composables/Commons/theme-props-resolver.composable.js +41 -32
  131. package/dist/src/composables/Commons/validation.composable.cjs +3 -3
  132. package/dist/src/composables/Commons/validation.composable.js +3 -3
  133. package/dist/src/composables/Commons/virtual.composable.cjs +24 -8
  134. package/dist/src/composables/Commons/virtual.composable.js +24 -8
  135. package/dist/src/composables/Masonry/masonry.composable.cjs +18 -11
  136. package/dist/src/composables/Masonry/masonry.composable.js +18 -11
  137. package/dist/src/composables/Parallax/parallax.composable.cjs +1 -1
  138. package/dist/src/composables/Parallax/parallax.composable.js +1 -1
  139. package/dist/src/composables/index.cjs +36 -0
  140. package/dist/src/composables/index.d.ts +3 -0
  141. package/dist/src/composables/index.js +3 -0
  142. package/dist/src/consts/Chart/chart-cartesian.const.cjs +5 -2
  143. package/dist/src/consts/Chart/chart-cartesian.const.d.ts +42 -0
  144. package/dist/src/consts/Chart/chart-cartesian.const.js +3 -0
  145. package/dist/src/consts/Commons/border.const.cjs +2 -1
  146. package/dist/src/consts/Commons/border.const.d.ts +19 -0
  147. package/dist/src/consts/Commons/border.const.js +15 -0
  148. package/dist/src/consts/Commons/elevation.const.cjs +5 -1
  149. package/dist/src/consts/Commons/elevation.const.d.ts +52 -2
  150. package/dist/src/consts/Commons/elevation.const.js +4 -0
  151. package/dist/src/consts/Commons/ripple.const.cjs +13 -3
  152. package/dist/src/consts/Commons/ripple.const.js +13 -3
  153. package/dist/src/consts/RatingField/rating-field.const.cjs +10 -0
  154. package/dist/src/consts/RatingField/rating-field.const.d.ts +36 -0
  155. package/dist/src/consts/RatingField/rating-field.const.js +12 -0
  156. package/dist/src/consts/index.cjs +11 -0
  157. package/dist/src/consts/index.d.ts +1 -0
  158. package/dist/src/consts/index.js +1 -0
  159. package/dist/src/directives/ClickOutside/clickOutside.directive.cjs +2 -0
  160. package/dist/src/directives/ClickOutside/clickOutside.directive.js +2 -0
  161. package/dist/src/directives/Ripple/ripple.directive.cjs +2 -0
  162. package/dist/src/directives/Ripple/ripple.directive.js +2 -0
  163. package/dist/src/enums/Commons/color.enum.cjs +0 -1
  164. package/dist/src/enums/Commons/color.enum.d.ts +14 -5
  165. package/dist/src/enums/Commons/color.enum.js +0 -1
  166. package/dist/src/enums/Sheet/sheet.enum.d.ts +1 -1
  167. package/dist/src/interfaces/Chart/chart-cartesian.interface.d.ts +6 -2
  168. package/dist/src/interfaces/Commons/activator.interface.d.ts +3 -2
  169. package/dist/src/interfaces/Commons/adjacent.interface.d.ts +29 -0
  170. package/dist/src/interfaces/Commons/group.interface.d.ts +13 -2
  171. package/dist/src/interfaces/Commons/ripple.interface.d.ts +16 -0
  172. package/dist/src/interfaces/Commons/scroll.interface.d.ts +3 -2
  173. package/dist/src/interfaces/DataTable/data-table-header.interface.d.ts +2 -2
  174. package/dist/src/interfaces/DatePicker/date-picker-month.interface.d.ts +2 -1
  175. package/dist/src/interfaces/Field/field.interface.d.ts +21 -1
  176. package/dist/src/interfaces/Menu/menu.interface.d.ts +28 -1
  177. package/dist/src/interfaces/OtpInputField/otp-input-field.interface.d.ts +21 -1
  178. package/dist/src/interfaces/RatingField/rating-field-item.interface.d.ts +16 -1
  179. package/dist/src/interfaces/index.cjs +11 -0
  180. package/dist/src/interfaces/index.d.ts +1 -0
  181. package/dist/src/interfaces/index.js +1 -0
  182. package/dist/src/themes/origam.theme.cjs +8 -14
  183. package/dist/src/themes/origam.theme.js +6 -8
  184. package/dist/src/types/Commons/color.type.d.ts +4 -3
  185. package/dist/src/types/Commons/commons.type.d.ts +33 -0
  186. package/dist/src/types/Commons/theme.type.d.ts +2 -1
  187. package/dist/src/types/Sheet/sheet.type.d.ts +2 -1
  188. package/dist/src/types/index.cjs +22 -0
  189. package/dist/src/types/index.d.ts +2 -0
  190. package/dist/src/types/index.js +2 -0
  191. package/dist/src/types/tokens.type.d.ts +1 -1
  192. package/dist/src/utils/Commons/a11y.util.cjs +35 -0
  193. package/dist/src/utils/Commons/a11y.util.d.ts +63 -0
  194. package/dist/src/utils/Commons/a11y.util.js +33 -0
  195. package/dist/src/utils/Commons/clickOutside.util.cjs +5 -1
  196. package/dist/src/utils/Commons/clickOutside.util.js +5 -1
  197. package/dist/src/utils/Commons/color.util.cjs +10 -5
  198. package/dist/src/utils/Commons/color.util.d.ts +34 -5
  199. package/dist/src/utils/Commons/color.util.js +9 -5
  200. package/dist/src/utils/Commons/goTo.util.cjs +31 -14
  201. package/dist/src/utils/Commons/goTo.util.d.ts +1 -1
  202. package/dist/src/utils/Commons/goTo.util.js +31 -16
  203. package/dist/src/utils/Commons/location.util.cjs +18 -3
  204. package/dist/src/utils/Commons/location.util.js +18 -3
  205. package/dist/src/utils/Commons/ripple.util.cjs +5 -1
  206. package/dist/src/utils/Commons/ripple.util.js +5 -1
  207. package/dist/src/utils/index.cjs +11 -0
  208. package/dist/src/utils/index.d.ts +1 -0
  209. package/dist/src/utils/index.js +1 -0
  210. package/package.json +13 -2
  211. package/dist/src/types/Commons/locale.type.cjs +0 -1
  212. package/dist/src/types/Commons/locale.type.d.ts +0 -0
  213. package/dist/src/types/Commons/locale.type.js +0 -0
@@ -115,7 +115,7 @@
115
115
  </template>
116
116
 
117
117
  <script lang="ts" setup>
118
- import { computed, nextTick, onMounted, ref, shallowRef, StyleValue, toRef } from "vue";
118
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, StyleValue, toRef } from "vue";
119
119
  import OrigamBtn from "../Btn/OrigamBtn.vue";
120
120
  import OrigamInfiniteScrollIntersect from "./OrigamInfiniteScrollIntersect.vue";
121
121
  import OrigamProgress from "../Progress/OrigamProgress.vue";
@@ -125,6 +125,7 @@ import { useLocale } from "../../composables/Commons/locale.composable";
125
125
  import { useProps } from "../../composables/Commons/props.composable";
126
126
  import { useStyle } from "../../composables/Commons/style.composable";
127
127
  import { useTypography } from "../../composables/Commons/typography.composable";
128
+ import { IN_BROWSER } from "../../consts/Commons/commons.const";
128
129
  import { DIRECTION } from "../../enums/Commons/direction.enum";
129
130
  import { INFINITE_SCROLL_MODE, INFINITE_SCROLL_SIDE, INFINITE_SCROLL_STATUS } from "../../enums/InfiniteScroll/infinite-scroll.enum";
130
131
  import { PROGRESS_TYPE } from "../../enums/Progress/progress.enum";
@@ -213,25 +214,40 @@ const handleIntersect = ({ side, isIntersecting: _isIntersecting }) => {
213
214
  intersecting(side);
214
215
  }
215
216
  };
217
+ const frames = /* @__PURE__ */ new Set();
218
+ let disposed = false;
219
+ const scheduleFrame = (cb) => {
220
+ if (disposed || !IN_BROWSER) return;
221
+ const id2 = window.requestAnimationFrame(() => {
222
+ frames.delete(id2);
223
+ cb();
224
+ });
225
+ frames.add(id2);
226
+ };
227
+ onBeforeUnmount(() => {
228
+ disposed = true;
229
+ for (const id2 of frames) window.cancelAnimationFrame(id2);
230
+ frames.clear();
231
+ });
232
+ const scheduleFrames = (count, cb) => {
233
+ scheduleFrame(count <= 1 ? cb : () => scheduleFrames(count - 1, cb));
234
+ };
235
+ const rearmIntersect = () => {
236
+ intersecting(currentSide.value);
237
+ };
238
+ const afterDoneTick = () => {
239
+ if (disposed) return;
240
+ if (status.value === INFINITE_SCROLL_STATUS.EMPTY || status.value === INFINITE_SCROLL_STATUS.ERROR) return;
241
+ if (status.value === INFINITE_SCROLL_STATUS.OK && currentSide.value === INFINITE_SCROLL_SIDE.START) {
242
+ setScrollAmount(getScrollSize() - previousScrollSize + getScrollAmount());
243
+ }
244
+ if (props.mode !== INFINITE_SCROLL_MODE.MANUAL) {
245
+ nextTick(() => scheduleFrames(3, rearmIntersect));
246
+ }
247
+ };
216
248
  const done = (_status) => {
217
249
  status.value = _status;
218
- nextTick(() => {
219
- if (status.value === INFINITE_SCROLL_STATUS.EMPTY || status.value === INFINITE_SCROLL_STATUS.ERROR) return;
220
- if (status.value === INFINITE_SCROLL_STATUS.OK && currentSide.value === INFINITE_SCROLL_SIDE.START) {
221
- setScrollAmount(getScrollSize() - previousScrollSize + getScrollAmount());
222
- }
223
- if (props.mode !== INFINITE_SCROLL_MODE.MANUAL) {
224
- nextTick(() => {
225
- window.requestAnimationFrame(() => {
226
- window.requestAnimationFrame(() => {
227
- window.requestAnimationFrame(() => {
228
- intersecting(currentSide.value);
229
- });
230
- });
231
- });
232
- });
233
- }
234
- });
250
+ nextTick(afterDoneTick);
235
251
  };
236
252
  const intersecting = (side) => {
237
253
  if (props.mode !== "manual" && !isIntersecting.value) return;
@@ -2,6 +2,7 @@
2
2
  <component
3
3
  :is="tag"
4
4
  :id="id"
5
+ ref="rootRef"
5
6
  class="origam-inline-edit"
6
7
  :class="rootClasses"
7
8
  :style="rootStyles"
@@ -76,8 +77,8 @@
76
77
  data-cy="origam-inline-edit-input"
77
78
  hide-details
78
79
  @update:model-value="handleInput"
80
+ @focusout="handleFocusOut"
79
81
  @keydown="handleKeyDown"
80
- @blur="handleBlur"
81
82
  >
82
83
  <template
83
84
  v-if="showActions"
@@ -131,8 +132,8 @@
131
132
  data-cy="origam-inline-edit-input"
132
133
  hide-details
133
134
  @update:model-value="handleInput"
135
+ @focusout="handleFocusOut"
134
136
  @keydown="handleKeyDown"
135
- @blur="handleBlur"
136
137
  >
137
138
  <template
138
139
  v-if="showActions"
@@ -260,6 +261,13 @@ const {
260
261
  }));
261
262
  const inputRef = ref(null);
262
263
  const errorId = `origam-inline-edit-error-${useId()}`;
264
+ const rootRef = ref(null);
265
+ const rootEl = () => {
266
+ const r = rootRef.value;
267
+ if (!r) return null;
268
+ const el = r instanceof Element ? r : r.$el;
269
+ return el instanceof HTMLElement ? el : null;
270
+ };
263
271
  const displayValue = computed(() => {
264
272
  const v = props.modelValue;
265
273
  if (v === null || v === void 0) return "";
@@ -280,16 +288,34 @@ const handleEnterEdit = () => {
280
288
  edit();
281
289
  emit("edit");
282
290
  };
291
+ let restoreFocusOnLeave = false;
292
+ const noteTransition = (fromFocusOut) => {
293
+ if (fromFocusOut) {
294
+ restoreFocusOnLeave = false;
295
+ return;
296
+ }
297
+ if (typeof document === "undefined") {
298
+ restoreFocusOnLeave = false;
299
+ return;
300
+ }
301
+ const root = rootEl();
302
+ const active = document.activeElement;
303
+ restoreFocusOnLeave = !!root && !!active && root.contains(active);
304
+ };
283
305
  const handleConfirm = () => {
306
+ noteTransition(false);
284
307
  void confirm();
285
308
  };
286
309
  const handleCancel = () => {
310
+ noteTransition(false);
287
311
  cancel();
288
312
  };
289
313
  const handleInput = (value) => {
290
314
  setValue(value ?? "");
291
315
  };
292
316
  const handleKeyDown = (event) => {
317
+ const target = event.target;
318
+ if (!(target instanceof HTMLInputElement) && !(target instanceof HTMLTextAreaElement)) return;
293
319
  if (event.key === "Enter" && props.confirmOnEnter && !props.multiline) {
294
320
  event.preventDefault();
295
321
  handleConfirm();
@@ -305,13 +331,28 @@ const handleKeyDown = (event) => {
305
331
  handleCancel();
306
332
  }
307
333
  };
308
- const handleBlur = () => {
334
+ const handleFocusOut = (event) => {
309
335
  if (!props.confirmOnBlur) return;
336
+ if (!isEditing.value) return;
310
337
  if (isPending.value) return;
311
- handleConfirm();
338
+ const root = rootEl();
339
+ const next = event.relatedTarget;
340
+ if (root && next instanceof Node && root.contains(next)) return;
341
+ noteTransition(true);
342
+ void confirm();
343
+ };
344
+ const restoreFocusAfterEdit = async () => {
345
+ if (!restoreFocusOnLeave) return;
346
+ restoreFocusOnLeave = false;
347
+ await nextTick();
348
+ const target = rootEl()?.querySelector('[data-cy="origam-inline-edit-display"]');
349
+ if (target && typeof target.focus === "function") target.focus();
312
350
  };
313
351
  watch(isEditing, async (next) => {
314
- if (!next) return;
352
+ if (!next) {
353
+ void restoreFocusAfterEdit();
354
+ return;
355
+ }
315
356
  if (!props.autoFocus) return;
316
357
  await nextTick();
317
358
  const el = inputRef.value;
@@ -9,8 +9,7 @@
9
9
  v-if="hasPrepend"
10
10
  key="prepend"
11
11
  class="origam-input__prepend"
12
- :role="isPrependClickable ? 'button' : undefined"
13
- :tabindex="isPrependClickable ? 0 : undefined"
12
+ v-bind="prependCommandAttrs"
14
13
  @click="handleClickPrepend"
15
14
  @keydown="handleKeydownPrepend"
16
15
  >
@@ -44,8 +43,7 @@
44
43
  v-if="hasAppend"
45
44
  key="append"
46
45
  class="origam-input__append"
47
- :role="isAppendClickable ? 'button' : undefined"
48
- :tabindex="isAppendClickable ? 0 : undefined"
46
+ v-bind="appendCommandAttrs"
49
47
  @click="handleClickAppend"
50
48
  @keydown="handleKeydownAppend"
51
49
  >
@@ -191,6 +189,8 @@ const props = defineProps({
191
189
  appendIcon: { type: null, required: false },
192
190
  prependAvatar: { type: String, required: false },
193
191
  prependIcon: { type: null, required: false },
192
+ prependAriaLabel: { type: String, required: false },
193
+ appendAriaLabel: { type: String, required: false },
194
194
  size: { type: null, required: false },
195
195
  fontSize: { type: null, required: false },
196
196
  fontWeight: { type: null, required: false },
@@ -226,8 +226,8 @@ const {
226
226
  onClickAppend: handleClickAppend,
227
227
  onKeydownPrepend: handleKeydownPrepend,
228
228
  onKeydownAppend: handleKeydownAppend,
229
- isPrependClickable,
230
- isAppendClickable
229
+ prependCommandAttrs,
230
+ appendCommandAttrs
231
231
  } = useAdjacent(props, toRef(props, "prependIcon"), toRef(props, "appendIcon"));
232
232
  const messages = computed(() => {
233
233
  if (props.errorMessages?.length || !isPristine.value && errorMessages.value.length) {
@@ -16,8 +16,10 @@
16
16
  <origam-list-item
17
17
  :active="isOpen"
18
18
  :append-avatar="appendAvatar"
19
+ :append-aria-label="appendAriaLabel"
19
20
  :append-icon="appendActivatorIcon"
20
21
  :prepend-avatar="prependAvatar"
22
+ :prepend-aria-label="prependAriaLabel"
21
23
  :prepend-icon="prependActivatorIcon"
22
24
  :title="title"
23
25
  :value="value"
@@ -112,6 +114,8 @@ const props = defineProps({
112
114
  appendIcon: { type: null, required: false },
113
115
  prependAvatar: { type: String, required: false },
114
116
  prependIcon: { type: null, required: false },
117
+ prependAriaLabel: { type: String, required: false },
118
+ appendAriaLabel: { type: String, required: false },
115
119
  activeClass: { type: String, required: false },
116
120
  hover: { type: [Boolean, Object], required: false },
117
121
  hoverClass: { type: String, required: false }
@@ -28,8 +28,7 @@
28
28
  v-if="hasPrepend"
29
29
  key="prepend"
30
30
  class="origam-list-item__prepend"
31
- :role="isPrependZoneFocusable ? 'button' : undefined"
32
- :tabindex="isPrependZoneFocusable ? 0 : undefined"
31
+ v-bind="prependCommandAttrs"
33
32
  @click="handleClickPrepend"
34
33
  @keydown="handleKeydownPrepend"
35
34
  >
@@ -92,8 +91,7 @@
92
91
  v-if="hasAppend"
93
92
  key="append"
94
93
  class="origam-list-item__append"
95
- :role="isAppendZoneFocusable ? 'button' : undefined"
96
- :tabindex="isAppendZoneFocusable ? 0 : undefined"
94
+ v-bind="appendCommandAttrs"
97
95
  @click="handleClickAppend"
98
96
  @keydown="handleKeydownAppend"
99
97
  >
@@ -123,6 +121,7 @@
123
121
  import { computed, onBeforeMount, StyleValue, toRef, useAttrs, useSlots, watch } from "vue";
124
122
  import OrigamAvatar from "../Avatar/OrigamAvatar.vue";
125
123
  import OrigamIcon from "../Icon/OrigamIcon.vue";
124
+ import { useAccessibleCommand } from "../../composables/Commons/accessibleCommand.composable";
126
125
  import { useAdjacent } from "../../composables/Commons/adjacent.composable";
127
126
  import { useBothColor } from "../../composables/Commons/bothColor.composable";
128
127
  import { useDensity } from "../../composables/Commons/density.composable";
@@ -207,6 +206,8 @@ const props = defineProps({
207
206
  appendIcon: { type: null, required: false },
208
207
  prependAvatar: { type: String, required: false },
209
208
  prependIcon: { type: null, required: false },
209
+ prependAriaLabel: { type: String, required: false },
210
+ appendAriaLabel: { type: String, required: false },
210
211
  hover: { type: [Boolean, Object], required: false },
211
212
  hoverClass: { type: String, required: false },
212
213
  fontSize: { type: null, required: false },
@@ -261,6 +262,20 @@ const {
261
262
  } = useAdjacent(props, toRef(props, "prependIcon"), toRef(props, "appendIcon"));
262
263
  const isPrependZoneFocusable = computed(() => isPrependClickable.value && !link.isLink.value);
263
264
  const isAppendZoneFocusable = computed(() => isAppendClickable.value && !link.isLink.value);
265
+ const prependCommandAttrs = useAccessibleCommand({
266
+ component: "OrigamListItem",
267
+ zone: "prepend",
268
+ prop: "prependAriaLabel",
269
+ active: isPrependZoneFocusable,
270
+ label: () => props.prependAriaLabel
271
+ });
272
+ const appendCommandAttrs = useAccessibleCommand({
273
+ component: "OrigamListItem",
274
+ zone: "append",
275
+ prop: "appendAriaLabel",
276
+ active: isAppendZoneFocusable,
277
+ label: () => props.appendAriaLabel
278
+ });
264
279
  const isActive = computed(() => {
265
280
  return isActiveFlag.value || link.isActive?.value || isSelected.value;
266
281
  });
@@ -473,6 +488,55 @@ defineExpose({
473
488
  --origam-list-item---padding-inline-end: var(--origam-list-item--slim---padding-inline-end, 8px);
474
489
  }
475
490
 
491
+ /*********************************************************
492
+ * Densité — la LIGNE fait autorité, la liste ne pose qu'un défaut
493
+ *
494
+ * @description
495
+ * Ces trois règles REDÉCLARENT `--origam-list---density`, la même
496
+ * custom property que `.origam-list--density-*` pose sur la liste
497
+ * (`OrigamList.vue:453-463`), avec les mêmes valeurs. Elles
498
+ * n'ajoutent PAS un second terme au `calc()` de la règle de base.
499
+ *
500
+ * @description
501
+ * ⛔ CETTE DISTINCTION EST TOUT LE TICKET (#571). Mesuré en
502
+ * Chromium, liste en `compact` :
503
+ *
504
+ * redéclaration (ici) min-height = 48px — inchangé
505
+ * second terme dans le calc() min-height = 40px — -8px compté DEUX FOIS
506
+ *
507
+ * Une redéclaration écrit la même valeur sur un élément plus
508
+ * proche : le `calc()` la lit une fois. C'est ce qui rend ce
509
+ * câblage gratuit en rendu à l'intérieur d'une liste, et c'est la
510
+ * promesse sur laquelle l'arbitrage a été rendu.
511
+ *
512
+ * @description
513
+ * Ce que ça répare : une ligne SANS liste ancêtre n'avait aucune
514
+ * densité — la variable ne venait que de la liste, donc la prop
515
+ * rendait 56px quelle que soit sa valeur. Mesuré avant/après :
516
+ * `density="compact"` hors liste passe de 56px à 48px.
517
+ *
518
+ * @description
519
+ * ⚠️ `withDefaults` ne pose AUCUNE densité par défaut et
520
+ * `useDensity` n'émet rien sur `null`/`undefined` : une ligne à
521
+ * laquelle personne ne passe `density` n'émet donc aucune de ces
522
+ * classes, et la valeur de la liste la traverse intacte. C'est ce
523
+ * qui préserve `<origam-list density="comfortable">`. Le thème
524
+ * livré posait `density: 'compact'` sur CHAQUE ligne, ce qui aurait
525
+ * fait gagner la ligne contre la liste sur tout le catalogue —
526
+ * l'entrée a été retirée de `origam.theme.ts` dans le même lot.
527
+ ********************************************************/
528
+ &--density-default {
529
+ --origam-list---density: 0px;
530
+ }
531
+
532
+ &--density-compact {
533
+ --origam-list---density: -8px;
534
+ }
535
+
536
+ &--density-comfortable {
537
+ --origam-list---density: 8px;
538
+ }
539
+
476
540
  // Row-height scale, aligned rung for rung on the control-height scale
477
541
  // (`--origam-input__control---height-{sm,md,lg,xl}` = 28/36/44/52px) so
478
542
  // a row and a field of the same `size` share an identical vertical
@@ -20,7 +20,7 @@
20
20
  :style="getItemStyle(idx)"
21
21
  >
22
22
  <component
23
- :is="{ render: () => child }"
23
+ :is="child"
24
24
  />
25
25
  </div>
26
26
  </template>
@@ -30,6 +30,7 @@
30
30
  <script lang="ts" setup>
31
31
  import {
32
32
  computed,
33
+ onBeforeUnmount,
33
34
  onMounted,
34
35
  ref,
35
36
  StyleValue,
@@ -138,14 +139,29 @@ const { containerRef, setItem, layout, relayout } = useMasonry({
138
139
  breakpointsRef: toRef(props, "columnBreakpoints"),
139
140
  alignRef: toRef(props, "align")
140
141
  });
142
+ const frames = /* @__PURE__ */ new Set();
143
+ let disposed = false;
144
+ const scheduleFrame = (cb) => {
145
+ if (disposed || typeof window === "undefined") return;
146
+ const id = window.requestAnimationFrame(() => {
147
+ frames.delete(id);
148
+ cb();
149
+ });
150
+ frames.add(id);
151
+ };
152
+ onBeforeUnmount(() => {
153
+ disposed = true;
154
+ for (const id of frames) window.cancelAnimationFrame(id);
155
+ frames.clear();
156
+ });
141
157
  onMounted(() => {
142
158
  containerRef.value = rootEl.value;
143
159
  resolveGapPx();
144
- requestAnimationFrame(() => relayout());
160
+ scheduleFrame(() => relayout());
145
161
  });
146
162
  const { theme, mode } = useTheme();
147
163
  watch([() => props.gap, theme, mode], () => {
148
- requestAnimationFrame(resolveGapPx);
164
+ scheduleFrame(resolveGapPx);
149
165
  });
150
166
  const childrenVNodes = computed(() => {
151
167
  const raw = slots.default?.() ?? [];
@@ -76,7 +76,7 @@
76
76
  </template>
77
77
 
78
78
  <script lang="ts" setup>
79
- import { computed, inject, mergeProps, nextTick, provide, ref, shallowRef, StyleValue, toRef, watch } from "vue";
79
+ import { computed, inject, mergeProps, nextTick, onBeforeUnmount, provide, ref, shallowRef, StyleValue, toRef, watch } from "vue";
80
80
  import OrigamList from "../List/OrigamList.vue";
81
81
  import OrigamListGroup from "../List/OrigamListGroup.vue";
82
82
  import OrigamListItem from "../List/OrigamListItem.vue";
@@ -206,10 +206,6 @@ const props = defineProps({
206
206
  to: { type: null, required: false },
207
207
  exact: { type: Boolean, required: false },
208
208
  ripple: { type: [Boolean, Object], required: false },
209
- appendAvatar: { type: String, required: false },
210
- appendIcon: { type: null, required: false },
211
- prependAvatar: { type: String, required: false },
212
- prependIcon: { type: null, required: false },
213
209
  hover: { type: [Boolean, Object], required: false },
214
210
  hoverClass: { type: String, required: false },
215
211
  fontSize: { type: null, required: false },
@@ -240,6 +236,22 @@ const id = computed(() => props.id || `origam-menu-${uid}`);
240
236
  const origamOverlayRef = ref();
241
237
  const parent = inject(ORIGAM_MENU_KEY, null);
242
238
  const openChildren = shallowRef(0);
239
+ let disposed = false;
240
+ const timers = /* @__PURE__ */ new Set();
241
+ const scheduleTimeout = (cb, delay) => {
242
+ if (disposed) return;
243
+ const id2 = setTimeout(() => {
244
+ timers.delete(id2);
245
+ if (disposed) return;
246
+ cb();
247
+ }, delay);
248
+ timers.add(id2);
249
+ };
250
+ onBeforeUnmount(() => {
251
+ disposed = true;
252
+ for (const id2 of timers) clearTimeout(id2);
253
+ timers.clear();
254
+ });
243
255
  provide(ORIGAM_MENU_KEY, {
244
256
  register() {
245
257
  ++openChildren.value;
@@ -248,7 +260,7 @@ provide(ORIGAM_MENU_KEY, {
248
260
  --openChildren.value;
249
261
  },
250
262
  closeParents() {
251
- setTimeout(() => {
263
+ scheduleTimeout(() => {
252
264
  if (!openChildren.value) {
253
265
  isActive.value = false;
254
266
  parent?.closeParents();
@@ -316,7 +328,7 @@ const handleActivatorKeydown = (e) => {
316
328
  } else if (keyDown.includes(e.key)) {
317
329
  isActive.value = true;
318
330
  e.preventDefault();
319
- setTimeout(() => setTimeout(() => handleActivatorKeydown(e)));
331
+ scheduleTimeout(() => scheduleTimeout(() => handleActivatorKeydown(e)));
320
332
  }
321
333
  };
322
334
  const activatorProps = computed(() => {
@@ -382,6 +394,50 @@ defineExpose(forwardRefs({
382
394
  box-shadow: none;
383
395
  }
384
396
 
397
+ /**
398
+ * #742 — le plafond de hauteur et le défilement DOIVENT porter sur la
399
+ * même boîte.
400
+ *
401
+ * Deux plafonds coexistent, et aucun des deux n'était le scrollport :
402
+ *
403
+ * 1. `.origam-overlay__content` — plafond posé en INLINE par
404
+ * `useDimension` quand le consommateur passe `max-height`
405
+ * (c'est le chemin d'`OrigamSelect`, qui passe `:max-height="310"`),
406
+ * ou par la stratégie de placement quand il n'y a pas de prop.
407
+ * 2. `.origam-menu__content` — plafond du token
408
+ * `--origam-menu---max-height`.
409
+ *
410
+ * Le `overflow` était, lui, posé sur `.origam-menu__list` — une boîte
411
+ * SANS plafond (`max-height: none`), donc `clientHeight === scrollHeight`
412
+ * et rien à faire défiler. Mesuré avant correctif, Chromium, 30 options :
413
+ * overlay 240/1453, menu__content 580/1448, list 1448/1448, les trois à
414
+ * `scrollTop === 0`. Le nom même du token (`--origam-menu__content---overflow`)
415
+ * disait déjà où la règle devait vivre.
416
+ *
417
+ * Le correctif rend `.origam-menu__content` — la boîte qui porte la
418
+ * surface visible, donc celle dont l'ascenseur doit épouser le rayon et
419
+ * le fond — scrollport :
420
+ *
421
+ * • `overflow` revient sur `.origam-menu__content` (token inchangé) ;
422
+ * • le parent `.origam-overlay__content` devient un conteneur flex
423
+ * colonne, ce qui rend son plafond (inline ou calculé) opposable à
424
+ * son enfant : sans cela un `max-height` posé sur le PARENT ne
425
+ * contraint pas un enfant en flux normal, et le contenu ressort.
426
+ * • `min-height: 0` lève le plancher `min-height: auto` des items
427
+ * flex, sans quoi l'enfant refuserait de descendre sous la hauteur
428
+ * de son contenu et ne défilerait toujours pas.
429
+ *
430
+ * Les sous-menus ne sont PAS rognés : `useTeleport` résout
431
+ * `props.attach || props.contained` à `false` → `document.body`, donc
432
+ * chaque niveau est téléporté dans `body > .origam-overlay-container` et
433
+ * n'est jamais un descendant DOM du scrollport. Vérifié en runtime
434
+ * (`root.contains(flyout) === false`).
435
+ */
436
+ .origam-menu :deep(.origam-overlay__content) {
437
+ display: flex;
438
+ flex-direction: column;
439
+ }
440
+
385
441
  .origam-menu__content {
386
442
  background: var(--origam-menu---background, var(--origam-color__surface---raised));
387
443
  backdrop-filter: var(--origam-menu---backdrop-filter, none);
@@ -390,11 +446,25 @@ defineExpose(forwardRefs({
390
446
  border-radius: var(--origam-menu---border-radius, 8px);
391
447
  box-shadow: var(--origam-menu---box-shadow);
392
448
  max-height: var(--origam-menu---max-height, calc(100vh - 32px));
393
- display: inline-block;
449
+ min-height: 0;
450
+ overflow: var(--origam-menu__content---overflow, auto);
451
+ /**
452
+ * `block`, plus `inline-block`. Un item flex est BLOCKIFIÉ : depuis
453
+ * que le parent est un conteneur flex, `inline-block` ne pouvait
454
+ * plus gagner — le déclarer aurait été exactement le genre de
455
+ * déclaration morte que ce ticket corrige. Le rétrécissement au
456
+ * contenu était déjà assuré par `width: max-content`, pas par
457
+ * `inline-block` : mesuré avant/après sur 8 panneaux (menu, select,
458
+ * contextual-menu, date-picker-field, color-picker-field,
459
+ * media-controller), le rectangle du panneau est IDENTIQUE au pixel.
460
+ * Seule la boîte parente perd 5px — le descendeur de la line-box
461
+ * qu'un enfant inline-block imposait à son bloc parent, bande
462
+ * transparente sous chaque panneau.
463
+ */
464
+ display: block;
394
465
  width: max-content;
395
466
 
396
467
  .origam-menu__list {
397
- overflow: var(--origam-menu__content---overflow, auto);
398
468
  max-width: var(--origam-menu__content---max-width, 320px);
399
469
  padding: var(--origam-menu__content---padding, 4px);
400
470
  }
@@ -348,6 +348,21 @@ const props = defineProps({
348
348
  prependInnerIcon: { type: null, required: false },
349
349
  clearIcon: { type: null, required: false },
350
350
  clearable: { type: Boolean, required: false },
351
+ prependInnerAriaLabel: { type: String, required: false },
352
+ appendInnerAriaLabel: { type: String, required: false },
353
+ border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true, default: true },
354
+ borderTop: { type: [Boolean, Number, String], required: false },
355
+ borderLeft: { type: [Boolean, Number, String], required: false },
356
+ borderBottom: { type: [Boolean, Number, String], required: false },
357
+ borderRight: { type: [Boolean, Number, String], required: false },
358
+ borderBlock: { type: [Boolean, Number, String], required: false },
359
+ borderInline: { type: [Boolean, Number, String], required: false },
360
+ borderColor: { type: String, required: false },
361
+ borderStyle: { type: String, required: false },
362
+ borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
363
+ borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
364
+ borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
365
+ borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
351
366
  focused: { type: Boolean, required: false },
352
367
  density: { type: null, required: false },
353
368
  text: { type: String, required: false },
@@ -367,19 +382,6 @@ const props = defineProps({
367
382
  paddingRight: { type: [Boolean, Number, String], required: false },
368
383
  paddingBlock: { type: [Boolean, Number, String], required: false },
369
384
  paddingInline: { type: [Boolean, Number, String], required: false },
370
- border: { type: [Boolean, Number, String, Array], required: false, skipCheck: true, default: true },
371
- borderTop: { type: [Boolean, Number, String], required: false },
372
- borderLeft: { type: [Boolean, Number, String], required: false },
373
- borderBottom: { type: [Boolean, Number, String], required: false },
374
- borderRight: { type: [Boolean, Number, String], required: false },
375
- borderBlock: { type: [Boolean, Number, String], required: false },
376
- borderInline: { type: [Boolean, Number, String], required: false },
377
- borderColor: { type: String, required: false },
378
- borderStyle: { type: String, required: false },
379
- borderTopColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
380
- borderRightColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
381
- borderBottomColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
382
- borderLeftColor: { type: [String, Object, Boolean, null], required: false, skipCheck: true },
383
385
  rounded: { type: [Boolean, Number, String, null], required: false, skipCheck: true, default: true },
384
386
  roundedTopRight: { type: [Boolean, Number, String], required: false },
385
387
  roundedTopLeft: { type: [Boolean, Number, String], required: false },
@@ -415,7 +417,9 @@ const props = defineProps({
415
417
  appendAvatar: { type: String, required: false },
416
418
  appendIcon: { type: null, required: false },
417
419
  prependAvatar: { type: String, required: false },
418
- prependIcon: { type: null, required: false }
420
+ prependIcon: { type: null, required: false },
421
+ prependAriaLabel: { type: String, required: false },
422
+ appendAriaLabel: { type: String, required: false }
419
423
  });
420
424
  const emits = defineEmits(["click:control", "mousedown:control", "click:clear", "increment", "decrement", "update:focused", "click:appendInner", "click:prependInner", "update:modelValue", "click:append", "click:prepend"]);
421
425
  defineSlots();
@@ -733,7 +737,11 @@ defineExpose(forwardRefs({
733
737
  }
734
738
 
735
739
  :deep(.origam-field--appended) {
736
- --origam-field---padding-end: 0;
740
+ // #800 — l'unite est obligatoire (`0` nu = `<number>`, jete toute
741
+ // declaration `max()` / `calc()` qui le lit). Sans effet de rendu ici
742
+ // (mesure Chromium) : `--padding-end` n'est pas un terme du plancher,
743
+ // il est passe tel quel comme seconde valeur de `padding-inline`.
744
+ --origam-field---padding-end: 0px;
737
745
  }
738
746
 
739
747
  &__control {
@@ -761,7 +769,9 @@ defineExpose(forwardRefs({
761
769
  }
762
770
 
763
771
  :deep(.origam-field--prepended) {
764
- --origam-field---padding-start: 0;
772
+ // #800 — idem : l'unite est obligatoire. Sans effet de rendu, la
773
+ // cible etant `--prepended`, qui n'applique pas le plancher.
774
+ --origam-field---padding-start: 0px;
765
775
  }
766
776
  }
767
777