@eunomia/elements 1.0.0-beta.6 → 1.0.0-beta.7

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 (245) hide show
  1. package/README.md +1 -1
  2. package/dist/cdn/components/chunks/{chunk-JYIIWN2P.js → chunk-36KLGY6U.js} +8 -8
  3. package/dist/cdn/components/chunks/chunk-3BMACIDO.js +1 -0
  4. package/dist/cdn/components/chunks/{chunk-KDN4O5W2.js → chunk-3PNGQEG4.js} +3 -3
  5. package/dist/cdn/components/chunks/{chunk-ZKZV2YG5.js → chunk-5XPOGBPL.js} +1 -1
  6. package/dist/cdn/components/chunks/{chunk-LMVW522V.js → chunk-62RLISRD.js} +1 -1
  7. package/dist/cdn/components/chunks/{chunk-PMPSJG5V.js → chunk-6FYW5TQU.js} +3 -3
  8. package/dist/cdn/components/chunks/chunk-AK2DIJX7.js +1 -0
  9. package/dist/cdn/components/chunks/chunk-B5XMGWM7.js +10 -0
  10. package/dist/cdn/components/chunks/chunk-BVASCT2V.js +109 -0
  11. package/dist/cdn/components/chunks/{chunk-VYFR364B.js → chunk-DGI7TKCU.js} +14 -9
  12. package/dist/cdn/components/chunks/chunk-GVS6IUKC.js +1 -0
  13. package/dist/cdn/components/chunks/chunk-GWLD2I3P.js +8 -0
  14. package/dist/cdn/components/chunks/{chunk-UDVB4LAE.js → chunk-I4ERDXSM.js} +5 -3
  15. package/dist/cdn/components/chunks/{chunk-QZ5SHR3I.js → chunk-J3SZBXM6.js} +2 -2
  16. package/dist/cdn/components/chunks/{chunk-MOMYII3P.js → chunk-LVKMAHMU.js} +10 -0
  17. package/dist/cdn/components/chunks/{chunk-XDPRWUKN.js → chunk-MQQJ6DID.js} +1 -1
  18. package/dist/cdn/components/chunks/{chunk-SZYEBMG6.js → chunk-PXF554MD.js} +1 -1
  19. package/dist/cdn/components/chunks/chunk-QL5GSW2A.js +1 -0
  20. package/dist/cdn/components/chunks/{chunk-7KKWYPHY.js → chunk-QXQ25SQS.js} +21 -19
  21. package/dist/cdn/components/chunks/{chunk-L2ADCEN7.js → chunk-SVGWCKWT.js} +1 -1
  22. package/dist/cdn/components/chunks/{chunk-MQQ4BGVJ.js → chunk-TFTRCIIK.js} +7 -6
  23. package/dist/cdn/components/chunks/chunk-TLBXTBMM.js +46 -0
  24. package/dist/cdn/components/chunks/chunk-UVHVQRPT.js +1 -0
  25. package/dist/cdn/components/chunks/chunk-WW4BTWMH.js +1 -0
  26. package/dist/cdn/components/chunks/{chunk-2Y2EU2CI.js → chunk-Z3OFIE7S.js} +1 -1
  27. package/dist/cdn/components/eun-alert.js +13 -6
  28. package/dist/cdn/components/eun-animate.js +3 -3
  29. package/dist/cdn/components/eun-badge.js +1 -1
  30. package/dist/cdn/components/eun-button.js +1 -1
  31. package/dist/cdn/components/eun-calendar.js +2 -2
  32. package/dist/cdn/components/eun-card.js +4 -4
  33. package/dist/cdn/components/eun-carousel.js +21 -18
  34. package/dist/cdn/components/eun-check-card.js +1 -1
  35. package/dist/cdn/components/eun-checkbox-list.js +11 -8
  36. package/dist/cdn/components/eun-checkbox.js +1 -1
  37. package/dist/cdn/components/eun-chip.js +3 -3
  38. package/dist/cdn/components/eun-color-picker.js +60 -68
  39. package/dist/cdn/components/eun-counter.js +10 -10
  40. package/dist/cdn/components/eun-date-picker.js +47 -46
  41. package/dist/cdn/components/eun-description-list.js +2 -2
  42. package/dist/cdn/components/eun-divider.js +3 -3
  43. package/dist/cdn/components/eun-drawer.js +5 -5
  44. package/dist/cdn/components/eun-dropdown-button.js +1 -1
  45. package/dist/cdn/components/eun-fab.js +2 -2
  46. package/dist/cdn/components/eun-icon.js +1 -1
  47. package/dist/cdn/components/eun-image-card.js +1 -1
  48. package/dist/cdn/components/eun-image-carousel.js +10 -10
  49. package/dist/cdn/components/eun-infinite-list.js +1 -1
  50. package/dist/cdn/components/eun-input-file.js +21 -21
  51. package/dist/cdn/components/eun-input-phone.js +10 -9
  52. package/dist/cdn/components/eun-input.js +1 -1
  53. package/dist/cdn/components/eun-link.js +2 -2
  54. package/dist/cdn/components/eun-loader.js +1 -1
  55. package/dist/cdn/components/eun-modal.js +13 -13
  56. package/dist/cdn/components/eun-pagination.js +16 -16
  57. package/dist/cdn/components/eun-password-strength.js +14 -10
  58. package/dist/cdn/components/eun-radio-card.js +1 -1
  59. package/dist/cdn/components/eun-radio-list.js +11 -8
  60. package/dist/cdn/components/eun-radio.js +1 -1
  61. package/dist/cdn/components/eun-rating.js +276 -0
  62. package/dist/cdn/components/eun-scheduler-event-editor.js +10 -10
  63. package/dist/cdn/components/eun-scheduler-event.js +1 -1
  64. package/dist/cdn/components/eun-scheduler.js +28 -28
  65. package/dist/cdn/components/eun-search.js +19 -21
  66. package/dist/cdn/components/eun-select.js +27 -27
  67. package/dist/cdn/components/eun-sidebar.js +10 -8
  68. package/dist/cdn/components/eun-skeleton.js +1 -1
  69. package/dist/cdn/components/eun-slider.js +3 -3
  70. package/dist/cdn/components/eun-sliding-card.js +1 -1
  71. package/dist/cdn/components/eun-step.js +5 -4
  72. package/dist/cdn/components/eun-stepper.js +25 -25
  73. package/dist/cdn/components/eun-switch.js +1 -1
  74. package/dist/cdn/components/eun-tab-group.js +4 -4
  75. package/dist/cdn/components/eun-tab.js +1 -1
  76. package/dist/cdn/components/eun-table-action-bar.js +1 -1
  77. package/dist/cdn/components/eun-table.js +1 -1
  78. package/dist/cdn/components/eun-tag.js +3 -3
  79. package/dist/cdn/components/eun-textarea.js +39 -34
  80. package/dist/cdn/components/eun-time-picker.js +15 -14
  81. package/dist/cdn/components/eun-toast.js +19 -10
  82. package/dist/cdn/components/eun-toggle-group.js +6 -4
  83. package/dist/cdn/components/eun-toggle-item.js +1 -1
  84. package/dist/cdn/components/eun-toggle.js +2 -2
  85. package/dist/cdn/components/eun-toolbar.js +5 -5
  86. package/dist/cdn/components/eun-tooltip.js +3 -3
  87. package/dist/components/action/button/button.d.ts +2 -1
  88. package/dist/components/action/button/button.js +3 -2
  89. package/dist/components/action/button/button.styles.js +10 -5
  90. package/dist/components/action/dropdown-button/dropdown-button.js +10 -5
  91. package/dist/components/action/toggle/toggle-group.js +1 -1
  92. package/dist/components/action/toggle/toggle-group.styles.js +4 -2
  93. package/dist/components/action/toggle/toggle.js +1 -1
  94. package/dist/components/alert/alert/alert.d.ts +9 -7
  95. package/dist/components/alert/alert/alert.js +11 -14
  96. package/dist/components/alert/alert/alert.styles.js +9 -2
  97. package/dist/components/alert/drawer/drawer.d.ts +5 -5
  98. package/dist/components/alert/drawer/drawer.js +8 -12
  99. package/dist/components/alert/drawer/drawer.styles.js +1 -1
  100. package/dist/components/alert/modal/modal.d.ts +10 -10
  101. package/dist/components/alert/modal/modal.js +13 -25
  102. package/dist/components/alert/toast/toast.d.ts +7 -5
  103. package/dist/components/alert/toast/toast.js +9 -13
  104. package/dist/components/alert/toast/toast.styles.js +15 -6
  105. package/dist/components/content/badge/badge.js +2 -2
  106. package/dist/components/content/card/card.js +1 -1
  107. package/dist/components/content/card/card.styles.js +2 -2
  108. package/dist/components/content/chip/chip.d.ts +4 -4
  109. package/dist/components/content/chip/chip.js +8 -8
  110. package/dist/components/content/description-list/description-list.js +3 -3
  111. package/dist/components/content/icon/icon.d.ts +3 -0
  112. package/dist/components/content/icon/icon.js +3 -0
  113. package/dist/components/content/icon/icon.style.d.ts +2 -0
  114. package/dist/components/content/icon/icon.style.js +4 -0
  115. package/dist/components/content/image-carousel/image-carousel.d.ts +12 -12
  116. package/dist/components/content/image-carousel/image-carousel.js +24 -24
  117. package/dist/components/content/password-strength/password-strength.d.ts +21 -6
  118. package/dist/components/content/password-strength/password-strength.js +37 -16
  119. package/dist/components/content/password-strength/password-strength.styles.js +4 -0
  120. package/dist/components/content/tag/tag.js +2 -2
  121. package/dist/components/content/tooltip/tooltip.js +3 -3
  122. package/dist/components/form/checkbox/check-card.d.ts +1 -0
  123. package/dist/components/form/checkbox/check-card.js +1 -0
  124. package/dist/components/form/checkbox/checkbox-list.d.ts +17 -0
  125. package/dist/components/form/checkbox/checkbox-list.js +39 -10
  126. package/dist/components/form/checkbox/checkbox.d.ts +1 -0
  127. package/dist/components/form/checkbox/checkbox.js +3 -1
  128. package/dist/components/form/checkbox/checkbox.styles.js +3 -2
  129. package/dist/components/form/color-picker/color-picker.d.ts +41 -28
  130. package/dist/components/form/color-picker/color-picker.js +66 -50
  131. package/dist/components/form/color-picker/color-picker.styles.js +1 -1
  132. package/dist/components/form/counter/counter.d.ts +22 -18
  133. package/dist/components/form/counter/counter.js +59 -61
  134. package/dist/components/form/date-picker/date-picker.d.ts +27 -6
  135. package/dist/components/form/date-picker/date-picker.js +75 -54
  136. package/dist/components/form/input/input.d.ts +38 -39
  137. package/dist/components/form/input/input.js +85 -109
  138. package/dist/components/form/input-file/input-file.d.ts +26 -13
  139. package/dist/components/form/input-file/input-file.js +35 -35
  140. package/dist/components/form/input-file/input-file.styles.js +4 -4
  141. package/dist/components/form/input-phone/input-phone.d.ts +22 -5
  142. package/dist/components/form/input-phone/input-phone.js +41 -13
  143. package/dist/components/form/radio/radio-card.d.ts +1 -0
  144. package/dist/components/form/radio/radio-card.js +1 -0
  145. package/dist/components/form/radio/radio-list.d.ts +23 -7
  146. package/dist/components/form/radio/radio-list.js +47 -22
  147. package/dist/components/form/radio/radio.d.ts +1 -0
  148. package/dist/components/form/radio/radio.js +1 -0
  149. package/dist/components/form/rating/rating.d.ts +349 -0
  150. package/dist/components/form/rating/rating.js +665 -0
  151. package/dist/components/form/rating/rating.styles.d.ts +1 -0
  152. package/dist/components/form/rating/rating.styles.js +213 -0
  153. package/dist/components/form/search/search.d.ts +8 -8
  154. package/dist/components/form/search/search.js +23 -41
  155. package/dist/components/form/select/select.d.ts +23 -10
  156. package/dist/components/form/select/select.js +59 -41
  157. package/dist/components/form/shared-styles/listbox.styles.js +10 -0
  158. package/dist/components/form/slider/slider.d.ts +7 -8
  159. package/dist/components/form/slider/slider.js +9 -12
  160. package/dist/components/form/switch/switch.d.ts +1 -0
  161. package/dist/components/form/switch/switch.js +1 -0
  162. package/dist/components/form/textarea/textarea.d.ts +89 -23
  163. package/dist/components/form/textarea/textarea.js +192 -43
  164. package/dist/components/form/time-picker/time-picker-columns.d.ts +2 -2
  165. package/dist/components/form/time-picker/time-picker-columns.js +8 -8
  166. package/dist/components/form/time-picker/time-picker.d.ts +24 -8
  167. package/dist/components/form/time-picker/time-picker.js +59 -38
  168. package/dist/components/layout/animate/animate.js +1 -1
  169. package/dist/components/layout/animate/animate.styles.js +2 -2
  170. package/dist/components/layout/divider/divider.js +1 -1
  171. package/dist/components/layout/divider/divider.styles.js +1 -1
  172. package/dist/components/loader/loader/loader.js +2 -2
  173. package/dist/components/loader/loader/loader.styles.js +14 -12
  174. package/dist/components/loader/skeleton/skeleton.js +1 -1
  175. package/dist/components/navigation/carousel/carousel.d.ts +31 -7
  176. package/dist/components/navigation/carousel/carousel.js +74 -35
  177. package/dist/components/navigation/carousel/carousel.styles.js +5 -2
  178. package/dist/components/navigation/pagination/pagination.d.ts +23 -21
  179. package/dist/components/navigation/pagination/pagination.js +30 -53
  180. package/dist/components/navigation/sidebar/sidebar.d.ts +15 -13
  181. package/dist/components/navigation/sidebar/sidebar.js +21 -33
  182. package/dist/components/navigation/sidebar/sidebar.styles.js +5 -3
  183. package/dist/components/navigation/stepper/step.js +9 -8
  184. package/dist/components/navigation/stepper/stepper.js +12 -5
  185. package/dist/components/navigation/tabs/tab-group/tab-group.js +2 -2
  186. package/dist/components/navigation/tabs/tab-group/tab-group.styles.js +2 -2
  187. package/dist/components/navigation/toolbar/toolbar.d.ts +13 -13
  188. package/dist/components/navigation/toolbar/toolbar.js +20 -34
  189. package/dist/features/scheduler/calendar/calendar.js +1 -1
  190. package/dist/features/scheduler/scheduler/scheduler.d.ts +7 -7
  191. package/dist/features/scheduler/scheduler/scheduler.js +15 -24
  192. package/dist/features/scheduler/scheduler-event/scheduler-event.js +3 -3
  193. package/dist/features/scheduler/scheduler-event/scheduler-event.styles.js +1 -1
  194. package/dist/features/scheduler/scheduler-event-editor/scheduler-event-editor.d.ts +6 -4
  195. package/dist/features/scheduler/scheduler-event-editor/scheduler-event-editor.js +6 -7
  196. package/dist/i18n/en.d.ts +68 -0
  197. package/dist/i18n/en.js +68 -0
  198. package/dist/i18n/fr.js +68 -2
  199. package/dist/index.d.ts +2 -0
  200. package/dist/index.js +1 -0
  201. package/dist/mixins/button.mixin.js +3 -2
  202. package/dist/mixins/check.mixin.js +11 -10
  203. package/dist/mixins/disabled.mixin.d.ts +5 -0
  204. package/dist/mixins/disabled.mixin.js +21 -1
  205. package/dist/mixins/editable.mixin.js +28 -5
  206. package/dist/mixins/field-appearance.mixin.js +3 -2
  207. package/dist/mixins/form.mixin.d.ts +4 -0
  208. package/dist/mixins/form.mixin.js +87 -13
  209. package/dist/mixins/localizable.mixin.d.ts +1 -1
  210. package/dist/mixins/localizable.mixin.js +1 -1
  211. package/dist/mixins/radio.mixin.js +11 -10
  212. package/dist/mixins/readonly.mixin.d.ts +2 -1
  213. package/dist/mixins/readonly.mixin.js +10 -3
  214. package/dist/ssr/alert-ssr.css +187 -0
  215. package/dist/ssr/badge-ssr.css +67 -0
  216. package/dist/ssr/breadcrumb-ssr.css +41 -0
  217. package/dist/ssr/card-ssr.css +27 -15
  218. package/dist/ssr/carousel-ssr.css +238 -0
  219. package/dist/ssr/checkbox-ssr.css +67 -0
  220. package/dist/ssr/chip-ssr.css +242 -0
  221. package/dist/ssr/collapse-ssr.css +151 -0
  222. package/dist/ssr/field-ssr.css +163 -0
  223. package/dist/ssr/icon-ssr.css +266 -0
  224. package/dist/ssr/image-carousel-ssr.css +24 -0
  225. package/dist/ssr/links-ssr.css +7 -1
  226. package/dist/ssr/pagination-ssr.css +4 -0
  227. package/dist/ssr/rating-ssr.css +254 -0
  228. package/dist/ssr/sidebar-ssr.css +9 -1
  229. package/dist/ssr/skeleton-ssr.css +63 -0
  230. package/dist/ssr/tabs-ssr.css +129 -0
  231. package/dist/ssr/toggle-group-ssr.css +182 -0
  232. package/dist/ssr/toolbar-ssr.css +31 -2
  233. package/dist/utils/implicit-submission.utils.d.ts +18 -0
  234. package/dist/utils/implicit-submission.utils.js +79 -0
  235. package/dist/utils/listbox-options.utils.d.ts +11 -0
  236. package/dist/utils/listbox-options.utils.js +41 -3
  237. package/package.json +26 -7
  238. package/dist/cdn/components/chunks/chunk-4PI6RDUS.js +0 -1
  239. package/dist/cdn/components/chunks/chunk-A3X4KD2X.js +0 -1
  240. package/dist/cdn/components/chunks/chunk-BQFJR2UP.js +0 -110
  241. package/dist/cdn/components/chunks/chunk-G5SBDQQ3.js +0 -1
  242. package/dist/cdn/components/chunks/chunk-KSZRQRN4.js +0 -1
  243. package/dist/cdn/components/chunks/chunk-PE4DAXHQ.js +0 -3
  244. package/dist/cdn/components/chunks/chunk-RS7TWEMQ.js +0 -1
  245. package/dist/cdn/components/chunks/chunk-VOTRXBDS.js +0 -38
@@ -21,6 +21,7 @@ import { findRichTextColor, formatRichText, getPlainTextLength, populateEditable
21
21
  import { formLabelsStyles } from "../shared-styles/form-labels.styles.js";
22
22
  import { textareaStyles } from "./textarea.styles.js";
23
23
  import { pickValidity } from "../../../utils/validity.utils.js";
24
+ import { LocalizableMixin, } from "../../../mixins/localizable.mixin.js";
24
25
  /**
25
26
  * Tag name of the textarea component.
26
27
  */
@@ -467,7 +468,7 @@ function getActiveColorName(root, kind) {
467
468
  * @internal
468
469
  */
469
470
  const Base = DisabledMixin(ValidatorsMixin(LitElement));
470
- const EunomiaTextareaMixinBase = FieldAppearanceMixin(FormLabelMixin(ReadonlyMixin(EditableMixin(FormMixin(Base)))));
471
+ const EunomiaTextareaMixinBase = LocalizableMixin(FieldAppearanceMixin(FormLabelMixin(ReadonlyMixin(EditableMixin(FormMixin(Base))))));
471
472
  /**
472
473
  * A multi-line text field, sharing its label, hint, and error chrome and
473
474
  * theming with the input component. It grows and shrinks to fit its
@@ -496,13 +497,14 @@ const EunomiaTextareaMixinBase = FieldAppearanceMixin(FormLabelMixin(ReadonlyMix
496
497
  * @prop {boolean} [readonly=false] - Whether the field is read only
497
498
  * @prop {boolean} [required=false] - Whether the field is required
498
499
  * @prop {boolean} [hideError=false] - Whether the errors are hidden. The hint stays visible
500
+ * @prop {boolean} [invalid=false] - Shows the field as invalid without any message, for an error displayed elsewhere
499
501
  * @prop {string} [error] - An error computed outside the field, by the form or by the server. While set, the field is invalid and shows this message right away
500
502
  * @prop {Array<import('../../../types/form-validators.type.js').Validators<string>>} validators - The list of validation rules applied to the field value
501
503
  * @prop {number} rows - The fixed number of visible rows. When omitted, the field automatically grows and shrinks its height to fit its content
502
504
  * @prop {boolean} [readonlyAvailable=false] - Whether the field can switch between a static display and an editable one
503
505
  * @attr {boolean} [readonly-available=false] - Whether the field can switch between a static display and an editable one
504
506
  * @prop {boolean} [formatting=false] - Switches the field to a rich text surface with a formatting toolbar above it, and, combined with readonlyAvailable, renders the static display as formatted rich text instead of raw source
505
- * @prop {string} [formatToolbarLabel='Text formatting'] - The accessible label of the bold, italic, and underline toggle group
507
+ * @prop {string} [formatToolbarLabel='Text formatting'] - The accessible label of the formatting toolbar
506
508
  * @prop {string} [formatBoldLabel='Bold'] - The accessible label of the bold toggle
507
509
  * @prop {string} [formatItalicLabel='Italic'] - The accessible label of the italic toggle
508
510
  * @prop {string} [formatUnderlineLabel='Underline'] - The accessible label of the underline toggle
@@ -517,9 +519,9 @@ const EunomiaTextareaMixinBase = FieldAppearanceMixin(FormLabelMixin(ReadonlyMix
517
519
  * @prop {string} [autocomplete='off'] - The native autocomplete attribute forwarded to the field
518
520
  * @prop {number} minlength - The native minimum length constraint forwarded to the field
519
521
  * @prop {number} maxlength - The field's maximum length. Forwarded natively when not formatting, and enforced manually otherwise. Either way, a live character counter is shown under the field
520
- * @prop {string} [emptyValueLabel='No value set'] - Text displayed in place of the value when readonly and empty
521
- * @prop {string} [confirmLabel='Save'] - The label of the confirm button in edit mode
522
- * @prop {string} [cancelLabel='Cancel'] - The label of the cancel button in edit mode
522
+ * @prop {string} [emptyValueLabel] - Text displayed in place of the value when readonly and empty. Defaults to the localized string for the current locale (English: "No value set")
523
+ * @prop {string} [confirmLabel] - The label of the confirm button in edit mode. Defaults to the localized string for the current locale (English: "Save")
524
+ * @prop {string} [cancelLabel] - The label of the cancel button in edit mode. Defaults to the localized string for the current locale (English: "Cancel")
523
525
  * @fires {ChangeEvent} eunchange - Fired on every value change, including one applied through the formatting toolbar
524
526
  * @fires {CommitEvent} euncommit - Fired when an edit is confirmed in readonlyAvailable mode
525
527
  * @cssprop [--field-background] - Sets the background color of the field
@@ -555,7 +557,7 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
555
557
  */
556
558
  this.formatting = false;
557
559
  /**
558
- * Accessible label of the Bold/Italic/Underline toggle group.
560
+ * Accessible label of the formatting toolbar.
559
561
  * @default Text formatting
560
562
  */
561
563
  this.formatToolbarLabel = "Text formatting";
@@ -625,21 +627,6 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
625
627
  * @default off
626
628
  */
627
629
  this.autocomplete = "off";
628
- /**
629
- * Text displayed in place of the value when readonly and empty.
630
- * @default No value set
631
- */
632
- this.emptyValueLabel = "No value set";
633
- /**
634
- * Label of the confirm button in edit mode.
635
- * @default Save
636
- */
637
- this.confirmLabel = "Save";
638
- /**
639
- * Label of the cancel button in edit mode.
640
- * @default Cancel
641
- */
642
- this.cancelLabel = "Cancel";
643
630
  /**
644
631
  * Which color picker (text-color or highlight) is currently open, if any.
645
632
  * @private
@@ -692,18 +679,11 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
692
679
  */
693
680
  this.pendingCaretNode = null;
694
681
  /**
695
- * Redirects focus to the native field whenever the host itself receives
696
- * it. The host stays in the tab order (`DisabledMixin`) rather than
697
- * being excluded via `tabindex="-1"` — for this form-associated
698
- * component, that turned out to break Tab from reaching the field
699
- * entirely, instead of just skipping the host. Redirecting keeps a
700
- * single, real tab stop from the user's perspective without touching
701
- * that tab order.
702
- * @private
682
+ * Index, among {@link toolbarControls}, of the control holding the
683
+ * toolbar's single Tab stop.
684
+ * @internal
703
685
  */
704
- this.handleHostFocus = () => {
705
- this.fieldEl?.focus();
706
- };
686
+ this.toolbarFocusIndex = 0;
707
687
  /**
708
688
  * Reads native HTML constraint validation from the underlying field
709
689
  * element (`required`, `minlength`, `maxlength`) when not `formatting` ;
@@ -914,6 +894,55 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
914
894
  this.closeColorPicker();
915
895
  }
916
896
  };
897
+ /**
898
+ * Keyboard support of the toolbar, following the toolbar pattern :
899
+ * Left/Right move between its controls (wrapping), Home/End jump to the
900
+ * first and last, and Enter/Space pick an alignment. Listened to in the
901
+ * capture phase, ahead of the alignment group's own arrow handling.
902
+ * Up/Down are left to the alignment group, which selects the next
903
+ * alignment.
904
+ *
905
+ * @param event the keyboard event.
906
+ * @private
907
+ */
908
+ this.handleToolbarKeydown = {
909
+ handleEvent: (event) => {
910
+ const controls = this.toolbarControls().filter((control) => !control.hasAttribute("disabled"));
911
+ const current = controls.indexOf(event.target);
912
+ if (current === -1) {
913
+ return;
914
+ }
915
+ const control = controls[current];
916
+ if ((event.key === "Enter" || event.key === " ") &&
917
+ control.closest("#align-toolbar")) {
918
+ event.preventDefault();
919
+ event.stopPropagation();
920
+ control.click();
921
+ return;
922
+ }
923
+ let next;
924
+ switch (event.key) {
925
+ case "ArrowRight":
926
+ next = (current + 1) % controls.length;
927
+ break;
928
+ case "ArrowLeft":
929
+ next = (current - 1 + controls.length) % controls.length;
930
+ break;
931
+ case "Home":
932
+ next = 0;
933
+ break;
934
+ case "End":
935
+ next = controls.length - 1;
936
+ break;
937
+ default:
938
+ return;
939
+ }
940
+ event.preventDefault();
941
+ event.stopPropagation();
942
+ controls[next].focus();
943
+ },
944
+ capture: true,
945
+ };
917
946
  }
918
947
  /**
919
948
  * The default value applied on connection and form reset. Overrides the
@@ -932,15 +961,11 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
932
961
  // @ts-expect-error — see comment above ; FormMixin's real setter exists.
933
962
  super.defaultValue = value;
934
963
  }
935
- connectedCallback() {
936
- super.connectedCallback?.();
937
- this.addEventListener("focus", this.handleHostFocus);
938
- }
939
964
  disconnectedCallback() {
940
- this.removeEventListener("focus", this.handleHostFocus);
941
965
  document.removeEventListener("click", this.handleOutsideClick, {
942
966
  capture: true,
943
967
  });
968
+ clearTimeout(this.toolbarRovingTimer);
944
969
  super.disconnectedCallback?.();
945
970
  }
946
971
  /**
@@ -980,6 +1005,7 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
980
1005
  }
981
1006
  return;
982
1007
  }
1008
+ this.scheduleToolbarRoving();
983
1009
  const shouldSync = ((changedProperties.has("editing") && this.editing) ||
984
1010
  (changedProperties.has("formatting") && this.formatting) ||
985
1011
  (changedProperties.has("value") &&
@@ -1013,6 +1039,14 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1013
1039
  }
1014
1040
  return { validity: {} };
1015
1041
  }
1042
+ /**
1043
+ * The host is never a tab stop of its own : sequential navigation goes
1044
+ * straight to the controls inside, in both directions, and
1045
+ * {@link focus} covers a direct call on the host.
1046
+ */
1047
+ get hostTabStop() {
1048
+ return false;
1049
+ }
1016
1050
  /**
1017
1051
  * Returns the field element to focus/anchor on validation errors.
1018
1052
  *
@@ -1284,6 +1318,63 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1284
1318
  document.addEventListener("click", this.handleOutsideClick, {
1285
1319
  capture: true,
1286
1320
  });
1321
+ void this.updateComplete.then(() => {
1322
+ const swatches = this.colorSwatches();
1323
+ (swatches.find((swatch) => swatch.ariaChecked === "true") ?? swatches[0])?.focus();
1324
+ });
1325
+ }
1326
+ /**
1327
+ * The swatches of the open color picker, in display order.
1328
+ *
1329
+ * @returns the swatch buttons, empty while no picker is open.
1330
+ * @private
1331
+ */
1332
+ colorSwatches() {
1333
+ return Array.from(this.shadowRoot?.querySelectorAll(".color-picker-panel .color-swatch") ?? []);
1334
+ }
1335
+ /**
1336
+ * Keyboard support of the open color picker, following the menu pattern
1337
+ * : arrows move between swatches (wrapping), Home/End jump to the first
1338
+ * and last, Escape closes it, and Tab closes it before leaving it. Both
1339
+ * return the focus to the picker's trigger.
1340
+ *
1341
+ * @param event the keyboard event.
1342
+ * @private
1343
+ */
1344
+ handleColorPickerKeydown(event) {
1345
+ const panel = event.currentTarget;
1346
+ const trigger = panel.previousElementSibling;
1347
+ if (event.key === "Escape" || event.key === "Tab") {
1348
+ if (event.key === "Escape") {
1349
+ event.preventDefault();
1350
+ }
1351
+ this.closeColorPicker();
1352
+ trigger?.focus();
1353
+ return;
1354
+ }
1355
+ const swatches = this.colorSwatches();
1356
+ const current = swatches.indexOf(this.shadowRoot?.activeElement);
1357
+ let next;
1358
+ switch (event.key) {
1359
+ case "ArrowRight":
1360
+ case "ArrowDown":
1361
+ next = (current + 1) % swatches.length;
1362
+ break;
1363
+ case "ArrowLeft":
1364
+ case "ArrowUp":
1365
+ next = (current - 1 + swatches.length) % swatches.length;
1366
+ break;
1367
+ case "Home":
1368
+ next = 0;
1369
+ break;
1370
+ case "End":
1371
+ next = swatches.length - 1;
1372
+ break;
1373
+ default:
1374
+ return;
1375
+ }
1376
+ event.preventDefault();
1377
+ swatches[next]?.focus();
1287
1378
  }
1288
1379
  /**
1289
1380
  * Closes whichever color picker is open, if any.
@@ -1329,6 +1420,56 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1329
1420
  this.closeColorPicker();
1330
1421
  void this.updateComplete.then(() => this.fieldEl?.focus());
1331
1422
  }
1423
+ /**
1424
+ * The toolbar's controls, in visual order : every format and alignment
1425
+ * toggle, then both color picker triggers.
1426
+ *
1427
+ * @returns the controls, empty while the toolbar isn't rendered.
1428
+ * @private
1429
+ */
1430
+ toolbarControls() {
1431
+ return Array.from(this.shadowRoot?.querySelectorAll("#toolbar-groups eun-toggle-item, #toolbar-groups .color-picker-trigger") ?? []);
1432
+ }
1433
+ /**
1434
+ * Applies the toolbar's roving `tabindex` once the toggle groups have
1435
+ * applied their own (which they do after their items' updates), so the
1436
+ * whole toolbar stays a single Tab stop.
1437
+ * @private
1438
+ */
1439
+ scheduleToolbarRoving() {
1440
+ clearTimeout(this.toolbarRovingTimer);
1441
+ this.toolbarRovingTimer = setTimeout(() => this.applyToolbarRoving());
1442
+ }
1443
+ /**
1444
+ * Makes the control at {@link toolbarFocusIndex} the toolbar's only Tab
1445
+ * stop. Left alone while the toolbar is disabled, every control then
1446
+ * being out of the Tab order already.
1447
+ * @private
1448
+ */
1449
+ applyToolbarRoving() {
1450
+ if (this.disabled || this.readonly) {
1451
+ return;
1452
+ }
1453
+ const controls = this.toolbarControls();
1454
+ const active = Math.min(this.toolbarFocusIndex, controls.length - 1);
1455
+ controls.forEach((control, index) => {
1456
+ control.setAttribute("tabindex", index === active ? "0" : "-1");
1457
+ });
1458
+ }
1459
+ /**
1460
+ * Remembers the toolbar control receiving the focus, so Tab comes back
1461
+ * to it.
1462
+ *
1463
+ * @param event the focus event.
1464
+ * @private
1465
+ */
1466
+ handleToolbarFocusIn(event) {
1467
+ const index = this.toolbarControls().indexOf(event.target);
1468
+ if (index !== -1 && index !== this.toolbarFocusIndex) {
1469
+ this.toolbarFocusIndex = index;
1470
+ this.applyToolbarRoving();
1471
+ }
1472
+ }
1332
1473
  /**
1333
1474
  * Renders the formatting toolbar, shown above the field itself (never
1334
1475
  * above the readonly display) when `formatting` is set.
@@ -1342,11 +1483,14 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1342
1483
  return html `
1343
1484
  <div
1344
1485
  id="toolbar-groups"
1486
+ role="toolbar"
1487
+ aria-label=${this.formatToolbarLabel}
1345
1488
  @mousedown=${(event) => event.preventDefault()}
1489
+ @focusin=${this.handleToolbarFocusIn}
1490
+ @keydown=${this.handleToolbarKeydown}
1346
1491
  >
1347
1492
  <eun-toggle-group
1348
1493
  id="toolbar"
1349
- aria-label=${this.formatToolbarLabel}
1350
1494
  ?disabled=${toolbarDisabled}
1351
1495
  @eunchange=${this.handleToolbarChange}
1352
1496
  >
@@ -1422,7 +1566,7 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1422
1566
  <button
1423
1567
  type="button"
1424
1568
  class="color-picker-trigger"
1425
- aria-haspopup="true"
1569
+ aria-haspopup="menu"
1426
1570
  aria-expanded=${isOpen ? "true" : "false"}
1427
1571
  aria-label=${label}
1428
1572
  ?disabled=${toolbarDisabled}
@@ -1439,12 +1583,13 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1439
1583
  class="color-picker-panel"
1440
1584
  role="menu"
1441
1585
  aria-label=${label}
1442
- @keydown=${(event) => event.key === "Escape" && this.closeColorPicker()}
1586
+ @keydown=${this.handleColorPickerKeydown}
1443
1587
  >
1444
1588
  <button
1445
1589
  type="button"
1446
1590
  class="color-swatch clear"
1447
1591
  role="menuitemradio"
1592
+ tabindex="-1"
1448
1593
  aria-checked=${activeName === null ? "true" : "false"}
1449
1594
  aria-label=${this.formatColorClearLabel}
1450
1595
  @click=${() => this.selectColor(kind, null)}
@@ -1454,6 +1599,7 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1454
1599
  type="button"
1455
1600
  class="color-swatch"
1456
1601
  role="menuitemradio"
1602
+ tabindex="-1"
1457
1603
  aria-checked=${activeName === color.name
1458
1604
  ? "true"
1459
1605
  : "false"}
@@ -1520,7 +1666,10 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1520
1666
  ? formatRichText(this.value)
1521
1667
  : html `<span
1522
1668
  class=${classMap({ "plain-value": true, empty: !hasValue })}
1523
- >${hasValue ? this.value : this.emptyValueLabel}</span
1669
+ >${hasValue
1670
+ ? this.value
1671
+ : (this.emptyValueLabel ??
1672
+ this.dictionary.common.noValue)}</span
1524
1673
  >`}
1525
1674
  </div>
1526
1675
  `;
@@ -1626,7 +1775,7 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1626
1775
  rounded
1627
1776
  type="button"
1628
1777
  @click=${this.confirmEdit}
1629
- >${this.confirmLabel}</eun-button
1778
+ >${this.confirmLabel ?? this.dictionary.common.save}</eun-button
1630
1779
  >
1631
1780
  <eun-button
1632
1781
  class="cancel"
@@ -1636,7 +1785,7 @@ let EunomiaTextarea = class EunomiaTextarea extends EunomiaTextareaMixinBase {
1636
1785
  rounded
1637
1786
  type="button"
1638
1787
  @click=${this.cancelEdit}
1639
- >${this.cancelLabel}</eun-button
1788
+ >${this.cancelLabel ?? this.dictionary.common.cancel}</eun-button
1640
1789
  >
1641
1790
  </div>
1642
1791
  `)}
@@ -35,8 +35,8 @@ export interface TimePickerColumnsProps {
35
35
  ariaLabelHour?: string;
36
36
  ariaLabelMinute?: string;
37
37
  ariaLabelPeriod?: string;
38
- ariaLabelIncrement?: string;
39
- ariaLabelDecrement?: string;
38
+ incrementLabel?: string;
39
+ decrementLabel?: string;
40
40
  onHourChange: (hour24: number) => void;
41
41
  onMinuteChange: (minute: number) => void;
42
42
  onPeriodChange: (period: Period) => void;
@@ -73,8 +73,8 @@ export function renderTimePickerColumns(props) {
73
73
  disabled,
74
74
  noAnimation,
75
75
  label: props.ariaLabelHour ?? "Hour",
76
- ariaLabelIncrement: props.ariaLabelIncrement ?? "Increase hour",
77
- ariaLabelDecrement: props.ariaLabelDecrement ?? "Decrease hour",
76
+ incrementLabel: props.incrementLabel ?? "Increase hour",
77
+ decrementLabel: props.decrementLabel ?? "Decrease hour",
78
78
  min: hourMin,
79
79
  max: hourMax,
80
80
  current: display.hour,
@@ -89,8 +89,8 @@ export function renderTimePickerColumns(props) {
89
89
  disabled,
90
90
  noAnimation,
91
91
  label: props.ariaLabelMinute ?? "Minute",
92
- ariaLabelIncrement: props.ariaLabelIncrement ?? "Increase minute",
93
- ariaLabelDecrement: props.ariaLabelDecrement ?? "Decrease minute",
92
+ incrementLabel: props.incrementLabel ?? "Increase minute",
93
+ decrementLabel: props.decrementLabel ?? "Decrease minute",
94
94
  min: 0,
95
95
  max: 59,
96
96
  current: minute,
@@ -106,8 +106,8 @@ export function renderTimePickerColumns(props) {
106
106
  disabled,
107
107
  noAnimation,
108
108
  label: props.ariaLabelPeriod ?? "AM/PM",
109
- ariaLabelIncrement: props.ariaLabelIncrement ?? "Toggle AM/PM",
110
- ariaLabelDecrement: props.ariaLabelDecrement ?? "Toggle AM/PM",
109
+ incrementLabel: props.incrementLabel ?? "Toggle AM/PM",
110
+ decrementLabel: props.decrementLabel ?? "Toggle AM/PM",
111
111
  min: 0,
112
112
  max: 1,
113
113
  current: period === "AM" ? 0 : 1,
@@ -164,7 +164,7 @@ function renderColumn(config) {
164
164
  type="button"
165
165
  class="tp-arrow tp-arrow-up"
166
166
  tabindex="-1"
167
- aria-label=${config.ariaLabelIncrement}
167
+ aria-label=${config.incrementLabel}
168
168
  ?disabled=${disabled}
169
169
  @click=${() => onStep(1)}
170
170
  >
@@ -194,7 +194,7 @@ function renderColumn(config) {
194
194
  type="button"
195
195
  class="tp-arrow tp-arrow-down"
196
196
  tabindex="-1"
197
- aria-label=${config.ariaLabelDecrement}
197
+ aria-label=${config.decrementLabel}
198
198
  ?disabled=${disabled}
199
199
  @click=${() => onStep(-1)}
200
200
  >
@@ -65,14 +65,15 @@ declare const EunomiaTimePickerMixinBase: Constructor<EunomiaTimePickerBase>;
65
65
  * @prop {boolean} [readonly=false] - Whether the field is read only
66
66
  * @prop {boolean} [required=false] - Whether the field is required
67
67
  * @prop {boolean} [hideError=false] - Whether the errors are hidden. The hint stays visible
68
+ * @prop {boolean} [invalid=false] - Shows the field as invalid without any message, for an error displayed elsewhere
68
69
  * @prop {string} [error] - An error computed outside the field, by the form or by the server. While set, the field is invalid and shows this message right away
69
70
  * @prop {Array<Validators<Date | null>>} validators - The list of custom validation rules applied to the value
70
71
  * @prop {string} [applyLabel='Apply'] - The label of the mobile modal's confirm button
71
72
  * @attr {string} [apply-label='Apply'] - The label of the mobile modal's confirm button
72
- * @prop {string} [cancelLabel='Cancel'] - The label of the mobile modal's cancel button
73
- * @attr {string} [cancel-label='Cancel'] - The label of the mobile modal's cancel button
74
- * @prop {string} [ariaLabelClock='Open clock'] - The accessible label of the trailing clock button
75
- * @attr {string} [aria-label-clock='Open clock'] - The accessible label of the trailing clock button
73
+ * @prop {string} [cancelLabel] - The label of the mobile modal's cancel button. Defaults to the localized string for the current locale (English: "Cancel")
74
+ * @attr {string} [cancel-label] - The label of the mobile modal's cancel button. Defaults to the localized string for the current locale (English: "Cancel")
75
+ * @prop {string} [clockLabel] - The accessible label of the trailing clock button. Defaults to the localized string for the current locale (English: "Open clock")
76
+ * @attr {string} [clock-label] - The accessible label of the trailing clock button. Defaults to the localized string for the current locale (English: "Open clock")
76
77
  * @prop {string} [hourPlaceholder='hh'] - The placeholder shown in the empty hour segment
77
78
  * @attr {string} [hour-placeholder='hh'] - The placeholder shown in the empty hour segment
78
79
  * @prop {string} [minutePlaceholder='mm'] - The placeholder shown in the empty minute segment
@@ -186,14 +187,14 @@ export declare class EunomiaTimePicker extends EunomiaTimePickerMixinBase {
186
187
  applyLabel: string;
187
188
  /**
188
189
  * Label of the mobile modal's cancel button.
189
- * @default Cancel
190
+ * Falls back to the localized string for the current locale when unset.
190
191
  */
191
- cancelLabel: string;
192
+ cancelLabel?: string;
192
193
  /**
193
194
  * Accessible label of the trailing clock button.
194
- * @default Open clock
195
+ * Falls back to the localized string for the current locale when unset.
195
196
  */
196
- ariaLabelClock: string;
197
+ clockLabel?: string;
197
198
  /**
198
199
  * Placeholder shown in the empty hour segment.
199
200
  * @default hh
@@ -227,6 +228,15 @@ export declare class EunomiaTimePicker extends EunomiaTimePickerMixinBase {
227
228
  * @internal
228
229
  */
229
230
  private isOpen;
231
+ constructor();
232
+ /**
233
+ * Submits the owning form on Enter in one of the field's segments, as a
234
+ * native time input does, since the browser never does it from a
235
+ * shadow root. Left alone while the panel is open, and on keys a
236
+ * segment already handles, such as Enter toggling the AM/PM segment.
237
+ * @private
238
+ */
239
+ private readonly handleImplicitSubmission;
230
240
  /**
231
241
  * Whether the mobile modal is open.
232
242
  * @internal
@@ -327,6 +337,12 @@ export declare class EunomiaTimePicker extends EunomiaTimePickerMixinBase {
327
337
  * @returns validity state and optional message.
328
338
  */
329
339
  checkLocalValidators: () => Validity;
340
+ /**
341
+ * The host is never a tab stop of its own : sequential navigation goes
342
+ * straight to the controls inside, in both directions, and
343
+ * {@link focus} covers a direct call on the host.
344
+ */
345
+ protected get hostTabStop(): boolean;
330
346
  /**
331
347
  * Returns the first segment element to focus/anchor on validation errors.
332
348
  *