@aceshooting/lyra-ui 16.0.0 → 17.0.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 (296) hide show
  1. package/CHANGELOG.md +504 -0
  2. package/custom-elements.json +1 -1
  3. package/dist/cli/migration-contract.json +1 -1
  4. package/dist/components/agent-tools/browser-frame/browser-frame.class.d.ts +3 -3
  5. package/dist/components/agent-tools/browser-frame/browser-frame.class.js +2 -2
  6. package/dist/components/agent-tools/compare-panel/compare-panel.class.d.ts +2 -2
  7. package/dist/components/agent-tools/compare-panel/compare-panel.class.js +3 -3
  8. package/dist/components/agent-tools/confirm-bar/confirm-bar.class.d.ts +37 -13
  9. package/dist/components/agent-tools/confirm-bar/confirm-bar.class.js +2 -2
  10. package/dist/components/agent-tools/task-list/task-list.class.js +2 -2
  11. package/dist/components/agent-tools/tool-call-chip/tool-call-chip.class.d.ts +4 -0
  12. package/dist/components/agent-tools/tool-call-chip/tool-call-chip.class.js +2 -2
  13. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.d.ts +3 -3
  14. package/dist/components/agent-tools/tool-param-form/tool-param-form.class.js +1 -1
  15. package/dist/components/charts/chart/chart.class.d.ts +117 -17
  16. package/dist/components/charts/chart/chart.class.js +3 -3
  17. package/dist/components/charts/chart/histogram-bin.d.ts +5 -1
  18. package/dist/components/charts/chart/histogram-bin.js +1 -1
  19. package/dist/components/charts/chart/lite-chart.class.d.ts +9 -0
  20. package/dist/components/conversation/code-block/code-block.styles.js +1 -1
  21. package/dist/components/conversation/message-actions/message-actions.styles.js +1 -1
  22. package/dist/components/conversation/model-select/model-select.class.d.ts +13 -4
  23. package/dist/components/conversation/model-select/model-select.class.js +2 -1
  24. package/dist/components/conversation/model-select/model-select.styles.js +1 -1
  25. package/dist/components/conversation/streaming-text/streaming-text-base.class.d.ts +40 -2
  26. package/dist/components/conversation/streaming-text/streaming-text-base.class.js +2 -2
  27. package/dist/components/conversation/streaming-text/streaming-text-core.class.d.ts +5 -3
  28. package/dist/components/conversation/streaming-text/streaming-text-core.class.js +10 -0
  29. package/dist/components/conversation/streaming-text/streaming-text.class.d.ts +9 -3
  30. package/dist/components/conversation/streaming-text/streaming-text.class.js +10 -0
  31. package/dist/components/conversation/suggestion-chips/suggestion-chips.class.d.ts +30 -2
  32. package/dist/components/conversation/suggestion-chips/suggestion-chips.class.js +4 -3
  33. package/dist/components/conversation/suggestion-chips/suggestion-chips.styles.js +1 -1
  34. package/dist/components/conversation/transcript-feed/transcript-feed.class.js +1 -1
  35. package/dist/components/conversation/usage-badge/usage-badge-overlay-runtime.js +1 -1
  36. package/dist/components/conversation/usage-badge/usage-badge.class.d.ts +4 -0
  37. package/dist/components/conversation/voice-picker/voice-picker.class.d.ts +16 -4
  38. package/dist/components/conversation/voice-picker/voice-picker.class.js +2 -1
  39. package/dist/components/conversation/voice-picker/voice-picker.styles.js +1 -1
  40. package/dist/components/data/context-meter/context-meter.class.d.ts +23 -4
  41. package/dist/components/data/context-meter/context-meter.class.js +10 -7
  42. package/dist/components/data/context-meter/context-meter.styles.js +1 -1
  43. package/dist/components/data/data-grid/data-grid.class.d.ts +5 -2
  44. package/dist/components/data/data-grid/data-grid.class.js +1 -1
  45. package/dist/components/data/flow-canvas/flow-canvas.class.d.ts +32 -5
  46. package/dist/components/data/flow-canvas/flow-canvas.class.js +3 -1
  47. package/dist/components/data/flow-canvas/flow-canvas.styles.js +1 -1
  48. package/dist/components/data/flow-canvas/flow-model.js +1 -1
  49. package/dist/components/data/flow-canvas/flow-types.d.ts +10 -1
  50. package/dist/components/data/gauge/gauge.class.d.ts +15 -2
  51. package/dist/components/data/gauge/gauge.class.js +20 -20
  52. package/dist/components/data/gauge/gauge.styles.js +1 -1
  53. package/dist/components/data/graph-query-builder/graph-query-builder.class.d.ts +14 -5
  54. package/dist/components/data/graph-query-builder/graph-query-builder.class.js +2 -2
  55. package/dist/components/data/sequence-strip/sequence-strip.class.d.ts +28 -2
  56. package/dist/components/data/sequence-strip/sequence-strip.class.js +3 -2
  57. package/dist/components/data/sequence-strip/sequence-strip.styles.js +1 -1
  58. package/dist/components/data/table/table.class.d.ts +155 -30
  59. package/dist/components/data/table/table.class.js +6 -4
  60. package/dist/components/data/table/table.styles.js +1 -1
  61. package/dist/components/data/timeline/timeline-item.class.d.ts +9 -1
  62. package/dist/components/data/timeline/timeline-item.class.js +2 -2
  63. package/dist/components/data/word-cloud/word-cloud.class.js +1 -1
  64. package/dist/components/data/word-cloud/word-cloud.styles.js +1 -1
  65. package/dist/components/forms/button/button.class.d.ts +30 -1
  66. package/dist/components/forms/button/button.class.js +2 -2
  67. package/dist/components/forms/checkbox/checkbox.class.d.ts +8 -6
  68. package/dist/components/forms/checkbox/checkbox.class.js +2 -2
  69. package/dist/components/forms/checkbox-group/checkbox-group.class.d.ts +7 -5
  70. package/dist/components/forms/checkbox-group/checkbox-group.class.js +1 -1
  71. package/dist/components/forms/color-picker/color-picker.class.d.ts +16 -2
  72. package/dist/components/forms/color-picker/color-picker.class.js +2 -2
  73. package/dist/components/forms/color-picker/color-picker.styles.js +1 -1
  74. package/dist/components/forms/combobox/combobox.class.d.ts +43 -8
  75. package/dist/components/forms/combobox/combobox.class.js +2 -2
  76. package/dist/components/forms/date-picker/date-input.class.d.ts +4 -0
  77. package/dist/components/forms/date-picker/date-input.class.js +1 -1
  78. package/dist/components/forms/icon-button/icon-button.class.d.ts +20 -3
  79. package/dist/components/forms/icon-button/icon-button.class.js +1 -1
  80. package/dist/components/forms/icon-button/icon-button.styles.js +1 -1
  81. package/dist/components/forms/input/input.class.d.ts +5 -2
  82. package/dist/components/forms/input/input.class.js +1 -1
  83. package/dist/components/forms/input/time-input.class.d.ts +4 -0
  84. package/dist/components/forms/input/time-input.class.js +1 -1
  85. package/dist/components/forms/locale-picker/locale-picker.class.d.ts +11 -5
  86. package/dist/components/forms/locale-picker/locale-picker.class.js +1 -1
  87. package/dist/components/forms/otp-input/otp-input.class.d.ts +7 -2
  88. package/dist/components/forms/otp-input/otp-input.class.js +2 -2
  89. package/dist/components/forms/radio/radio-button.class.d.ts +2 -1
  90. package/dist/components/forms/radio/radio-group.class.d.ts +9 -4
  91. package/dist/components/forms/radio/radio-group.class.js +1 -1
  92. package/dist/components/forms/radio/radio.class.d.ts +13 -7
  93. package/dist/components/forms/radio/radio.class.js +1 -1
  94. package/dist/components/forms/rubric-form/rubric-form.class.d.ts +16 -6
  95. package/dist/components/forms/rubric-form/rubric-form.class.js +2 -2
  96. package/dist/components/forms/select/select.class.d.ts +19 -8
  97. package/dist/components/forms/select/select.class.js +2 -2
  98. package/dist/components/forms/slider/slider.class.d.ts +4 -2
  99. package/dist/components/forms/slider/slider.class.js +1 -1
  100. package/dist/components/forms/switch/switch.class.d.ts +8 -6
  101. package/dist/components/forms/switch/switch.class.js +1 -1
  102. package/dist/components/forms/textarea/textarea.class.d.ts +5 -3
  103. package/dist/components/forms/textarea/textarea.class.js +1 -1
  104. package/dist/components/forms/time-range/time-range.class.d.ts +12 -7
  105. package/dist/components/forms/time-range/time-range.class.js +1 -1
  106. package/dist/components/forms/time-range/time-range.styles.js +1 -1
  107. package/dist/components/forms/token-input/token-input.class.d.ts +6 -4
  108. package/dist/components/forms/token-input/token-input.class.js +1 -1
  109. package/dist/components/layout/app-rail/app-rail-item.class.d.ts +109 -4
  110. package/dist/components/layout/app-rail/app-rail-item.class.js +34 -29
  111. package/dist/components/layout/app-rail/app-rail-item.styles.js +1 -1
  112. package/dist/components/layout/app-rail/app-rail.class.d.ts +25 -3
  113. package/dist/components/layout/app-rail/app-rail.styles.js +1 -1
  114. package/dist/components/layout/app-rail-group/app-rail-group.class.d.ts +2 -2
  115. package/dist/components/layout/app-rail-group/app-rail-group.class.js +2 -2
  116. package/dist/components/layout/carousel/carousel.class.d.ts +1 -1
  117. package/dist/components/layout/carousel/carousel.class.js +1 -1
  118. package/dist/components/layout/details/accordion.class.d.ts +2 -2
  119. package/dist/components/layout/details/accordion.class.js +2 -2
  120. package/dist/components/layout/filter-bar/filter-bar-register.d.ts +1 -0
  121. package/dist/components/layout/filter-bar/filter-bar-register.js +1 -0
  122. package/dist/components/layout/filter-bar/filter-bar.class.d.ts +85 -10
  123. package/dist/components/layout/filter-bar/filter-bar.class.js +7 -4
  124. package/dist/components/layout/menu/menu-item.class.d.ts +3 -3
  125. package/dist/components/layout/menu/menu-item.class.js +3 -3
  126. package/dist/components/layout/menu/menu.class.d.ts +5 -1
  127. package/dist/components/layout/menu/menu.class.js +2 -2
  128. package/dist/components/layout/reorder-list/reorder-item.styles.js +1 -1
  129. package/dist/components/layout/virtual-list/virtual-list.class.js +1 -1
  130. package/dist/components/media/attachment-trigger/attachment-trigger.styles.js +1 -1
  131. package/dist/components/media/avatar-group/avatar-group.class.d.ts +12 -1
  132. package/dist/components/media/avatar-group/avatar-group.class.js +2 -2
  133. package/dist/components/media/drop-zone/drop-zone.class.d.ts +32 -11
  134. package/dist/components/media/drop-zone/drop-zone.class.js +2 -2
  135. package/dist/components/media/file-input/file-input.class.d.ts +40 -19
  136. package/dist/components/media/file-input/file-input.class.js +2 -2
  137. package/dist/components/overlays/callout/callout.styles.js +1 -1
  138. package/dist/components/overlays/dialog/dialog.styles.js +1 -1
  139. package/dist/components/overlays/overlay/dropdown.class.d.ts +13 -3
  140. package/dist/components/overlays/overlay/dropdown.class.js +2 -2
  141. package/dist/components/overlays/overlay/popover.class.d.ts +12 -3
  142. package/dist/components/overlays/overlay/popover.class.js +2 -2
  143. package/dist/components/overlays/rating/rating.class.d.ts +9 -7
  144. package/dist/components/overlays/rating/rating.class.js +1 -1
  145. package/dist/components/retrieval/citation-badge/citation-badge.class.d.ts +5 -1
  146. package/dist/components/retrieval/citation-badge/citation-badge.class.js +1 -1
  147. package/dist/components/retrieval/embedding-explorer/embedding-explorer.styles.js +1 -1
  148. package/dist/components/retrieval/entity-chip/entity-chip.class.d.ts +5 -1
  149. package/dist/components/retrieval/entity-chip/entity-chip.class.js +1 -1
  150. package/dist/components/retrieval/graph-legend/graph-legend.styles.js +1 -1
  151. package/dist/components/retrieval/retrieval-value-format.js +1 -1
  152. package/dist/components/retrieval/source-list/source-list.styles.js +1 -1
  153. package/dist/components/utility/copy-button/copy-button.class.d.ts +23 -11
  154. package/dist/components/utility/copy-button/copy-button.class.js +2 -2
  155. package/dist/components/utility/copy-button/copy-button.styles.js +1 -1
  156. package/dist/components/utility/diff-view/diff-view.styles.js +1 -1
  157. package/dist/components/utility/export-button/export-button.class.d.ts +4 -0
  158. package/dist/components/utility/export-button/export-button.class.js +1 -1
  159. package/dist/components/utility/json-viewer/json-viewer.styles.js +1 -1
  160. package/dist/components/utility/known-date/known-date.class.js +1 -1
  161. package/dist/components/utility/mention-popover/mention-popover.class.d.ts +38 -3
  162. package/dist/components/utility/mention-popover/mention-popover.class.js +2 -1
  163. package/dist/components/utility/mention-popover/mention-popover.styles.js +1 -1
  164. package/dist/components/utility/poll-status/poll-status.styles.js +1 -1
  165. package/dist/components/utility/tour/tour.class.d.ts +4 -0
  166. package/dist/components/utility/tour/tour.class.js +1 -1
  167. package/dist/components/utility/tour/tour.styles.js +1 -1
  168. package/dist/components/viewers/document-preview/document-preview.class.js +2 -2
  169. package/dist/components/viewers/docx-viewer/docx-viewer.class.js +2 -2
  170. package/dist/components/viewers/ebook-viewer/ebook-viewer.class.js +2 -2
  171. package/dist/components/viewers/highlight-layer/highlight-layer.class.js +2 -2
  172. package/dist/components/viewers/notebook-viewer/notebook-viewer.class.js +2 -2
  173. package/dist/components/viewers/pdf-viewer/pdf-viewer.class.js +2 -2
  174. package/dist/components/viewers/pptx-viewer/pptx-viewer.class.js +2 -2
  175. package/dist/components/viewers/xml-viewer/xml-viewer.class.js +2 -2
  176. package/dist/custom-elements-jsx.d.ts +2 -2
  177. package/dist/events.d.ts +13 -12
  178. package/dist/internal/aggregate-file-limits.d.ts +33 -0
  179. package/dist/internal/aggregate-file-limits.js +1 -0
  180. package/dist/internal/catalog-picker.d.ts +15 -2
  181. package/dist/internal/catalog-picker.js +1 -1
  182. package/dist/internal/debounce-controller.d.ts +14 -0
  183. package/dist/internal/debounce-controller.js +1 -1
  184. package/dist/internal/default-strings.generated.d.ts +1 -1
  185. package/dist/internal/default-strings.generated.js +2 -2
  186. package/dist/internal/focus-navigation.d.ts +45 -0
  187. package/dist/internal/focus-navigation.js +1 -1
  188. package/dist/internal/form-associated.js +1 -1
  189. package/dist/internal/initial-slot-collection.d.ts +30 -0
  190. package/dist/internal/initial-slot-collection.js +1 -0
  191. package/dist/internal/intl-cache.js +1 -1
  192. package/dist/internal/invalid-event-alias.d.ts +46 -0
  193. package/dist/internal/invalid-event-alias.js +1 -1
  194. package/dist/internal/localization-runtime.d.ts +24 -0
  195. package/dist/internal/localization-runtime.js +1 -1
  196. package/dist/internal/localization-types.d.ts +1 -1
  197. package/dist/internal/localization.js +1 -1
  198. package/dist/internal/package-metadata.d.ts +1 -1
  199. package/dist/internal/package-metadata.js +1 -1
  200. package/dist/internal/positioning-strategy.d.ts +3 -1
  201. package/dist/internal/state-part.d.ts +49 -0
  202. package/dist/internal/state-part.js +1 -0
  203. package/dist/internal/variants.styles.js +1 -1
  204. package/dist/lyra.d.ts +1 -1
  205. package/dist/svelte.d.ts +2 -2
  206. package/dist/testing/index.d.ts +1 -1
  207. package/dist/testing/index.js +1 -1
  208. package/dist/testing/lyra-tag-event-map.d.ts +2 -2
  209. package/dist/testing/lyra-tag-event-map.js +1 -1
  210. package/dist/testing/wait-for-mount.d.ts +46 -0
  211. package/dist/testing/wait-for-mount.js +1 -0
  212. package/dist/theme/theme-bootstrap.js +1 -1
  213. package/dist/theme/theme.d.ts +11 -2
  214. package/dist/theme/theme.js +1 -1
  215. package/dist/translations/ar/layout.js +1 -1
  216. package/dist/translations/de/layout.js +1 -1
  217. package/dist/translations/es/layout.js +1 -1
  218. package/dist/translations/fa/layout.js +1 -1
  219. package/dist/translations/fr/layout.js +1 -1
  220. package/dist/translations/he/layout.js +1 -1
  221. package/dist/translations/it/layout.js +1 -1
  222. package/dist/translations/ja/layout.js +1 -1
  223. package/dist/translations/pt-BR/layout.js +1 -1
  224. package/dist/translations/ru/layout.js +1 -1
  225. package/dist/translations/zh-CN/layout.js +1 -1
  226. package/dist/utilities/format.d.ts +17 -0
  227. package/dist/utilities/format.js +1 -1
  228. package/dist/vue.d.ts +2 -2
  229. package/llms/components/lr-app-rail-group.md +87 -10
  230. package/llms/components/lr-app-rail-item.md +88 -11
  231. package/llms/components/lr-app-rail.md +88 -11
  232. package/llms/components/lr-attachment-trigger.md +21 -0
  233. package/llms/components/lr-bar-chart.md +3 -2
  234. package/llms/components/lr-bubble-chart.md +3 -2
  235. package/llms/components/lr-callout.md +10 -0
  236. package/llms/components/lr-chart.md +43 -12
  237. package/llms/components/lr-citation-badge.md +7 -1
  238. package/llms/components/lr-code-block.md +21 -0
  239. package/llms/components/lr-color-picker.md +12 -7
  240. package/llms/components/lr-combobox.md +13 -1
  241. package/llms/components/lr-confirm-bar.md +36 -7
  242. package/llms/components/lr-context-meter.md +17 -4
  243. package/llms/components/lr-date-input.md +7 -1
  244. package/llms/components/lr-date-picker.md +6 -0
  245. package/llms/components/lr-dialog.md +21 -0
  246. package/llms/components/lr-doughnut-chart.md +3 -2
  247. package/llms/components/lr-drawer.md +10 -0
  248. package/llms/components/lr-drop-zone.md +16 -7
  249. package/llms/components/lr-dropdown-item.md +7 -0
  250. package/llms/components/lr-entity-chip.md +7 -1
  251. package/llms/components/lr-export-button.md +7 -1
  252. package/llms/components/lr-file-input.md +21 -10
  253. package/llms/components/lr-filter-bar.md +91 -15
  254. package/llms/components/lr-flow-canvas.md +16 -9
  255. package/llms/components/lr-gauge.md +22 -2
  256. package/llms/components/lr-histogram.md +7 -2
  257. package/llms/components/lr-icon-button.md +15 -7
  258. package/llms/components/lr-input.md +3 -1
  259. package/llms/components/lr-line-chart.md +3 -2
  260. package/llms/components/lr-lite-chart.md +13 -0
  261. package/llms/components/lr-locale-picker.md +7 -1
  262. package/llms/components/lr-mention-popover.md +16 -3
  263. package/llms/components/lr-menu-item.md +7 -0
  264. package/llms/components/lr-menu.md +8 -1
  265. package/llms/components/lr-message-actions.md +10 -0
  266. package/llms/components/lr-model-select.md +8 -3
  267. package/llms/components/lr-native-time-input.md +8 -1
  268. package/llms/components/lr-number-input.md +8 -1
  269. package/llms/components/lr-option.md +12 -0
  270. package/llms/components/lr-otp-input.md +6 -0
  271. package/llms/components/lr-pie-chart.md +3 -2
  272. package/llms/components/lr-polar-area-chart.md +3 -2
  273. package/llms/components/lr-prompt-input.md +2 -2
  274. package/llms/components/lr-radar-chart.md +3 -2
  275. package/llms/components/lr-reorder-item.md +12 -0
  276. package/llms/components/lr-reorder-list.md +12 -0
  277. package/llms/components/lr-scatter-chart.md +3 -2
  278. package/llms/components/lr-sequence-strip.md +10 -4
  279. package/llms/components/lr-streaming-text-core.md +21 -8
  280. package/llms/components/lr-streaming-text.md +34 -4
  281. package/llms/components/lr-suggestion-chips.md +8 -4
  282. package/llms/components/lr-table.md +47 -10
  283. package/llms/components/lr-textarea.md +1 -1
  284. package/llms/components/lr-time-input.md +7 -1
  285. package/llms/components/lr-tool-call-chip.md +7 -1
  286. package/llms/components/lr-tour.md +7 -1
  287. package/llms/components/lr-usage-badge.md +7 -1
  288. package/llms/components/lr-voice-picker.md +7 -3
  289. package/llms/shared.md +169 -16
  290. package/llms/tokens.md +17 -1
  291. package/llms-full.txt +941 -147
  292. package/package.json +16 -2
  293. package/registrations.json +1 -1
  294. package/vscode-css-data.json +1 -1
  295. package/vscode-html-data.json +1 -1
  296. package/web-types.json +1 -1
@@ -102,6 +102,51 @@ export declare function focusFirstAvailable(targets:ComposedFocusRepairTargetSou
102
102
  */
103
103
  export declare function repairComposedFocus(owner:Element,fallbackTargets:ComposedFocusRepairTargetSource):boolean;
104
104
  /**
105
+ * Resolves once a reactive host has had a realistic chance to commit an update it scheduled
106
+ * during the task that just ran -- the exact window `deferComposedFocusRepair()` waits out before
107
+ * re-resolving a return-focus thunk. One microtask, then one animation frame:
108
+ *
109
+ * - A microtask covers Lit (this library's own components included), Vue's `nextTick`, and
110
+ * Svelte's `tick()` -- all three schedule their reactive flush as a microtask off the change
111
+ * that just happened, so by the time a microtask callback of our own runs, one already queued
112
+ * ahead of it (because the host's property write happened first, in the same synchronous turn
113
+ * that led here) has already committed its DOM mutation.
114
+ * - A following animation frame covers React's default automatic batching, which commits a
115
+ * click-driven state update synchronously before the browser's next paint rather than
116
+ * guaranteed inside a single microtask tick. `requestAnimationFrame` runs after the browser has
117
+ * finished any pending style/layout/paint work for the current frame, so a commit that landed
118
+ * "before paint" has necessarily already happened by the time this callback fires.
119
+ *
120
+ * One evaluation, not a poll loop: a return-focus thunk is "ask again once you have had a
121
+ * chance", not "keep asking until you succeed" -- see `deferComposedFocusRepair()`'s own doc
122
+ * comment for the give-up contract that depends on this being a single, bounded wait.
123
+ */
124
+ export declare function nextHostUpdateOpportunity():Promise<void>;
125
+ /**
126
+ * Captures a repair on `bridge` right now (the synchronous parking spot a terminal focus handoff
127
+ * already moved focus to, so there is no focus gap), then -- after `nextHostUpdateOpportunity()`
128
+ * -- calls `resolveTarget()` again and moves focus to whatever it names if that has since become
129
+ * connected and focusable, without overriding a newer, genuinely different focus move.
130
+ *
131
+ * This exists for exactly one shape: a return-focus thunk whose whole documented reason to exist
132
+ * is naming a control the host is expected to *re-create* on the way back (an async re-render), so
133
+ * calling it once, synchronously, at handoff time necessarily finds nothing yet. Call this only
134
+ * after that first synchronous resolution has already failed and landed focus on `bridge` --
135
+ * an immediately-resolving thunk or a plain element value never reaches this function, so
136
+ * behavior for those already-working cases is unchanged.
137
+ *
138
+ * Declines exactly as `applyComposedFocusRepair()` already does: focus that moved to some other
139
+ * real element outside `owner` in the meantime is left alone. Focus that was lost along with
140
+ * `owner`'s own branch (the host removed the bridge's entire component, dropping focus to
141
+ * `<body>`) is NOT treated as "moved on" -- that disappearance is precisely the case a deferred
142
+ * thunk exists to recover from.
143
+ *
144
+ * Bounded and quiet: exactly one deferred re-resolution; a target that still does not exist, is
145
+ * not connected, or refuses focus (`inert`, removed, hidden) simply leaves focus wherever the
146
+ * synchronous parking step already put it.
147
+ */
148
+ export declare function deferComposedFocusRepair(owner:Element,bridge:HTMLElement,resolveTarget:()=>HTMLElement|null):void;
149
+ /**
105
150
  * Iteratively collects composed focus targets with a shared depth/node budget. Programmatic mode
106
151
  * retains native and ARIA-managed actions after a roving owner assigns `tabindex=-1`; tabbable mode
107
152
  * models sequential browser order, including one stop per native radio group.
@@ -1 +1 @@
1
- import{composedParentElement,deepActiveElementIn}from"./active-element.js";import{isAriaTrue}from"./accessibility-visibility.js";import{asciiWhitespaceTokens}from"./ascii-whitespace.js";import{imageMapImageFor,isHtmlElement,isSvgElement}from"./dom-guards.js";const DEFAULT_FOCUS_MAX_DEPTH=256,DEFAULT_FOCUS_MAX_NODES=1e4,MAX_CONFIGURED_FOCUS_LIMIT=1e5,ARIA_WIDGET_ROLES=new Set(["button","checkbox","combobox","grid","gridcell","link","listbox","menu","menubar","menuitem","menuitemcheckbox","menuitemradio","option","radio","radiogroup","scrollbar","searchbox","separator","slider","spinbutton","switch","tab","tablist","textbox","tree","treegrid","treeitem"]),ARIA_NON_WIDGET_ROLES=new Set(["alert","alertdialog","application","article","banner","blockquote","caption","cell","code","columnheader","comment","complementary","contentinfo","definition","deletion","dialog","directory","document","emphasis","feed","figure","form","generic","group","heading","img","image","insertion","list","listitem","log","main","marquee","mark","math","meter","navigation","none","note","paragraph","presentation","progressbar","region","row","rowgroup","rowheader","search","sectionfooter","sectionheader","status","strong","subscript","suggestion","superscript","table","tabpanel","term","time","timer","toolbar","tooltip"]);function finiteFocusLimit(value,fallback){return Number.isFinite(value)?Math.min(MAX_CONFIGURED_FOCUS_LIMIT,Math.max(0,Math.floor(value))):fallback}function createFocusTraversalContext(options){return{elementStates:new Map,imageMapImages:new Map,maxDepth:finiteFocusLimit(options.maxDepth,DEFAULT_FOCUS_MAX_DEPTH),maxNodes:finiteFocusLimit(options.maxNodes,DEFAULT_FOCUS_MAX_NODES),reasons:new Set,workUnits:0}}function renderedElementState(element,imageMapImage){let style;try{style=element.ownerDocument.defaultView?.getComputedStyle(element)}catch{}return{display:style?.display,subtreeUnavailable:element.hasAttribute("hidden")||element.hasAttribute("inert")||isAriaTrue(element.getAttribute("aria-hidden"))||isAriaTrue(element.getAttribute("aria-disabled"))||!imageMapImage&&(style?.display==="none"||style?.contentVisibility==="hidden"),visibility:style?.visibility}}function consumeFocusWork(context){return context.workUnits>=context.maxNodes?(context.reasons.add("nodes"),!1):(context.workUnits+=1,!0)}function cachedRenderedElementState(context,element){let state=context.elementStates.get(element);return state||(state=renderedElementState(element,cachedImageMapImage(context,element)),context.elementStates.set(element,state)),state}function cachedImageMapImage(context,element){if(context.imageMapImages.has(element))return context.imageMapImages.get(element);const image=imageMapImageFor(element,{consume:()=>consumeFocusWork(context)});return context.imageMapImages.set(element,image),image}function isClosedDetailsBranch(details,branch,context){if(details.localName!=="details"||details.hasAttribute("open")||branch===null)return!1;for(const child of details.children){if(!consumeFocusWork(context))return!0;if(child.localName==="summary")return child!==branch}return!0}function composedAncestorsAvailable(element,context){let branch=element,ancestor=composedParentElement(element),depth=0;for(;ancestor;){if(!consumeFocusWork(context)||cachedRenderedElementState(context,ancestor).subtreeUnavailable||isClosedDetailsBranch(ancestor,branch,context))return!1;if(depth+=1,depth>context.maxDepth)return context.reasons.add("depth"),!1;branch=ancestor,ancestor=composedParentElement(ancestor)}return!0}function isRenderedFocusCandidate(context,element,state){const imageMapImage=cachedImageMapImage(context,element);if(isHtmlElement(element)&&element.localName==="area"&&!imageMapImage)return!1;if(imageMapImage){const imageState=cachedRenderedElementState(context,imageMapImage);return composedAncestorsAvailable(imageMapImage,context)&&!imageState.subtreeUnavailable&&isRenderedFocusCandidate(context,imageMapImage,imageState)}if(!element.isConnected||state.visibility==="hidden"||state.visibility==="collapse")return!1;const candidate=element;if(typeof candidate.checkVisibility=="function")try{return candidate.checkVisibility({contentVisibilityAuto:!0})}catch{return!1}return element.getClientRects().length>0}function hasAriaWidgetRole(element){for(const token of asciiWhitespaceTokens(element.getAttribute("role"))){const role=token.toLowerCase();if(ARIA_WIDGET_ROLES.has(role))return!0;if(ARIA_NON_WIDGET_ROLES.has(role))return!1}return!1}function isNativeAction(element){if(isSvgElement(element))return element.localName==="a"&&(element.hasAttribute("href")||element.hasAttributeNS("http://www.w3.org/1999/xlink","href"));switch(element.localName){case"a":return element.hasAttribute("href");case"area":{if(!element.hasAttribute("href"))return!1;let ancestor=element.parentElement;for(let depth=0;ancestor&&depth<=DEFAULT_FOCUS_MAX_DEPTH;depth+=1){if(ancestor.localName==="map")return!0;ancestor=ancestor.parentElement}return!1}case"audio":case"video":return element.hasAttribute("controls");case"button":case"embed":case"iframe":case"select":case"textarea":return!0;case"object":{const data=element.getAttribute("data");return data!==null&&data.trim()!==""}case"input":return element.type!=="hidden";case"summary":return element.matches("details > summary:first-of-type");default:return element.hasAttribute("contenteditable")&&element.isContentEditable&&!element.parentElement?.isContentEditable}}function isBrowserFocusElement(element){return isHtmlElement(element)||isSvgElement(element)}function isShadowRoot(root){return root.nodeType===11&&"host"in root}function isSemanticActionElement(element){return isBrowserFocusElement(element)&&(isNativeAction(element)||hasAriaWidgetRole(element))}function isActionableElement(element){return isSemanticActionElement(element)||isBrowserFocusElement(element)&&element.hasAttribute("tabindex")&&element.tabIndex>=0}function isComposedFocusAvailable(element,options={}){if(!isBrowserFocusElement(element))return!1;const context=createFocusTraversalContext(options);if(!consumeFocusWork(context)||!composedAncestorsAvailable(element,context))return!1;const state=cachedRenderedElementState(context,element);return state.subtreeUnavailable||element.matches(":disabled")?!1:isRenderedFocusCandidate(context,element,state)}function composedContains(container,candidate,maxDepth=DEFAULT_FOCUS_MAX_DEPTH){let current=candidate,depth=0;for(;current;){if(current===container)return!0;if(depth>=maxDepth)return!1;current=composedParentElement(current),depth+=1}return!1}function isComposedFocusRepairTargetList(value){return Array.isArray(value)}function resolveComposedFocusRepairTargets(source){const resolved=typeof source=="function"?source():source;if(!resolved)return[];if(!isComposedFocusRepairTargetList(resolved))return[resolved];const targets=[];for(const target of resolved)target&&targets.push(target);return targets}function captureComposedFocusRepair(owner,candidate){if(!candidate||candidate.ownerDocument!==owner.ownerDocument)return null;const activeElement=deepActiveElementIn(owner.ownerDocument);return!activeElement||!composedContains(owner,activeElement)?null:{activeElement,candidate,document:owner.ownerDocument,owner}}function applyComposedFocusRepair(snapshot,candidateOverride){const{document:ownerDocument,owner}=snapshot,targetSource=arguments.length<2?snapshot.candidate:candidateOverride,candidates=resolveComposedFocusRepairTargets(targetSource);if(candidates.length===0)return!1;const current=deepActiveElementIn(ownerDocument),lostWithBranch=current===null||current===ownerDocument.body||current===ownerDocument.documentElement;return current!==snapshot.activeElement&&!composedContains(owner,current)&&!lostWithBranch?!1:focusFirstAvailable(candidates.filter(candidate=>candidate.ownerDocument===ownerDocument))}function focusFirstAvailable(targets){for(const candidate of resolveComposedFocusRepairTargets(targets)){if(!isComposedFocusAvailable(candidate))continue;candidate.focus();const focused=deepActiveElementIn(candidate.ownerDocument);if(focused===candidate||composedContains(candidate,focused))return!0}return!1}function repairComposedFocus(owner,fallbackTargets){const activeElement=deepActiveElementIn(owner.ownerDocument);if(!activeElement||!composedContains(owner,activeElement))return!1;const candidates=resolveComposedFocusRepairTargets(fallbackTargets),[candidate]=candidates;return candidate?applyComposedFocusRepair({activeElement,candidate,document:owner.ownerDocument,owner},candidates):!1}function traverseComposedElements(root,options,include){const context=createFocusTraversalContext(options),{maxDepth,maxNodes}=context,elements=[],stack=[],visited=new Set,navigationScope={entries:[],nextOrder:0};if(maxNodes===0)return context.reasons.add("nodes"),{elements,navigationScope,reasons:context.reasons,visitedElements:0};const schedule=(element,depth,ancestorsAvailable,scope,workCharged=!1)=>{if(depth>maxDepth){context.reasons.add("depth");return}stack.push({ancestorsAvailable,depth,element,kind:"element",scope,workCharged})},scheduleChildren=(children,depth,ancestorsAvailable,scope)=>{if(children.length!==0){if(depth>maxDepth){context.reasons.add("depth");return}stack.push({ancestorsAvailable,children,depth,index:0,kind:"children",scope})}},scheduleSlotChildren=(slot,depth,ancestorsAvailable,scope)=>{if(depth>maxDepth){context.reasons.add("depth");return}const slotRoot=slot.getRootNode(),candidates=slotRoot.nodeType===11&&"host"in slotRoot?slotRoot.host.childNodes:[];stack.push({ancestorsAvailable,candidates,depth,fallback:slot.children,foundAssigned:!1,index:0,kind:"slot",scope,slot})},scheduleComposedChildren=(element,depth,ancestorsAvailable,scope)=>{if(element.localName==="slot"&&isHtmlElement(element)){scheduleSlotChildren(element,depth,ancestorsAvailable,scope);return}if(element.localName==="details"&&!element.hasAttribute("open")){for(const child of element.children){if(!consumeFocusWork(context))return;if(child.localName==="summary"){schedule(child,depth,ancestorsAvailable,scope,!0);return}}return}scheduleChildren(element.shadowRoot?.children??element.children,depth,ancestorsAvailable,scope)};if(isShadowRoot(root)){const shadowRoot=root,ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(shadowRoot.host,context),hostStateAvailable=consumeFocusWork(context)&&!cachedRenderedElementState(context,shadowRoot.host).subtreeUnavailable;scheduleChildren(shadowRoot.children,0,ancestorsAvailable&&hostStateAvailable,navigationScope)}else if(options.includeRoot===!1){const ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(root,context),ownAvailable=consumeFocusWork(context)&&!cachedRenderedElementState(context,root).subtreeUnavailable;scheduleComposedChildren(root,0,ancestorsAvailable&&ownAvailable,navigationScope)}else{const ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(root,context);schedule(root,0,ancestorsAvailable,navigationScope)}for(;stack.length>0;){const work=stack.pop();if(work.kind==="slot"){if(work.index>=work.candidates.length){work.foundAssigned||scheduleChildren(work.fallback,work.depth,work.ancestorsAvailable,work.scope);continue}if(!consumeFocusWork(context)){stack.length=0;break}const node=work.candidates[work.index],assigned=!!(node&&node.assignedSlot===work.slot);stack.push({...work,foundAssigned:work.foundAssigned||assigned,index:work.index+1}),node?.nodeType===1&&assigned&&schedule(node,work.depth,work.ancestorsAvailable,work.scope,!0);continue}if(work.kind==="children"){if(work.index>=work.children.length)continue;const element=work.children[work.index];stack.push({...work,index:work.index+1}),element&&schedule(element,work.depth,work.ancestorsAvailable,work.scope);continue}if(visited.has(work.element))continue;if(!work.workCharged&&!consumeFocusWork(context)){stack.length=0;break}visited.add(work.element);const state=cachedRenderedElementState(context,work.element),available=work.ancestorsAvailable&&!state.subtreeUnavailable,included=include(work.element,available,state,context);if(included&&elements.push(work.element),!available)continue;if(work.element.shadowRoot||work.element.localName==="slot"&&isHtmlElement(work.element)){const childScope={entries:[],nextOrder:0};work.scope.entries.push({childScope,delegatesFocus:!!work.element.shadowRoot?.delegatesFocus,order:work.scope.nextOrder++,suppressSequentialDescendants:work.element.hasAttribute("tabindex")&&work.element.tabIndex<0,target:included&&isBrowserFocusElement(work.element)?work.element:void 0}),scheduleComposedChildren(work.element,work.depth+1,!0,childScope);continue}included&&isBrowserFocusElement(work.element)&&work.scope.entries.push({order:work.scope.nextOrder++,target:work.element}),scheduleComposedChildren(work.element,work.depth+1,!0,work.scope)}return{elements,navigationScope,reasons:context.reasons,visitedElements:visited.size}}function isOverflowingTabStop(element){const view=element.ownerDocument.defaultView;if(!view)return!1;const{overflowX,overflowY}=view.getComputedStyle(element);return overflowX==="scroll"||overflowY==="scroll"||overflowY==="auto"&&element.scrollHeight>element.clientHeight?!0:overflowX==="auto"&&element.scrollWidth>element.clientWidth}function isTabbableCandidate(element){return element.hasAttribute("tabindex")?element.tabIndex>=0?!0:isHtmlElement(element)&&!isNativeAction(element)&&isOverflowingTabStop(element):isHtmlElement(element)&&element.hasAttribute("contenteditable")&&element.isContentEditable?!element.parentElement?.isContentEditable:isNativeAction(element)}function collapseRadioGroups(elements){const byRoot=new Map;for(const element of elements){if(!isHtmlElement(element)||element.localName!=="input")continue;const input=element;if(input.type!=="radio"||input.name==="")continue;const root=input.getRootNode();let byForm=byRoot.get(root);byForm||(byForm=new Map,byRoot.set(root,byForm));let byName=byForm.get(input.form);byName||(byName=new Map,byForm.set(input.form,byName));const group=byName.get(input.name);group?input.checked&&!group.checked&&(group.checked=input):byName.set(input.name,{checked:input.checked?input:void 0,first:input})}const tabStops=new Set;for(const byForm of byRoot.values())for(const byName of byForm.values())for(const group of byName.values())tabStops.add(group.checked??group.first);return elements.filter(element=>{if(!isHtmlElement(element)||element.localName!=="input")return!0;const input=element;return input.type!=="radio"||input.name===""||tabStops.has(input)})}function navigationEntryTabIndex(entry){return entry.target&&entry.target.tabIndex>0?entry.target.tabIndex:0}function flattenNavigationScope(scope,mode,retainedTargets){const orderedEntries=candidate=>mode==="tabbable"?[...candidate.entries].sort((first,second)=>{const firstTabIndex=navigationEntryTabIndex(first),secondTabIndex=navigationEntryTabIndex(second);return firstTabIndex>0!=secondTabIndex>0?firstTabIndex>0?-1:1:firstTabIndex>0&&firstTabIndex!==secondTabIndex?firstTabIndex-secondTabIndex:first.order-second.order}):candidate.entries,flattened=[],work=[{kind:"scope",scope}];for(;work.length>0;){const current=work.pop();if(current.kind==="target"){flattened.push(current.target);continue}const entries=orderedEntries(current.scope);for(let index=entries.length-1;index>=0;index-=1){const entry=entries[index];entry.childScope&&(mode!=="tabbable"||!entry.suppressSequentialDescendants)&&work.push({kind:"scope",scope:entry.childScope}),entry.target&&retainedTargets.has(entry.target)&&!entry.delegatesFocus&&work.push({kind:"target",target:entry.target})}}return flattened}function collectComposedFocusTargets(root,options={}){const mode=options.mode??"tabbable",traversed=traverseComposedElements(root,options,(candidate,available,state,context)=>!available||!isBrowserFocusElement(candidate)||candidate.matches(":disabled")||!isRenderedFocusCandidate(context,candidate,state)?!1:mode==="programmatic"?candidate.hasAttribute("tabindex")||isActionableElement(candidate):(candidate.hasAttribute("tabindex")||isActionableElement(candidate))&&isTabbableCandidate(candidate)),included=traversed.elements.filter(isBrowserFocusElement),retained=new Set(included),orderedElements=flattenNavigationScope(traversed.navigationScope,mode,retained);return{elements:mode==="tabbable"?collapseRadioGroups(orderedElements):orderedElements,truncated:traversed.reasons.size>0,truncationReasons:[...traversed.reasons],visitedElements:traversed.visitedElements}}function collectComposedAutofocusElements(root,options={}){const traversed=traverseComposedElements(root,options,(element,available)=>available&&isHtmlElement(element)&&element.hasAttribute("autofocus"));return{elements:traversed.elements,truncated:traversed.reasons.size>0,truncationReasons:[...traversed.reasons],visitedElements:traversed.visitedElements}}export{applyComposedFocusRepair,captureComposedFocusRepair,collectComposedAutofocusElements,collectComposedFocusTargets,focusFirstAvailable,isActionableElement,isComposedFocusAvailable,isSemanticActionElement,repairComposedFocus};
1
+ import{composedParentElement,deepActiveElementIn}from"./active-element.js";import{isAriaTrue}from"./accessibility-visibility.js";import{asciiWhitespaceTokens}from"./ascii-whitespace.js";import{imageMapImageFor,isHtmlElement,isSvgElement}from"./dom-guards.js";const DEFAULT_FOCUS_MAX_DEPTH=256,DEFAULT_FOCUS_MAX_NODES=1e4,MAX_CONFIGURED_FOCUS_LIMIT=1e5,ARIA_WIDGET_ROLES=new Set(["button","checkbox","combobox","grid","gridcell","link","listbox","menu","menubar","menuitem","menuitemcheckbox","menuitemradio","option","radio","radiogroup","scrollbar","searchbox","separator","slider","spinbutton","switch","tab","tablist","textbox","tree","treegrid","treeitem"]),ARIA_NON_WIDGET_ROLES=new Set(["alert","alertdialog","application","article","banner","blockquote","caption","cell","code","columnheader","comment","complementary","contentinfo","definition","deletion","dialog","directory","document","emphasis","feed","figure","form","generic","group","heading","img","image","insertion","list","listitem","log","main","marquee","mark","math","meter","navigation","none","note","paragraph","presentation","progressbar","region","row","rowgroup","rowheader","search","sectionfooter","sectionheader","status","strong","subscript","suggestion","superscript","table","tabpanel","term","time","timer","toolbar","tooltip"]);function finiteFocusLimit(value,fallback){return Number.isFinite(value)?Math.min(MAX_CONFIGURED_FOCUS_LIMIT,Math.max(0,Math.floor(value))):fallback}function createFocusTraversalContext(options){return{elementStates:new Map,imageMapImages:new Map,maxDepth:finiteFocusLimit(options.maxDepth,DEFAULT_FOCUS_MAX_DEPTH),maxNodes:finiteFocusLimit(options.maxNodes,DEFAULT_FOCUS_MAX_NODES),reasons:new Set,workUnits:0}}function renderedElementState(element,imageMapImage){let style;try{style=element.ownerDocument.defaultView?.getComputedStyle(element)}catch{}return{display:style?.display,subtreeUnavailable:element.hasAttribute("hidden")||element.hasAttribute("inert")||isAriaTrue(element.getAttribute("aria-hidden"))||isAriaTrue(element.getAttribute("aria-disabled"))||!imageMapImage&&(style?.display==="none"||style?.contentVisibility==="hidden"),visibility:style?.visibility}}function consumeFocusWork(context){return context.workUnits>=context.maxNodes?(context.reasons.add("nodes"),!1):(context.workUnits+=1,!0)}function cachedRenderedElementState(context,element){let state=context.elementStates.get(element);return state||(state=renderedElementState(element,cachedImageMapImage(context,element)),context.elementStates.set(element,state)),state}function cachedImageMapImage(context,element){if(context.imageMapImages.has(element))return context.imageMapImages.get(element);const image=imageMapImageFor(element,{consume:()=>consumeFocusWork(context)});return context.imageMapImages.set(element,image),image}function isClosedDetailsBranch(details,branch,context){if(details.localName!=="details"||details.hasAttribute("open")||branch===null)return!1;for(const child of details.children){if(!consumeFocusWork(context))return!0;if(child.localName==="summary")return child!==branch}return!0}function composedAncestorsAvailable(element,context){let branch=element,ancestor=composedParentElement(element),depth=0;for(;ancestor;){if(!consumeFocusWork(context)||cachedRenderedElementState(context,ancestor).subtreeUnavailable||isClosedDetailsBranch(ancestor,branch,context))return!1;if(depth+=1,depth>context.maxDepth)return context.reasons.add("depth"),!1;branch=ancestor,ancestor=composedParentElement(ancestor)}return!0}function isRenderedFocusCandidate(context,element,state){const imageMapImage=cachedImageMapImage(context,element);if(isHtmlElement(element)&&element.localName==="area"&&!imageMapImage)return!1;if(imageMapImage){const imageState=cachedRenderedElementState(context,imageMapImage);return composedAncestorsAvailable(imageMapImage,context)&&!imageState.subtreeUnavailable&&isRenderedFocusCandidate(context,imageMapImage,imageState)}if(!element.isConnected||state.visibility==="hidden"||state.visibility==="collapse")return!1;const candidate=element;if(typeof candidate.checkVisibility=="function")try{return candidate.checkVisibility({contentVisibilityAuto:!0})}catch{return!1}return element.getClientRects().length>0}function hasAriaWidgetRole(element){for(const token of asciiWhitespaceTokens(element.getAttribute("role"))){const role=token.toLowerCase();if(ARIA_WIDGET_ROLES.has(role))return!0;if(ARIA_NON_WIDGET_ROLES.has(role))return!1}return!1}function isNativeAction(element){if(isSvgElement(element))return element.localName==="a"&&(element.hasAttribute("href")||element.hasAttributeNS("http://www.w3.org/1999/xlink","href"));switch(element.localName){case"a":return element.hasAttribute("href");case"area":{if(!element.hasAttribute("href"))return!1;let ancestor=element.parentElement;for(let depth=0;ancestor&&depth<=DEFAULT_FOCUS_MAX_DEPTH;depth+=1){if(ancestor.localName==="map")return!0;ancestor=ancestor.parentElement}return!1}case"audio":case"video":return element.hasAttribute("controls");case"button":case"embed":case"iframe":case"select":case"textarea":return!0;case"object":{const data=element.getAttribute("data");return data!==null&&data.trim()!==""}case"input":return element.type!=="hidden";case"summary":return element.matches("details > summary:first-of-type");default:return element.hasAttribute("contenteditable")&&element.isContentEditable&&!element.parentElement?.isContentEditable}}function isBrowserFocusElement(element){return isHtmlElement(element)||isSvgElement(element)}function isShadowRoot(root){return root.nodeType===11&&"host"in root}function isSemanticActionElement(element){return isBrowserFocusElement(element)&&(isNativeAction(element)||hasAriaWidgetRole(element))}function isActionableElement(element){return isSemanticActionElement(element)||isBrowserFocusElement(element)&&element.hasAttribute("tabindex")&&element.tabIndex>=0}function isComposedFocusAvailable(element,options={}){if(!isBrowserFocusElement(element))return!1;const context=createFocusTraversalContext(options);if(!consumeFocusWork(context)||!composedAncestorsAvailable(element,context))return!1;const state=cachedRenderedElementState(context,element);return state.subtreeUnavailable||element.matches(":disabled")?!1:isRenderedFocusCandidate(context,element,state)}function composedContains(container,candidate,maxDepth=DEFAULT_FOCUS_MAX_DEPTH){let current=candidate,depth=0;for(;current;){if(current===container)return!0;if(depth>=maxDepth)return!1;current=composedParentElement(current),depth+=1}return!1}function isComposedFocusRepairTargetList(value){return Array.isArray(value)}function resolveComposedFocusRepairTargets(source){const resolved=typeof source=="function"?source():source;if(!resolved)return[];if(!isComposedFocusRepairTargetList(resolved))return[resolved];const targets=[];for(const target of resolved)target&&targets.push(target);return targets}function captureComposedFocusRepair(owner,candidate){if(!candidate||candidate.ownerDocument!==owner.ownerDocument)return null;const activeElement=deepActiveElementIn(owner.ownerDocument);return!activeElement||!composedContains(owner,activeElement)?null:{activeElement,candidate,document:owner.ownerDocument,owner}}function applyComposedFocusRepair(snapshot,candidateOverride){const{document:ownerDocument,owner}=snapshot,targetSource=arguments.length<2?snapshot.candidate:candidateOverride,candidates=resolveComposedFocusRepairTargets(targetSource);if(candidates.length===0)return!1;const current=deepActiveElementIn(ownerDocument),lostWithBranch=current===null||current===ownerDocument.body||current===ownerDocument.documentElement;return current!==snapshot.activeElement&&!composedContains(owner,current)&&!lostWithBranch?!1:focusFirstAvailable(candidates.filter(candidate=>candidate.ownerDocument===ownerDocument))}function focusFirstAvailable(targets){for(const candidate of resolveComposedFocusRepairTargets(targets)){if(!isComposedFocusAvailable(candidate))continue;candidate.focus();const focused=deepActiveElementIn(candidate.ownerDocument);if(focused===candidate||composedContains(candidate,focused))return!0}return!1}function repairComposedFocus(owner,fallbackTargets){const activeElement=deepActiveElementIn(owner.ownerDocument);if(!activeElement||!composedContains(owner,activeElement))return!1;const candidates=resolveComposedFocusRepairTargets(fallbackTargets),[candidate]=candidates;return candidate?applyComposedFocusRepair({activeElement,candidate,document:owner.ownerDocument,owner},candidates):!1}function nextHostUpdateOpportunity(){return new Promise(resolve=>{queueMicrotask(()=>{requestAnimationFrame(()=>resolve())})})}function deferComposedFocusRepair(owner,bridge,resolveTarget){const snapshot=captureComposedFocusRepair(owner,bridge);snapshot&&nextHostUpdateOpportunity().then(()=>{let target;try{target=resolveTarget()}catch{target=null}applyComposedFocusRepair(snapshot,target?[target]:[])})}function traverseComposedElements(root,options,include){const context=createFocusTraversalContext(options),{maxDepth,maxNodes}=context,elements=[],stack=[],visited=new Set,navigationScope={entries:[],nextOrder:0};if(maxNodes===0)return context.reasons.add("nodes"),{elements,navigationScope,reasons:context.reasons,visitedElements:0};const schedule=(element,depth,ancestorsAvailable,scope,workCharged=!1)=>{if(depth>maxDepth){context.reasons.add("depth");return}stack.push({ancestorsAvailable,depth,element,kind:"element",scope,workCharged})},scheduleChildren=(children,depth,ancestorsAvailable,scope)=>{if(children.length!==0){if(depth>maxDepth){context.reasons.add("depth");return}stack.push({ancestorsAvailable,children,depth,index:0,kind:"children",scope})}},scheduleSlotChildren=(slot,depth,ancestorsAvailable,scope)=>{if(depth>maxDepth){context.reasons.add("depth");return}const slotRoot=slot.getRootNode(),candidates=slotRoot.nodeType===11&&"host"in slotRoot?slotRoot.host.childNodes:[];stack.push({ancestorsAvailable,candidates,depth,fallback:slot.children,foundAssigned:!1,index:0,kind:"slot",scope,slot})},scheduleComposedChildren=(element,depth,ancestorsAvailable,scope)=>{if(element.localName==="slot"&&isHtmlElement(element)){scheduleSlotChildren(element,depth,ancestorsAvailable,scope);return}if(element.localName==="details"&&!element.hasAttribute("open")){for(const child of element.children){if(!consumeFocusWork(context))return;if(child.localName==="summary"){schedule(child,depth,ancestorsAvailable,scope,!0);return}}return}scheduleChildren(element.shadowRoot?.children??element.children,depth,ancestorsAvailable,scope)};if(isShadowRoot(root)){const shadowRoot=root,ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(shadowRoot.host,context),hostStateAvailable=consumeFocusWork(context)&&!cachedRenderedElementState(context,shadowRoot.host).subtreeUnavailable;scheduleChildren(shadowRoot.children,0,ancestorsAvailable&&hostStateAvailable,navigationScope)}else if(options.includeRoot===!1){const ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(root,context),ownAvailable=consumeFocusWork(context)&&!cachedRenderedElementState(context,root).subtreeUnavailable;scheduleComposedChildren(root,0,ancestorsAvailable&&ownAvailable,navigationScope)}else{const ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(root,context);schedule(root,0,ancestorsAvailable,navigationScope)}for(;stack.length>0;){const work=stack.pop();if(work.kind==="slot"){if(work.index>=work.candidates.length){work.foundAssigned||scheduleChildren(work.fallback,work.depth,work.ancestorsAvailable,work.scope);continue}if(!consumeFocusWork(context)){stack.length=0;break}const node=work.candidates[work.index],assigned=!!(node&&node.assignedSlot===work.slot);stack.push({...work,foundAssigned:work.foundAssigned||assigned,index:work.index+1}),node?.nodeType===1&&assigned&&schedule(node,work.depth,work.ancestorsAvailable,work.scope,!0);continue}if(work.kind==="children"){if(work.index>=work.children.length)continue;const element=work.children[work.index];stack.push({...work,index:work.index+1}),element&&schedule(element,work.depth,work.ancestorsAvailable,work.scope);continue}if(visited.has(work.element))continue;if(!work.workCharged&&!consumeFocusWork(context)){stack.length=0;break}visited.add(work.element);const state=cachedRenderedElementState(context,work.element),available=work.ancestorsAvailable&&!state.subtreeUnavailable,included=include(work.element,available,state,context);if(included&&elements.push(work.element),!available)continue;if(work.element.shadowRoot||work.element.localName==="slot"&&isHtmlElement(work.element)){const childScope={entries:[],nextOrder:0};work.scope.entries.push({childScope,delegatesFocus:!!work.element.shadowRoot?.delegatesFocus,order:work.scope.nextOrder++,suppressSequentialDescendants:work.element.hasAttribute("tabindex")&&work.element.tabIndex<0,target:included&&isBrowserFocusElement(work.element)?work.element:void 0}),scheduleComposedChildren(work.element,work.depth+1,!0,childScope);continue}included&&isBrowserFocusElement(work.element)&&work.scope.entries.push({order:work.scope.nextOrder++,target:work.element}),scheduleComposedChildren(work.element,work.depth+1,!0,work.scope)}return{elements,navigationScope,reasons:context.reasons,visitedElements:visited.size}}function isOverflowingTabStop(element){const view=element.ownerDocument.defaultView;if(!view)return!1;const{overflowX,overflowY}=view.getComputedStyle(element);return overflowX==="scroll"||overflowY==="scroll"||overflowY==="auto"&&element.scrollHeight>element.clientHeight?!0:overflowX==="auto"&&element.scrollWidth>element.clientWidth}function isTabbableCandidate(element){return element.hasAttribute("tabindex")?element.tabIndex>=0?!0:isHtmlElement(element)&&!isNativeAction(element)&&isOverflowingTabStop(element):isHtmlElement(element)&&element.hasAttribute("contenteditable")&&element.isContentEditable?!element.parentElement?.isContentEditable:isNativeAction(element)}function collapseRadioGroups(elements){const byRoot=new Map;for(const element of elements){if(!isHtmlElement(element)||element.localName!=="input")continue;const input=element;if(input.type!=="radio"||input.name==="")continue;const root=input.getRootNode();let byForm=byRoot.get(root);byForm||(byForm=new Map,byRoot.set(root,byForm));let byName=byForm.get(input.form);byName||(byName=new Map,byForm.set(input.form,byName));const group=byName.get(input.name);group?input.checked&&!group.checked&&(group.checked=input):byName.set(input.name,{checked:input.checked?input:void 0,first:input})}const tabStops=new Set;for(const byForm of byRoot.values())for(const byName of byForm.values())for(const group of byName.values())tabStops.add(group.checked??group.first);return elements.filter(element=>{if(!isHtmlElement(element)||element.localName!=="input")return!0;const input=element;return input.type!=="radio"||input.name===""||tabStops.has(input)})}function navigationEntryTabIndex(entry){return entry.target&&entry.target.tabIndex>0?entry.target.tabIndex:0}function flattenNavigationScope(scope,mode,retainedTargets){const orderedEntries=candidate=>mode==="tabbable"?[...candidate.entries].sort((first,second)=>{const firstTabIndex=navigationEntryTabIndex(first),secondTabIndex=navigationEntryTabIndex(second);return firstTabIndex>0!=secondTabIndex>0?firstTabIndex>0?-1:1:firstTabIndex>0&&firstTabIndex!==secondTabIndex?firstTabIndex-secondTabIndex:first.order-second.order}):candidate.entries,flattened=[],work=[{kind:"scope",scope}];for(;work.length>0;){const current=work.pop();if(current.kind==="target"){flattened.push(current.target);continue}const entries=orderedEntries(current.scope);for(let index=entries.length-1;index>=0;index-=1){const entry=entries[index];entry.childScope&&(mode!=="tabbable"||!entry.suppressSequentialDescendants)&&work.push({kind:"scope",scope:entry.childScope}),entry.target&&retainedTargets.has(entry.target)&&!entry.delegatesFocus&&work.push({kind:"target",target:entry.target})}}return flattened}function collectComposedFocusTargets(root,options={}){const mode=options.mode??"tabbable",traversed=traverseComposedElements(root,options,(candidate,available,state,context)=>!available||!isBrowserFocusElement(candidate)||candidate.matches(":disabled")||!isRenderedFocusCandidate(context,candidate,state)?!1:mode==="programmatic"?candidate.hasAttribute("tabindex")||isActionableElement(candidate):(candidate.hasAttribute("tabindex")||isActionableElement(candidate))&&isTabbableCandidate(candidate)),included=traversed.elements.filter(isBrowserFocusElement),retained=new Set(included),orderedElements=flattenNavigationScope(traversed.navigationScope,mode,retained);return{elements:mode==="tabbable"?collapseRadioGroups(orderedElements):orderedElements,truncated:traversed.reasons.size>0,truncationReasons:[...traversed.reasons],visitedElements:traversed.visitedElements}}function collectComposedAutofocusElements(root,options={}){const traversed=traverseComposedElements(root,options,(element,available)=>available&&isHtmlElement(element)&&element.hasAttribute("autofocus"));return{elements:traversed.elements,truncated:traversed.reasons.size>0,truncationReasons:[...traversed.reasons],visitedElements:traversed.visitedElements}}export{applyComposedFocusRepair,captureComposedFocusRepair,collectComposedAutofocusElements,collectComposedFocusTargets,deferComposedFocusRepair,focusFirstAvailable,isActionableElement,isComposedFocusAvailable,isSemanticActionElement,nextHostUpdateOpportunity,repairComposedFocus};
@@ -1 +1 @@
1
- import{LYRA_DEFAULT_fieldRequired}from"./default-strings.generated.js";import{resolveLyraString}from"./localization-runtime.js";import{AnchoredValidityController,SET_ANCHORED_VALIDITY,VALIDITY_ANCHOR}from"./anchored-validity.js";import{syncValidityStates}from"./custom-states.js";import{installInvalidEventAlias}from"./invalid-event-alias.js";import{omittedEmptyStringConverter}from"./converters.js";import{attachInternalsSafely,createFallbackInternals}from"./element-internals.js";import{installFormControlLabelSupport}from"./form-control-labels.js";import{getFormOwner,installCustomErrorProperty,setFormOwner}from"./direct-form-associated.js";installFormControlLabelSupport();const FORM_ASSOCIATED_DEFAULT_STRINGS=Object.freeze({fieldRequired:LYRA_DEFAULT_fieldRequired});function createStringArrayFormDataState(name,values){const state=new FormData,key=name||"value";for(const value of values)state.append(key,value);return state}function readStringArrayFormDataState(state){if(typeof FormData!="function")return[];let entries;try{entries=[...FormData.prototype.values.call(state)]}catch{return[]}return entries.some(entry=>typeof entry!="string")?[]:entries}function isEmptyFormValue(value){if(value==null)return!0;if(typeof value=="string")return value==="";if(typeof value=="object")try{if(Array.isArray(value))return value.length===0;const prototype=Object.getPrototypeOf(value);if(prototype===null)return Object.keys(value).length===0;if(Object.getPrototypeOf(prototype)===null){const constructor=Object.getOwnPropertyDescriptor(prototype,"constructor")?.value;if(typeof constructor=="function"&&constructor.name==="Object"&&constructor.prototype===prototype)return Object.keys(value).length===0}}catch{return!1}return!1}const stringFormValueAdapter={empty:"",toFormValue:value=>value,isEmpty:value=>value==="",fromAttribute:attribute=>attribute,toAttribute:value=>value,fromFormState:state=>typeof state=="string"?state:""};function resolveFormValueAdapter(adapter){return adapter===void 0?stringFormValueAdapter:{empty:adapter.empty,toFormValue:value=>adapter.toFormValue(value),...adapter.toFormState?{toFormState:value=>adapter.toFormState(value)}:{},isEmpty:adapter.isEmpty?value=>adapter.isEmpty(value):isEmptyFormValue,fromAttribute:adapter.fromAttribute?attribute=>adapter.fromAttribute(attribute):attribute=>attribute,toAttribute:adapter.toAttribute?value=>adapter.toAttribute(value):value=>value==null?null:String(value),fromFormState:adapter.fromFormState?state=>adapter.fromFormState(state):state=>typeof state=="string"?state:adapter.empty}}function isBarredFromValidation(host,internals){if((host.effectiveDisabled??host.disabled)||host.readonly)return!0;if(internals){const willValidate=readNativeWillValidate(internals);if(willValidate!==void 0)return!willValidate}return!1}function readNativeWillValidate(internals){if(typeof ElementInternals!="function")return;const getter=Object.getOwnPropertyDescriptor(ElementInternals.prototype,"willValidate")?.get;if(typeof getter=="function")try{const value=getter.call(internals);return typeof value=="boolean"?value:void 0}catch{return}}function FormAssociated(Base,valueAdapter){const adapter=resolveFormValueAdapter(valueAdapter),defaultValueConverter={fromAttribute:attribute=>attribute===null?null:adapter.fromAttribute(attribute),toAttribute:value=>value==null?null:adapter.toAttribute(value)};class FormAssociatedElement extends Base{static{this.formAssociated=!0}static{this.properties={name:{reflect:!0,noAccessor:!0,converter:omittedEmptyStringConverter},value:{attribute:!1,noAccessor:!0},defaultValue:{attribute:"value",reflect:!0,useDefault:!0,noAccessor:!0,...valueAdapter?{converter:defaultValueConverter}:{}},customError:{attribute:"custom-error",reflect:!0,noAccessor:!0},form:{noAccessor:!0},disabled:{type:Boolean,reflect:!0,noAccessor:!0},required:{type:Boolean,reflect:!0,noAccessor:!0}}}constructor(...args){super(...args),this._fieldsetDisabled=!1,this._disabled=!1,this._reflectingDisabledAttribute=!1,this._name="",this._value=adapter.empty,this._defaultValue=adapter.empty,this._valueDirty=!1,this.settingDefaultValue=!1,this.reflectingDefaultValue=!1,this.reflectingCustomError=!1,this.reflectingFormOwner=!1,this._required=!1,this._hasInteracted=!1,this.internals=attachInternalsSafely(this),this.validityController=new AnchoredValidityController(this,this.internals,()=>this[VALIDITY_ANCHOR]()),this.commitFormValue(this._value),installInvalidEventAlias(this,init=>this.emit("lr-invalid",null,init));const markInteracted=()=>{this._hasInteracted||(this._hasInteracted=!0,this.syncValidityStates())};this.addEventListener("input",markInteracted),this.addEventListener("change",markInteracted),this.addEventListener("focusout",()=>{this.effectiveDisabled||markInteracted()}),this.syncValidityStates()}get form(){return getFormOwner(this.internals)}set form(owner){if(!this.reflectingFormOwner){this.reflectingFormOwner=!0;try{setFormOwner(this,owner)}finally{this.reflectingFormOwner=!1}}}getForm(){return getFormOwner(this.internals)}get labels(){return this.internals.labels}get validity(){return this.internals.validity}get validationMessage(){return this.internals.validationMessage}get willValidate(){return this.internals.willValidate}[VALIDITY_ANCHOR](){return this.renderRoot?.querySelector("input:not([type='hidden']), textarea, select, button, [tabindex]:not([tabindex='-1'])")??null}[SET_ANCHORED_VALIDITY](flags,message=""){this.validityController.setValidity(flags,message),this.syncValidityStates()}commitCustomValidity(message){const old=this.customError,normalized=message??"";this.validityController.setCustomValidity(normalized),this.syncValidityStates(),this.reflectingCustomError=!0;try{normalized?this.setAttribute("custom-error",normalized):this.removeAttribute("custom-error")}finally{this.reflectingCustomError=!1}this.requestUpdate("customError",old)}setCustomValidity(message){this.commitCustomValidity(message)}resetValidity(){this.commitCustomValidity(""),this.updateValidity(),this.syncValidityStates()}syncValidityStates(){syncValidityStates(this.internals,{required:this.required,hasInteracted:this._hasInteracted,barred:this.isBarredFromValidation()})}isBarredFromValidation(){return isBarredFromValidation(this,this.internals)}get name(){return this._name}set name(next){const old=this._name;this._name=next??"",this._name?this.setAttribute("name",this._name):this.removeAttribute("name"),this.requestUpdate("name",old)}commitFormValue(value){const submitted=adapter.toFormValue(value);adapter.toFormState?this.internals.setFormValue(submitted,adapter.toFormState(value)):this.internals.setFormValue(submitted)}get value(){return this._value}set value(next){const old=this._value;this._value=next??adapter.empty,this.settingDefaultValue||(this._valueDirty=!0),this.commitFormValue(this._value),this.updateValidity(),this.requestUpdate("value",old)}captureLiveValueCheckpoint(){return{value:this._value,dirty:this._valueDirty}}restoreLiveValueCheckpoint(checkpoint){const old=this._value;this._value=checkpoint.value,this._valueDirty=checkpoint.dirty,this.commitFormValue(this._value),this.updateValidity(),this.requestUpdate("value",old)}get defaultValue(){return this._defaultValue}set defaultValue(next){if(this.reflectingDefaultValue)return;const old=this._defaultValue;this._defaultValue=next??adapter.empty,this.reflectingDefaultValue=!0;try{const attribute=next==null?null:adapter.toAttribute(this._defaultValue);attribute==null?this.removeAttribute("value"):this.setAttribute("value",attribute)}finally{this.reflectingDefaultValue=!1}this._valueDirty||this.restoreLiveValueFromDefault(),this.requestUpdate("defaultValue",old)}get customError(){return this.validityController.customValidityMessage||null}set customError(next){this.reflectingCustomError||this.commitCustomValidity(next)}get disabled(){return this._disabled}set disabled(next){const old=this._disabled;this._disabled=!!next,this.toggleAttribute("disabled",this._disabled),!this._disabled&&typeof this.matches=="function"&&(this._fieldsetDisabled=this.matches(":disabled")),this.updateValidity(),this.syncValidityStates(),this.requestUpdate("disabled",old)}toggleAttribute(qualifiedName,force){if(qualifiedName!=="disabled")return super.toggleAttribute(qualifiedName,force);const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{return super.toggleAttribute(qualifiedName,force)}finally{this._reflectingDisabledAttribute=wasReflecting}}setAttribute(qualifiedName,value){if(qualifiedName!=="disabled"){super.setAttribute(qualifiedName,value);return}const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{super.setAttribute(qualifiedName,value)}finally{this._reflectingDisabledAttribute=wasReflecting}}removeAttribute(qualifiedName){if(qualifiedName!=="disabled"){super.removeAttribute(qualifiedName);return}const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{super.removeAttribute(qualifiedName)}finally{this._reflectingDisabledAttribute=wasReflecting}}get required(){return this._required}set required(next){const old=this._required;this._required=next,this.toggleAttribute("required",next),this.updateValidity(),this.syncValidityStates(),this.requestUpdate("required",old)}get effectiveDisabled(){return this.disabled||this._fieldsetDisabled}setFormValue(next){this.value=next}updateValidity(){if(this.isBarredFromValidation()){this[SET_ANCHORED_VALIDITY]({});return}if(this.required&&adapter.isEmpty(this._value)){const overrides=this.strings,message=resolveLyraString(this,"fieldRequired",overrides,void 0,void 0,FORM_ASSOCIATED_DEFAULT_STRINGS);this[SET_ANCHORED_VALIDITY]({valueMissing:!0},message)}else this[SET_ANCHORED_VALIDITY]({})}syncConstraintsToNative(){const host=this;host.hasUpdated&&host.performUpdate()}checkValidity(){return this.syncConstraintsToNative(),this.updateValidity(),this.internals.checkValidity()}reportValidity(){return this.syncConstraintsToNative(),this.updateValidity(),this._hasInteracted=!0,this.syncValidityStates(),this.internals.reportValidity()}formResetCallback(){this._valueDirty=!1,this.restoreLiveValueFromDefault(),this._hasInteracted=!1,this.syncValidityStates()}restoreLiveValueFromDefault(){this.settingDefaultValue=!0;try{this.value=this._defaultValue}finally{this.settingDefaultValue=!1}this._valueDirty=!1}formStateRestoreCallback(state,reason){this.value=adapter.fromFormState(state)}formDisabledCallback(fieldsetDisabled){if(this._reflectingDisabledAttribute)return;const before=this.effectiveDisabled;this._fieldsetDisabled=fieldsetDisabled,this.effectiveDisabled!==before&&(this.updateValidity(),this.syncValidityStates(),this.requestUpdate())}updated(changed){super.updated(changed),!(!changed.has("readonly")&&!changed.has("disabled"))&&(this.updateValidity(),this.syncValidityStates())}connectedCallback(){super.connectedCallback(),this.updateValidity(),this.syncValidityStates()}}return FormAssociatedElement}export{FormAssociated,attachInternalsSafely,createFallbackInternals,createStringArrayFormDataState,getFormOwner,installCustomErrorProperty,isBarredFromValidation,isEmptyFormValue,readStringArrayFormDataState,setFormOwner,stringFormValueAdapter};
1
+ import{LYRA_DEFAULT_fieldRequired}from"./default-strings.generated.js";import{resolveLyraString}from"./localization-runtime.js";import{AnchoredValidityController,SET_ANCHORED_VALIDITY,VALIDITY_ANCHOR}from"./anchored-validity.js";import{syncValidityStates}from"./custom-states.js";import{installInteractionOnInvalid,installInvalidEventAlias,withStaticValidityCheck}from"./invalid-event-alias.js";import{omittedEmptyStringConverter}from"./converters.js";import{attachInternalsSafely,createFallbackInternals}from"./element-internals.js";import{installFormControlLabelSupport}from"./form-control-labels.js";import{getFormOwner,installCustomErrorProperty,setFormOwner}from"./direct-form-associated.js";installFormControlLabelSupport();const FORM_ASSOCIATED_DEFAULT_STRINGS=Object.freeze({fieldRequired:LYRA_DEFAULT_fieldRequired});function createStringArrayFormDataState(name,values){const state=new FormData,key=name||"value";for(const value of values)state.append(key,value);return state}function readStringArrayFormDataState(state){if(typeof FormData!="function")return[];let entries;try{entries=[...FormData.prototype.values.call(state)]}catch{return[]}return entries.some(entry=>typeof entry!="string")?[]:entries}function isEmptyFormValue(value){if(value==null)return!0;if(typeof value=="string")return value==="";if(typeof value=="object")try{if(Array.isArray(value))return value.length===0;const prototype=Object.getPrototypeOf(value);if(prototype===null)return Object.keys(value).length===0;if(Object.getPrototypeOf(prototype)===null){const constructor=Object.getOwnPropertyDescriptor(prototype,"constructor")?.value;if(typeof constructor=="function"&&constructor.name==="Object"&&constructor.prototype===prototype)return Object.keys(value).length===0}}catch{return!1}return!1}const stringFormValueAdapter={empty:"",toFormValue:value=>value,isEmpty:value=>value==="",fromAttribute:attribute=>attribute,toAttribute:value=>value,fromFormState:state=>typeof state=="string"?state:""};function resolveFormValueAdapter(adapter){return adapter===void 0?stringFormValueAdapter:{empty:adapter.empty,toFormValue:value=>adapter.toFormValue(value),...adapter.toFormState?{toFormState:value=>adapter.toFormState(value)}:{},isEmpty:adapter.isEmpty?value=>adapter.isEmpty(value):isEmptyFormValue,fromAttribute:adapter.fromAttribute?attribute=>adapter.fromAttribute(attribute):attribute=>attribute,toAttribute:adapter.toAttribute?value=>adapter.toAttribute(value):value=>value==null?null:String(value),fromFormState:adapter.fromFormState?state=>adapter.fromFormState(state):state=>typeof state=="string"?state:adapter.empty}}function isBarredFromValidation(host,internals){if((host.effectiveDisabled??host.disabled)||host.readonly)return!0;if(internals){const willValidate=readNativeWillValidate(internals);if(willValidate!==void 0)return!willValidate}return!1}function readNativeWillValidate(internals){if(typeof ElementInternals!="function")return;const getter=Object.getOwnPropertyDescriptor(ElementInternals.prototype,"willValidate")?.get;if(typeof getter=="function")try{const value=getter.call(internals);return typeof value=="boolean"?value:void 0}catch{return}}function FormAssociated(Base,valueAdapter){const adapter=resolveFormValueAdapter(valueAdapter),defaultValueConverter={fromAttribute:attribute=>attribute===null?null:adapter.fromAttribute(attribute),toAttribute:value=>value==null?null:adapter.toAttribute(value)};class FormAssociatedElement extends Base{static{this.formAssociated=!0}static{this.properties={name:{reflect:!0,noAccessor:!0,converter:omittedEmptyStringConverter},value:{attribute:!1,noAccessor:!0},defaultValue:{attribute:"value",reflect:!0,useDefault:!0,noAccessor:!0,...valueAdapter?{converter:defaultValueConverter}:{}},customError:{attribute:"custom-error",reflect:!0,noAccessor:!0},form:{noAccessor:!0},disabled:{type:Boolean,reflect:!0,noAccessor:!0},required:{type:Boolean,reflect:!0,noAccessor:!0}}}constructor(...args){super(...args),this._fieldsetDisabled=!1,this._disabled=!1,this._reflectingDisabledAttribute=!1,this._name="",this._value=adapter.empty,this._defaultValue=adapter.empty,this._valueDirty=!1,this.settingDefaultValue=!1,this.reflectingDefaultValue=!1,this.reflectingCustomError=!1,this.reflectingFormOwner=!1,this._required=!1,this._hasInteracted=!1,this.internals=attachInternalsSafely(this),this.validityController=new AnchoredValidityController(this,this.internals,()=>this[VALIDITY_ANCHOR]()),this.commitFormValue(this._value),installInvalidEventAlias(this,init=>this.emit("lr-invalid",null,init));const markInteracted=()=>{this._hasInteracted||(this._hasInteracted=!0,this.syncValidityStates())};this.addEventListener("input",markInteracted),this.addEventListener("change",markInteracted),this.addEventListener("focusout",()=>{this.effectiveDisabled||markInteracted()}),installInteractionOnInvalid(this,markInteracted),this.syncValidityStates()}get form(){return getFormOwner(this.internals)}set form(owner){if(!this.reflectingFormOwner){this.reflectingFormOwner=!0;try{setFormOwner(this,owner)}finally{this.reflectingFormOwner=!1}}}getForm(){return getFormOwner(this.internals)}get labels(){return this.internals.labels}get validity(){return this.internals.validity}get validationMessage(){return this.internals.validationMessage}get willValidate(){return this.internals.willValidate}[VALIDITY_ANCHOR](){return this.renderRoot?.querySelector("input:not([type='hidden']), textarea, select, button, [tabindex]:not([tabindex='-1'])")??null}[SET_ANCHORED_VALIDITY](flags,message=""){this.validityController.setValidity(flags,message),this.syncValidityStates()}commitCustomValidity(message){const old=this.customError,normalized=message??"";this.validityController.setCustomValidity(normalized),this.syncValidityStates(),this.reflectingCustomError=!0;try{normalized?this.setAttribute("custom-error",normalized):this.removeAttribute("custom-error")}finally{this.reflectingCustomError=!1}this.requestUpdate("customError",old)}setCustomValidity(message){this.commitCustomValidity(message)}resetValidity(){this.commitCustomValidity(""),this.updateValidity(),this.syncValidityStates()}syncValidityStates(){syncValidityStates(this.internals,{required:this.required,hasInteracted:this._hasInteracted,barred:this.isBarredFromValidation()})}isBarredFromValidation(){return isBarredFromValidation(this,this.internals)}get name(){return this._name}set name(next){const old=this._name;this._name=next??"",this._name?this.setAttribute("name",this._name):this.removeAttribute("name"),this.requestUpdate("name",old)}commitFormValue(value){const submitted=adapter.toFormValue(value);adapter.toFormState?this.internals.setFormValue(submitted,adapter.toFormState(value)):this.internals.setFormValue(submitted)}get value(){return this._value}set value(next){const old=this._value;this._value=next??adapter.empty,this.settingDefaultValue||(this._valueDirty=!0),this.commitFormValue(this._value),this.updateValidity(),this.requestUpdate("value",old)}captureLiveValueCheckpoint(){return{value:this._value,dirty:this._valueDirty}}restoreLiveValueCheckpoint(checkpoint){const old=this._value;this._value=checkpoint.value,this._valueDirty=checkpoint.dirty,this.commitFormValue(this._value),this.updateValidity(),this.requestUpdate("value",old)}get defaultValue(){return this._defaultValue}set defaultValue(next){if(this.reflectingDefaultValue)return;const old=this._defaultValue;this._defaultValue=next??adapter.empty,this.reflectingDefaultValue=!0;try{const attribute=next==null?null:adapter.toAttribute(this._defaultValue);attribute==null?this.removeAttribute("value"):this.setAttribute("value",attribute)}finally{this.reflectingDefaultValue=!1}this._valueDirty||this.restoreLiveValueFromDefault(),this.requestUpdate("defaultValue",old)}get customError(){return this.validityController.customValidityMessage||null}set customError(next){this.reflectingCustomError||this.commitCustomValidity(next)}get disabled(){return this._disabled}set disabled(next){const old=this._disabled;this._disabled=!!next,this.toggleAttribute("disabled",this._disabled),!this._disabled&&typeof this.matches=="function"&&(this._fieldsetDisabled=this.matches(":disabled")),this.updateValidity(),this.syncValidityStates(),this.requestUpdate("disabled",old)}toggleAttribute(qualifiedName,force){if(qualifiedName!=="disabled")return super.toggleAttribute(qualifiedName,force);const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{return super.toggleAttribute(qualifiedName,force)}finally{this._reflectingDisabledAttribute=wasReflecting}}setAttribute(qualifiedName,value){if(qualifiedName!=="disabled"){super.setAttribute(qualifiedName,value);return}const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{super.setAttribute(qualifiedName,value)}finally{this._reflectingDisabledAttribute=wasReflecting}}removeAttribute(qualifiedName){if(qualifiedName!=="disabled"){super.removeAttribute(qualifiedName);return}const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{super.removeAttribute(qualifiedName)}finally{this._reflectingDisabledAttribute=wasReflecting}}get required(){return this._required}set required(next){const old=this._required;this._required=next,this.toggleAttribute("required",next),this.updateValidity(),this.syncValidityStates(),this.requestUpdate("required",old)}get effectiveDisabled(){return this.disabled||this._fieldsetDisabled}setFormValue(next){this.value=next}updateValidity(){if(this.isBarredFromValidation()){this[SET_ANCHORED_VALIDITY]({});return}if(this.required&&adapter.isEmpty(this._value)){const overrides=this.strings,message=resolveLyraString(this,"fieldRequired",overrides,void 0,void 0,FORM_ASSOCIATED_DEFAULT_STRINGS);this[SET_ANCHORED_VALIDITY]({valueMissing:!0},message)}else this[SET_ANCHORED_VALIDITY]({})}syncConstraintsToNative(){const host=this;host.hasUpdated&&host.performUpdate()}checkValidity(){return this.syncConstraintsToNative(),this.updateValidity(),withStaticValidityCheck(this,()=>this.internals.checkValidity())}reportValidity(){return this.syncConstraintsToNative(),this.updateValidity(),this._hasInteracted=!0,this.syncValidityStates(),this.internals.reportValidity()}formResetCallback(){this._valueDirty=!1,this.restoreLiveValueFromDefault(),this._hasInteracted=!1,this.syncValidityStates()}restoreLiveValueFromDefault(){this.settingDefaultValue=!0;try{this.value=this._defaultValue}finally{this.settingDefaultValue=!1}this._valueDirty=!1}formStateRestoreCallback(state,reason){this.value=adapter.fromFormState(state)}formDisabledCallback(fieldsetDisabled){if(this._reflectingDisabledAttribute)return;const before=this.effectiveDisabled;this._fieldsetDisabled=fieldsetDisabled,this.effectiveDisabled!==before&&(this.updateValidity(),this.syncValidityStates(),this.requestUpdate())}updated(changed){super.updated(changed),!(!changed.has("readonly")&&!changed.has("disabled"))&&(this.updateValidity(),this.syncValidityStates())}connectedCallback(){super.connectedCallback(),this.updateValidity(),this.syncValidityStates()}}return FormAssociatedElement}export{FormAssociated,attachInternalsSafely,createFallbackInternals,createStringArrayFormDataState,getFormOwner,installCustomErrorProperty,isBarredFromValidation,isEmptyFormValue,readStringArrayFormDataState,setFormOwner,stringFormValueAdapter};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Runs a component's own slot-assignment collector once against a slot's CURRENT assignment, for
3
+ * a call from `firstUpdated()` alongside the component's ordinary `@slotchange` listener.
4
+ *
5
+ * happy-dom (verified through 20.14.5) never fires `slotchange` for a slot's INITIAL assignment --
6
+ * only for a later mutation to an already-connected slot. So a component that derives state (an
7
+ * options list, a selection default, an item collection, ...) exclusively from a `slotchange`
8
+ * handler collects nothing under it when the slotted children already exist before the component
9
+ * first renders -- the ordinary Lit "render only once data is ready" pattern, which slots every
10
+ * child in the same commit as the host itself. A real browser DOES fire the initial event, so
11
+ * calling the same collector from both `firstUpdated()` and `slotchange` keeps the component
12
+ * correct in both environments, provided the collector is idempotent against being run twice with
13
+ * the same assigned elements -- which a real browser firing both does on every connect. This
14
+ * helper only supplies the timing; the caller owns idempotency. `select.class.ts`'s
15
+ * `collectOptionsFromSlot` is the reference: identity-diffing the previous element set against the
16
+ * newly-read one makes a second call over an unchanged set contribute no duplicate
17
+ * selection-seeding side effect.
18
+ *
19
+ * A caller whose one-shot seeding logic must not fire on a legitimately empty result (nothing
20
+ * assigned yet, real content arriving later through its own ordinary `slotchange`) filters that
21
+ * case out of `collect` itself, or checks `slot.assignedElements(...)` before calling this helper
22
+ * at all -- this helper does not special-case emptiness.
23
+ *
24
+ * @param slot The slot to read (e.g. an `@query`-bound field, or
25
+ * `renderRoot.querySelector('slot:not([name])')`). `null`/`undefined` is a no-op -- a component
26
+ * whose relevant slot didn't render for the current props has nothing to collect yet.
27
+ * @param collect The component's own collection logic, given the slot directly rather than an
28
+ * `Event` (`slotchange`'s `e.target`), so it has one calling convention from either origin.
29
+ */
30
+ export declare function collectInitialSlotAssignment<T extends HTMLSlotElement>(slot:T|null|undefined,collect:(slot:T)=>void):void;
@@ -0,0 +1 @@
1
+ function collectInitialSlotAssignment(slot,collect){slot&&collect(slot)}export{collectInitialSlotAssignment};
@@ -1 +1 @@
1
- const MAX_ENTRIES_PER_KIND=64,numberFormatCache=new Map,dateTimeFormatCache=new Map,displayNamesCache=new Map,listFormatCache=new Map,relativeTimeFormatCache=new Map,pluralRulesCache=new Map,collatorCache=new Map,segmenterCache=new Map,resolvedLocaleCache=new Map;function resolveIntlLocale(locale){const raw=locale?.trim()??"",cached=resolvedLocaleCache.get(raw);if(cached!==void 0)return cached;const normalized=raw.replaceAll("_","-");let resolved="en";if(normalized&&normalized.toLowerCase()!=="auto")try{resolved=Intl.getCanonicalLocales(normalized)[0]??"en"}catch{}return resolvedLocaleCache.size>=64&&resolvedLocaleCache.clear(),resolvedLocaleCache.set(raw,resolved),resolved}function cacheKey(locale,options){const localeKey=locale;return options?`${localeKey}\0${JSON.stringify(options,Object.keys(options).sort())}`:localeKey}function getCached(cache,key,create){const existing=cache.get(key);if(existing!==void 0)return cache.delete(key),cache.set(key,existing),existing;if(cache.size>=64){const oldest=cache.keys().next().value;oldest!==void 0&&cache.delete(oldest)}const created=create();return cache.set(key,created),created}function getNumberFormat(locale,options){const safeLocale=resolveIntlLocale(locale);return getCached(numberFormatCache,cacheKey(safeLocale,options),()=>new Intl.NumberFormat(safeLocale,options))}function getDateTimeFormat(locale,options){const safeLocale=resolveIntlLocale(locale);return getCached(dateTimeFormatCache,cacheKey(safeLocale,options),()=>new Intl.DateTimeFormat(safeLocale,options))}function getDisplayNames(locale,options){const safeLocale=resolveIntlLocale(locale);return getCached(displayNamesCache,cacheKey(safeLocale,options),()=>new Intl.DisplayNames([safeLocale],options))}function getListFormat(locale,options){const safeLocale=resolveIntlLocale(locale);return getCached(listFormatCache,cacheKey(safeLocale,options),()=>new Intl.ListFormat(safeLocale,options))}function getRelativeTimeFormat(locale,options){const safeLocale=resolveIntlLocale(locale);return getCached(relativeTimeFormatCache,cacheKey(safeLocale,options),()=>new Intl.RelativeTimeFormat(safeLocale,options))}function getPluralRules(locale,options){const safeLocale=resolveIntlLocale(locale);return getCached(pluralRulesCache,cacheKey(safeLocale,options),()=>new Intl.PluralRules(safeLocale,options))}function getCollator(locale,options){const safeLocale=resolveIntlLocale(locale);return getCached(collatorCache,cacheKey(safeLocale,options),()=>new Intl.Collator(safeLocale,options))}function getSegmenter(locale,options){const safeLocale=resolveIntlLocale(locale);return getCached(segmenterCache,cacheKey(safeLocale,options),()=>new Intl.Segmenter(safeLocale,options))}export{getCollator,getDateTimeFormat,getDisplayNames,getListFormat,getNumberFormat,getPluralRules,getRelativeTimeFormat,getSegmenter,resolveIntlLocale};
1
+ const MAX_ENTRIES_PER_KIND=64,numberFormatCache=new Map,dateTimeFormatCache=new Map,displayNamesCache=new Map,listFormatCache=new Map,relativeTimeFormatCache=new Map,pluralRulesCache=new Map,collatorCache=new Map,segmenterCache=new Map,resolvedLocaleCache=new Map;function resolveIntlLocale(locale){const raw=locale?.trim()??"",cached=resolvedLocaleCache.get(raw);if(cached!==void 0)return cached;const normalized=raw.replaceAll("_","-");let resolved="en";if(normalized&&normalized.toLowerCase()!=="auto")try{resolved=Intl.getCanonicalLocales(normalized)[0]??"en"}catch{}return resolvedLocaleCache.size>=64&&resolvedLocaleCache.clear(),resolvedLocaleCache.set(raw,resolved),resolved}function cacheKey(locale,options){const localeKey=locale;return options?`${localeKey}\0${JSON.stringify(options,Object.keys(options).sort())}`:localeKey}function getCached(cache,key,create){const existing=cache.get(key);if(existing!==void 0)return cache.delete(key),cache.set(key,existing),existing;if(cache.size>=64){const oldest=cache.keys().next().value;oldest!==void 0&&cache.delete(oldest)}const created=create();return cache.set(key,created),created}function getFormatter(locale,options,cache,create){const safeLocale=resolveIntlLocale(locale);return getCached(cache,cacheKey(safeLocale,options),()=>create(safeLocale))}function getNumberFormat(locale,options){return getFormatter(locale,options,numberFormatCache,safeLocale=>new Intl.NumberFormat(safeLocale,options))}function getDateTimeFormat(locale,options){return getFormatter(locale,options,dateTimeFormatCache,safeLocale=>new Intl.DateTimeFormat(safeLocale,options))}function getDisplayNames(locale,options){return getFormatter(locale,options,displayNamesCache,safeLocale=>new Intl.DisplayNames([safeLocale],options))}function getListFormat(locale,options){return getFormatter(locale,options,listFormatCache,safeLocale=>new Intl.ListFormat(safeLocale,options))}function getRelativeTimeFormat(locale,options){return getFormatter(locale,options,relativeTimeFormatCache,safeLocale=>new Intl.RelativeTimeFormat(safeLocale,options))}function getPluralRules(locale,options){return getFormatter(locale,options,pluralRulesCache,safeLocale=>new Intl.PluralRules(safeLocale,options))}function getCollator(locale,options){return getFormatter(locale,options,collatorCache,safeLocale=>new Intl.Collator(safeLocale,options))}function getSegmenter(locale,options){return getFormatter(locale,options,segmenterCache,safeLocale=>new Intl.Segmenter(safeLocale,options))}export{getCollator,getDateTimeFormat,getDisplayNames,getListFormat,getNumberFormat,getPluralRules,getRelativeTimeFormat,getSegmenter,resolveIntlLocale};
@@ -17,3 +17,49 @@
17
17
  * undefined, init)` — since only an event dispatched `cancelable` can be cancelled at all.
18
18
  */
19
19
  export declare function installInvalidEventAlias(host:EventTarget,emitAlias:(init:{cancelable:true;})=>Event|void):void;
20
+ /**
21
+ * Runs `run` (a control's own `internals.checkValidity()` call) in a scope where a synchronously
22
+ * dispatched `invalid` event on `host` is known to come from a **silent, static** validity query,
23
+ * not from interactive validation. Pair with `installInteractionOnInvalid()`, which reads this
24
+ * scope to decide whether that same `invalid` event should mark the control as user-interacted.
25
+ *
26
+ * @param host The control whose `internals.checkValidity()` is about to run.
27
+ * @param run Performs the static check (typically `() => this.internals.checkValidity()`) and
28
+ * returns its result.
29
+ */
30
+ export declare function withStaticValidityCheck<T>(host:EventTarget,run:()=>T):T;
31
+ /**
32
+ * Reads the scope `withStaticValidityCheck()` sets: true while `host`'s own `internals.checkValidity()`
33
+ * call is synchronously on the stack. For a control whose `invalid` targeting is more than "did this
34
+ * fire on the host itself" (a group that also owns other form-associated children and listens for
35
+ * their `invalid` events in the capture phase, say), this is the lower-level primitive to gate a
36
+ * bespoke listener with directly; `installInteractionOnInvalid()` is the convenience wrapper for the
37
+ * common host-only case.
38
+ */
39
+ export declare function isStaticValidityCheckInProgress(host:EventTarget):boolean;
40
+ /**
41
+ * Marks `host` as user-interacted whenever a native `invalid` event targets it directly, unless
42
+ * that event was raised synchronously inside a `withStaticValidityCheck()` scope.
43
+ *
44
+ * The platform dispatches the exact same `ElementInternals`-sourced `invalid` event, with no
45
+ * discriminator on it at all, for every path that revalidates a form-associated element:
46
+ * `checkValidity()` (silent — must never touch a pristine control's interaction state, however
47
+ * invalid the control already is), `reportValidity()`, and — the path nothing in this library
48
+ * previously observed — a submission attempt (`requestSubmit()`, a submit button, or implicit
49
+ * Enter submission), which is exactly when native `:user-invalid` starts matching. Listening for
50
+ * `invalid` itself, rather than wrapping `reportValidity()`, is what makes the submission path
51
+ * observable at all: a submission attempt never calls the control's own `reportValidity()` method,
52
+ * it drives `ElementInternals` directly.
53
+ *
54
+ * LIMITATION: a form's own **static** `form.checkValidity()` fires this identical event, from this
55
+ * identical `ElementInternals`, for every invalid participant — nothing distinguishes "the form is
56
+ * quietly asking every control whether it's valid" from "the form is attempting to submit and this
57
+ * control is one of the blockers" once the event reaches an individual control. This function
58
+ * resolves that ambiguity by marking interaction, the same as it would for a real submission
59
+ * attempt, since a form-level static check cannot be told apart from one on the receiving end.
60
+ *
61
+ * @param host The element whose own `invalid` events count toward interaction.
62
+ * @param markInteracted Records that `host` has now been "touched" for `:state(user-valid)`/
63
+ * `:state(user-invalid)` purposes and re-syncs whatever reflects those states.
64
+ */
65
+ export declare function installInteractionOnInvalid(host:EventTarget,markInteracted:()=>void):void;
@@ -1 +1 @@
1
- function installInvalidEventAlias(host,emitAlias){host.addEventListener("invalid",event=>{if(event.composedPath()[0]!==host)return;emitAlias({cancelable:!0})?.defaultPrevented&&event.preventDefault()})}export{installInvalidEventAlias};
1
+ function installInvalidEventAlias(host,emitAlias){host.addEventListener("invalid",event=>{if(!targetsHost(event,host))return;emitAlias({cancelable:!0})?.defaultPrevented&&event.preventDefault()})}function targetsHost(event,host){return event.composedPath()[0]===host}const staticValidityCheckDepth=new WeakMap;function withStaticValidityCheck(host,run){staticValidityCheckDepth.set(host,(staticValidityCheckDepth.get(host)??0)+1);try{return run()}finally{const depth=(staticValidityCheckDepth.get(host)??1)-1;depth<=0?staticValidityCheckDepth.delete(host):staticValidityCheckDepth.set(host,depth)}}function isStaticValidityCheckInProgress(host){return(staticValidityCheckDepth.get(host)??0)>0}function installInteractionOnInvalid(host,markInteracted){host.addEventListener("invalid",event=>{targetsHost(event,host)&&(isStaticValidityCheckInProgress(host)||markInteracted())})}export{installInteractionOnInvalid,installInvalidEventAlias,isStaticValidityCheckInProgress,withStaticValidityCheck};
@@ -65,6 +65,30 @@ export declare function setLyraLocale(locale:string):void;
65
65
  /** Return the current page-level locale. */
66
66
  export declare function getLyraLocale():string;
67
67
  /**
68
+ * Resolves a `locale` argument for a standalone, host-less locale-aware utility function --
69
+ * `formatNumber()`/`formatDate()`/`formatRelativeTime()`/`formatBytes()` (`utilities/format.ts`)
70
+ * and `binValues()` (`components/charts/chart/histogram-bin.ts`) are the current callers. These
71
+ * have no component host to inherit a locale from the way {@link inheritedLocale} does, so an
72
+ * omitted, empty/whitespace, or `'auto'` value means {@link setLyraLocale}'s active locale instead
73
+ * -- the one piece of that inheritance chain a plain function call can still observe. A
74
+ * non-empty, non-`'auto'` value is returned unchanged and stays authoritative over the active
75
+ * locale, exactly like an explicit argument always has.
76
+ *
77
+ * This deliberately stops at the active locale and does NOT fall through to `<html lang>` (let
78
+ * alone `navigator.language`, which no part of this library's resolution chain reads) the way
79
+ * {@link inheritedLocale} does for a component host with no closer signal: a document's `lang`
80
+ * attribute is metadata a *host element* inherits by walking the DOM, and a bare function call
81
+ * has no host to walk from. Silently reading the document here would also break the one
82
+ * compatibility guarantee this function exists to preserve -- see the next paragraph.
83
+ *
84
+ * `activeLocale` is `''` before any `setLyraLocale()` call, and `''` is returned as-is (never
85
+ * coerced to `'en'` here): every `Intl` cache getter's own `resolveIntlLocale()` step
86
+ * (`internal/intl-cache.ts`) already normalizes an empty/undefined locale to `'en'`, so an app
87
+ * that never calls `setLyraLocale()` gets exactly the deterministic English output it always has
88
+ * -- this function changes nothing for that app.
89
+ */
90
+ export declare function resolveActiveOrExplicitLocale(locale:string|undefined):string|undefined;
91
+ /**
68
92
  * Subscribe to active-locale selection changes and registrations that can alter the active
69
93
  * locale's messages or direction. Unrelated catalog registrations are registry-only and do not
70
94
  * fire this channel. The returned function is safe to call repeatedly.
@@ -1 +1 @@
1
- import{devWarnOnce}from"./dev-mode-attribute-warning.js";import{getPluralRules}from"./intl-cache.js";const MAX_LOCALE_CANDIDATES=64,MAX_LOCALE_SUBTAGS=32,MAX_LOCALE_TAG_LENGTH=255,MAX_LOCALE_CACHE_ENTRIES=128,MAX_CACHEABLE_LOCALE_LENGTH=512,LEGACY_LOCALE_PATTERN=/^[a-z0-9]{1,32}(?:-[a-z0-9]{1,32})*$/,locales=new Map,localePublicTags=new Map,localeMeta=new Map,wellFormedLocales=new Set,exactOnlyLocales=new Set,localeCatalogRevisions=new Map,listeners=new Set,hostLocaleListeners=new Set,hostLocaleFinalizer=new FinalizationRegistry(subscription=>{hostLocaleListeners.delete(subscription)}),ownerDocumentsWithBrowsingContext=new WeakSet,registryListeners=new Set;let activeLocale="",catalogRevision=0;const localeIdentityCache=new Map,localeCandidateCache=new Map;function cacheBounded(cache,key,value){cache.size>=MAX_LOCALE_CACHE_ENTRIES&&cache.clear(),cache.set(key,value)}function subtagCountWithinBounds(tag){if(tag.length>MAX_LOCALE_TAG_LENGTH)return!1;let count=tag?1:0;for(let index=0;index<tag.length;index+=1)if(tag.charCodeAt(index)===45&&++count>MAX_LOCALE_SUBTAGS)return!1;return!0}function localeIdentity(locale){const normalized=typeof locale=="string"?locale.trim().replace(/_/g,"-"):"";if(!normalized)return{publicTag:"",lookupKey:"",wellFormed:!1,candidateBounded:!0,storable:!1};const cached=normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH?localeIdentityCache.get(normalized):void 0;if(cached)return cached;let publicTag=normalized.toLowerCase(),wellFormed=!1;try{const canonical=Intl.getCanonicalLocales(normalized)[0];canonical&&(publicTag=canonical,wellFormed=!0)}catch{}const lookupKey=publicTag.toLowerCase(),candidateBounded=subtagCountWithinBounds(lookupKey),identity={publicTag,lookupKey,wellFormed,candidateBounded,storable:wellFormed||candidateBounded&&LEGACY_LOCALE_PATTERN.test(lookupKey)};return normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH&&cacheBounded(localeIdentityCache,normalized,identity),identity}function storedLocaleIdentity(locale,required){if(typeof locale!="string")throw new TypeError("A locale must be a string.");const identity=localeIdentity(locale);if(!identity.publicTag){if(!required)return identity;throw new TypeError("A locale is required.")}if(!identity.storable)throw new TypeError("The locale must be BCP-47 or a bounded alphanumeric custom tag.");return identity}function canonicalizeLyraLocale(locale){const identity=localeIdentity(locale);return identity.storable?identity.publicTag:"en"}function regionalFallbacks(requestedKey,limit,wellFormed){if(limit<=0||!wellFormed)return[];const separator=requestedKey.indexOf("-"),language=separator===-1?requestedKey:requestedKey.slice(0,separator);if(!language)return[];const requested=new Set(requestedKey.split("-")),score=key=>key.split("-").filter(subtag=>requested.has(subtag)).length;return[...locales.keys()].filter(key=>wellFormedLocales.has(key)&&!exactOnlyLocales.has(key)&&(key===language||key.startsWith(`${language}-`))&&!isPrefixOf(key,requestedKey)).sort((a,b)=>score(b)-score(a)||(a<b?-1:a>b?1:0)).slice(0,limit)}function isPrefixOf(key,requestedKey){return key===requestedKey||requestedKey.startsWith(`${key}-`)}function localeCandidates(locale){const identity=localeIdentity(locale),normalized=identity.lookupKey;if(!normalized)return["en"];const cached=normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH?localeCandidateCache.get(normalized):void 0;if(cached)return[...cached];const candidates=[];if((identity.wellFormed||identity.candidateBounded)&&candidates.push(normalized),identity.candidateBounded){for(let index=normalized.length-1;index>=0;index-=1)normalized.charCodeAt(index)===45&&index>0&&candidates.push(normalized.slice(0,index));const regionalBudget=Math.max(0,MAX_LOCALE_CANDIDATES-candidates.length-1);candidates.push(...regionalFallbacks(normalized,regionalBudget,identity.wellFormed))}else if(identity.wellFormed){const separator=normalized.indexOf("-");separator>0&&candidates.push(normalized.slice(0,separator))}candidates.includes("en")||candidates.push("en");const frozen=Object.freeze([...candidates]);return normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH&&cacheBounded(localeCandidateCache,normalized,frozen),candidates}function lyraLocaleCatalogVersion(locale){return localeCandidates(locale).map(candidate=>localeCatalogRevisions.get(candidate)??0).join(",")}function getRegisteredLyraLocales(){const keys=new Set(["en",...localePublicTags.values()]);return Object.freeze([...keys].sort())}const NO_REGISTERED_LOCALE_KEYS=Object.freeze([]);function getRegisteredLyraLocaleKeys(locale){const identity=localeIdentity(locale);if(!identity.lookupKey)return NO_REGISTERED_LOCALE_KEYS;const catalog=locales.get(identity.lookupKey);return catalog?Object.freeze(Object.keys(catalog)):NO_REGISTERED_LOCALE_KEYS}function subscribeLyraLocaleRegistry(listener){return registryListeners.add(listener),()=>registryListeners.delete(listener)}const MAX_CATALOG_MESSAGES=4096,MAX_CATALOG_PROPERTY_READS=MAX_CATALOG_MESSAGES*2,MAX_MESSAGE_KEY_LENGTH=256,PLURAL_CATEGORIES=new Set(["zero","one","two","few","many","other"]),trustedMessageRecords=new WeakSet;function isPlainRecord(value){if(value===null||typeof value!="object"||Array.isArray(value))return!1;try{const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}catch{return!1}}function ownDataValue(record,key){try{const descriptor=Object.getOwnPropertyDescriptor(record,key);return!descriptor||!("value"in descriptor)?{found:!1}:{found:!0,value:descriptor.value}}catch{return{found:!1}}}function snapshotPluralMessage(value){if(!isPlainRecord(value))return;const snapshot=Object.create(null);let count=0;try{for(const key in value){if(++count>PLURAL_CATEGORIES.size||!PLURAL_CATEGORIES.has(key)||!Object.prototype.hasOwnProperty.call(value,key))return;const entry=ownDataValue(value,key);if(!entry.found||typeof entry.value!="string")return;snapshot[key]=entry.value}}catch{return}if(typeof snapshot.other!="string")return;const frozen=Object.freeze(snapshot);return trustedMessageRecords.add(frozen),frozen}function snapshotMessage(value){return typeof value=="string"?value:snapshotPluralMessage(value)}function snapshotCatalog(strings){const snapshot=Object.create(null);if(!isPlainRecord(strings)){const frozen2=Object.freeze(snapshot);return trustedMessageRecords.add(frozen2),frozen2}let keys;try{keys=Reflect.ownKeys(strings).slice(0,MAX_CATALOG_PROPERTY_READS)}catch{const frozen2=Object.freeze(snapshot);return trustedMessageRecords.add(frozen2),frozen2}let count=0;for(const key of keys){if(count>=MAX_CATALOG_MESSAGES)break;if(typeof key!="string"||!key||key.length>MAX_MESSAGE_KEY_LENGTH)continue;let descriptor;try{descriptor=Reflect.getOwnPropertyDescriptor(strings,key)}catch{continue}if(!descriptor?.enumerable||!("value"in descriptor))continue;count+=1;const message=snapshotMessage(descriptor.value);message!==void 0&&(snapshot[key]=message)}const frozen=Object.freeze(snapshot);return trustedMessageRecords.add(frozen),frozen}function mergeCatalogs(current,incoming){const merged=Object.assign(Object.create(null),current??{},incoming);return Object.freeze(merged),trustedMessageRecords.add(merged),merged}function snapshotLocaleMeta(meta){if(meta===void 0)return;if(!isPlainRecord(meta))return Object.freeze({});const snapshot={},dir=ownDataValue(meta,"dir");dir.found&&(dir.value==="ltr"||dir.value==="rtl")&&(snapshot.dir=dir.value);const name=ownDataValue(meta,"name");return name.found&&typeof name.value=="string"&&(snapshot.name=name.value),Object.freeze(snapshot)}function snapshotLyraLocaleStrings(strings){return snapshotCatalog(strings)}function safeMessageAt(source,key){if(!isPlainRecord(source))return;if(trustedMessageRecords.has(source))return source[key];const entry=ownDataValue(source,key);return entry.found?snapshotMessage(entry.value):void 0}function deliverLocaleListeners(groups,operation){const errors=[];for(const group of groups)for(const listener of group)try{listener()}catch(error){errors.push(error)}if(errors.length>0)throw new AggregateError(errors,`${operation} committed, but ${errors.length} locale subscriber${errors.length===1?"":"s"} failed.`)}function localeUsesCatalog(locale,lookupKey){return localeCandidates(locale).includes(lookupKey)}function ownerView(host){try{return host.ownerDocument.defaultView}catch{return}}function recordLyraOwnerDocumentConnection(host){ownerView(host)&&ownerDocumentsWithBrowsingContext.add(host.ownerDocument)}function forgetHostLocaleSubscription(subscription){hostLocaleListeners.delete(subscription),hostLocaleFinalizer.unregister(subscription)}function liveHostLocaleSubscriptions(){const live=[];for(const subscription of[...hostLocaleListeners]){const host=subscription.host.deref();if(!host||!host.isConnected||ownerDocumentsWithBrowsingContext.has(host.ownerDocument)&&ownerView(host)===null){forgetHostLocaleSubscription(subscription);continue}live.push({host})}return live}function registerLocale(locale,strings,meta,exactOnly){const identity=storedLocaleIdentity(locale,!0),key=identity.lookupKey,incomingStrings=snapshotCatalog(strings),incomingMeta=snapshotLocaleMeta(meta),isNewLocale=!locales.has(key),candidateTopologyChanged=isNewLocale||exactOnly&&!exactOnlyLocales.has(key)||identity.wellFormed&&!wellFormedLocales.has(key);exactOnly&&exactOnlyLocales.add(key),identity.wellFormed&&wellFormedLocales.add(key),locales.set(key,mergeCatalogs(locales.get(key),incomingStrings)),localePublicTags.set(key,identity.publicTag),incomingMeta&&localeMeta.set(key,Object.freeze({...localeMeta.get(key)??{},...incomingMeta})),localeCatalogRevisions.set(key,++catalogRevision),candidateTopologyChanged&&(pluralLocaleCache.clear(),localeCandidateCache.clear());const activeSnapshot=activeLocale&&localeUsesCatalog(activeLocale,key)?[...listeners]:[],hostSnapshot=liveHostLocaleSubscriptions().filter(({host})=>localeUsesCatalog(inheritedLocale(host),key)).map(({host})=>()=>host.requestUpdate()),registrySnapshot=isNewLocale?[...registryListeners]:[];deliverLocaleListeners([activeSnapshot,hostSnapshot,registrySnapshot],`registerLyraLocale(${JSON.stringify(identity.publicTag)})`)}function registerLyraLocale(locale,strings,meta){registerLocale(locale,strings,meta,!1)}function registerLyraExactLocale(locale,strings,meta){registerLocale(locale,strings,meta,!0)}function getLyraLocaleDirection(locale){const identity=localeIdentity(locale);if(!identity.publicTag)return"ltr";for(const candidate of localeCandidates(identity.publicTag)){const declared=localeMeta.get(candidate)?.dir;if(declared)return declared}try{const resolved=new Intl.Locale(identity.publicTag);return(resolved.textInfo?.direction??resolved.getTextInfo?.().direction)==="rtl"?"rtl":"ltr"}catch{return"ltr"}}function setLyraLocale(locale){const next=storedLocaleIdentity(locale,!1).publicTag;if(activeLocale===next)return;const hostSnapshot=liveHostLocaleSubscriptions(),previousHostLocales=hostSnapshot.map(({host})=>inheritedLocale(host));activeLocale=next;const affectedHostListeners=hostSnapshot.filter(({host},index)=>inheritedLocale(host)!==previousHostLocales[index]).map(({host})=>()=>host.requestUpdate());deliverLocaleListeners([[...listeners],affectedHostListeners],`setLyraLocale(${JSON.stringify(next)})`)}function getLyraLocale(){return activeLocale}function subscribeLyraLocale(listener){return listeners.add(listener),()=>listeners.delete(listener)}function subscribeLyraLocaleForHost(host){recordLyraOwnerDocumentConnection(host);const subscription={host:new WeakRef(host)};return hostLocaleListeners.add(subscription),hostLocaleFinalizer.register(host,subscription,subscription),()=>forgetHostLocaleSubscription(subscription)}function composedParentElement(element){if(element.parentElement)return element.parentElement;const root=element.getRootNode(),candidate=root.host;return root.nodeType===11&&candidate!==null&&typeof candidate=="object"&&typeof candidate.getAttribute=="function"?candidate:null}function flattenedParentElement(element){const slot=element.assignedSlot;return slot!==null&&typeof slot=="object"&&typeof slot.getAttribute=="function"?slot:composedParentElement(element)}function inheritedLocale(host){const explicit=host.getAttribute("locale")||host.getAttribute("lang");if(explicit)return canonicalizeLyraLocale(explicit);if(host.getAttribute("lang")==="")return activeLocale||"en";const documentElement=host.ownerDocument?.documentElement;let parent=composedParentElement(host);for(;parent;){const isDocumentElement=parent===documentElement,locale=isDocumentElement?parent.getAttribute("locale"):parent.getAttribute("locale")||parent.getAttribute("lang");if(locale)return canonicalizeLyraLocale(locale);if(!isDocumentElement&&parent.getAttribute("lang")==="")return activeLocale||"en";parent=composedParentElement(parent)}if(activeLocale)return activeLocale;const documentLocale=documentElement?.getAttribute("lang");return documentLocale?canonicalizeLyraLocale(documentLocale):"en"}const cacheableLocaleHosts=new WeakSet,resolvedLocaleCache=new WeakMap,resolvedDirectionCache=new WeakMap;function enableLyraLocaleCache(host){cacheableLocaleHosts.add(host)}function invalidateLyraLocaleCache(host){resolvedLocaleCache.delete(host),resolvedDirectionCache.delete(host)}function resolveLyraLocale(host){if(!cacheableLocaleHosts.has(host))return inheritedLocale(host);let locale=resolvedLocaleCache.get(host);return locale===void 0&&(locale=inheritedLocale(host),resolvedLocaleCache.set(host,locale)),locale}function inheritedDirection(host){const explicit=host.getAttribute("dir")?.toLowerCase();if(explicit==="rtl"||explicit==="ltr")return explicit;const view=ownerView(host);if(view)try{const getComputedStyle=view.getComputedStyle;if(typeof getComputedStyle=="function"){const computed=getComputedStyle.call(view,host).direction;if(computed==="rtl"||computed==="ltr")return computed}}catch{}let parent=flattenedParentElement(host);for(;parent;){const inherited=parent.getAttribute("dir")?.toLowerCase();if(inherited==="rtl"||inherited==="ltr")return inherited;parent=flattenedParentElement(parent)}return"ltr"}function resolveLyraDirection(host){if(!cacheableLocaleHosts.has(host))return inheritedDirection(host);let direction=resolvedDirectionCache.get(host);return direction===void 0&&(direction=inheritedDirection(host),resolvedDirectionCache.set(host,direction)),direction}function peekLyraLocale(host){return resolvedLocaleCache.get(host)}function peekLyraDirection(host){return resolvedDirectionCache.get(host)}const PLURAL_CATEGORY_FALLBACKS={zero:["zero","other"],one:["one","other"],two:["two","few","many","other"],few:["few","many","other"],many:["many","few","other"],other:["other"]};function pluralSelector(values){let raw;try{raw=values.pluralCount??values.count}catch{return}return typeof raw=="number"&&Number.isFinite(raw)?raw:void 0}const pluralLocaleCache=new Map,MAX_PLURAL_LOCALE_ENTRIES=64;function pluralLocale(locale){const cached=pluralLocaleCache.get(locale);if(cached!==void 0)return cached;const resolved=localeCandidates(locale)[0];return pluralLocaleCache.size>=MAX_PLURAL_LOCALE_ENTRIES&&pluralLocaleCache.clear(),pluralLocaleCache.set(locale,resolved),resolved}function selectPluralMessage(message,locale,count){if(count===void 0)return message.other;const tag=pluralLocale(locale),category=getPluralRules(tag).select(count);for(const candidate of PLURAL_CATEGORY_FALLBACKS[category]??PLURAL_CATEGORY_FALLBACKS.other){const text=message[candidate];if(text!==void 0)return text}return message.other}function isEnglishLocale(locale){const lower=locale.toLowerCase();return lower==="en"||lower.startsWith("en-")}function warnLocaleFallback(locale,key){isEnglishLocale(locale)||devWarnOnce(`lyra-locale-fallback:${locale}:${key}`,`Lyra localization: no "${key}" message registered for locale "${locale}"; falling back to the English default. Register it with registerLyraLocale(), or accept the fallback intentionally for a still-partial catalog.`)}function resolveLyraString(host,key,overrides,fallback,values,defaults){let message=safeMessageAt(overrides,key);message===void 0&&typeof fallback=="string"&&(message=fallback);let locale;if(message===void 0){locale=resolveLyraLocale(host);for(const candidate of localeCandidates(locale)){const registered=safeMessageAt(locales.get(candidate),key);if(registered!==void 0){message=registered;break}}message===void 0&&warnLocaleFallback(locale,key)}message??=safeMessageAt(defaults,key)??key;let text;return typeof message!="string"?(locale??=resolveLyraLocale(host),text=selectPluralMessage(message,locale,values?pluralSelector(values):void 0)):text=message,values?text.replace(/\{(\w+)\}/g,(match,name)=>{try{const value=values[name];return typeof value=="string"||typeof value=="number"?String(value):match}catch{return match}}):text}function resolveLocalizedParts(template,interpolate){const privateUse=new Set;for(let index=0;index<template.length;index+=1){const code=template.charCodeAt(index);code>=57344&&code<=63743&&privateUse.add(code)}let marker="";for(let code=57344;code<=63743;code+=1)if(!privateUse.has(code)){marker=String.fromCharCode(code);break}if(!marker){const counts=new Uint32Array(65536);for(let index=0;index<template.length;index+=1){const code=template.charCodeAt(index);counts[code]=(counts[code]??0)+1}let leastCode=0,leastCount=Number.POSITIVE_INFINITY;for(let code=0;code<counts.length;code+=1){const count=counts[code]??0;if(count===0){marker=String.fromCharCode(code);break}count<leastCount&&(leastCode=code,leastCount=count)}if(!marker){const followers=new Uint8Array(65536);for(let index=0;index+1<template.length;index+=1)template.charCodeAt(index)===leastCode&&(followers[template.charCodeAt(index+1)]=1);let follower=0;for(;follower<followers.length&&followers[follower]!==0;)follower+=1;marker=String.fromCharCode(leastCode,follower<followers.length?follower:leastCode)}}return interpolate(marker).split(marker)}export{canonicalizeLyraLocale,enableLyraLocaleCache,getLyraLocale,getLyraLocaleDirection,getRegisteredLyraLocaleKeys,getRegisteredLyraLocales,invalidateLyraLocaleCache,lyraLocaleCatalogVersion,peekLyraDirection,peekLyraLocale,recordLyraOwnerDocumentConnection,registerLyraExactLocale,registerLyraLocale,resolveLocalizedParts,resolveLyraDirection,resolveLyraLocale,resolveLyraString,setLyraLocale,snapshotLyraLocaleStrings,subscribeLyraLocale,subscribeLyraLocaleForHost,subscribeLyraLocaleRegistry};
1
+ import{devWarnOnce}from"./dev-mode-attribute-warning.js";import{getPluralRules}from"./intl-cache.js";const MAX_LOCALE_CANDIDATES=64,MAX_LOCALE_SUBTAGS=32,MAX_LOCALE_TAG_LENGTH=255,MAX_LOCALE_CACHE_ENTRIES=128,MAX_CACHEABLE_LOCALE_LENGTH=512,LEGACY_LOCALE_PATTERN=/^[a-z0-9]{1,32}(?:-[a-z0-9]{1,32})*$/,locales=new Map,localePublicTags=new Map,localeMeta=new Map,wellFormedLocales=new Set,exactOnlyLocales=new Set,localeCatalogRevisions=new Map,listeners=new Set,hostLocaleListeners=new Set,hostLocaleFinalizer=new FinalizationRegistry(subscription=>{hostLocaleListeners.delete(subscription)}),ownerDocumentsWithBrowsingContext=new WeakSet,registryListeners=new Set;let activeLocale="",catalogRevision=0;const localeIdentityCache=new Map,localeCandidateCache=new Map;function cacheBounded(cache,key,value){cache.size>=MAX_LOCALE_CACHE_ENTRIES&&cache.clear(),cache.set(key,value)}function subtagCountWithinBounds(tag){if(tag.length>MAX_LOCALE_TAG_LENGTH)return!1;let count=tag?1:0;for(let index=0;index<tag.length;index+=1)if(tag.charCodeAt(index)===45&&++count>MAX_LOCALE_SUBTAGS)return!1;return!0}function localeIdentity(locale){const normalized=typeof locale=="string"?locale.trim().replace(/_/g,"-"):"";if(!normalized)return{publicTag:"",lookupKey:"",wellFormed:!1,candidateBounded:!0,storable:!1};const cached=normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH?localeIdentityCache.get(normalized):void 0;if(cached)return cached;let publicTag=normalized.toLowerCase(),wellFormed=!1;try{const canonical=Intl.getCanonicalLocales(normalized)[0];canonical&&(publicTag=canonical,wellFormed=!0)}catch{}const lookupKey=publicTag.toLowerCase(),candidateBounded=subtagCountWithinBounds(lookupKey),identity={publicTag,lookupKey,wellFormed,candidateBounded,storable:wellFormed||candidateBounded&&LEGACY_LOCALE_PATTERN.test(lookupKey)};return normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH&&cacheBounded(localeIdentityCache,normalized,identity),identity}function storedLocaleIdentity(locale,required){if(typeof locale!="string")throw new TypeError("A locale must be a string.");const identity=localeIdentity(locale);if(!identity.publicTag){if(!required)return identity;throw new TypeError("A locale is required.")}if(!identity.storable)throw new TypeError("The locale must be BCP-47 or a bounded alphanumeric custom tag.");return identity}function canonicalizeLyraLocale(locale){const identity=localeIdentity(locale);return identity.storable?identity.publicTag:"en"}function regionalFallbacks(requestedKey,limit,wellFormed){if(limit<=0||!wellFormed)return[];const separator=requestedKey.indexOf("-"),language=separator===-1?requestedKey:requestedKey.slice(0,separator);if(!language)return[];const requested=new Set(requestedKey.split("-")),score=key=>key.split("-").filter(subtag=>requested.has(subtag)).length;return[...locales.keys()].filter(key=>wellFormedLocales.has(key)&&!exactOnlyLocales.has(key)&&(key===language||key.startsWith(`${language}-`))&&!isPrefixOf(key,requestedKey)).sort((a,b)=>score(b)-score(a)||(a<b?-1:a>b?1:0)).slice(0,limit)}function isPrefixOf(key,requestedKey){return key===requestedKey||requestedKey.startsWith(`${key}-`)}function localeCandidates(locale){const identity=localeIdentity(locale),normalized=identity.lookupKey;if(!normalized)return["en"];const cached=normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH?localeCandidateCache.get(normalized):void 0;if(cached)return[...cached];const candidates=[];if((identity.wellFormed||identity.candidateBounded)&&candidates.push(normalized),identity.candidateBounded){for(let index=normalized.length-1;index>=0;index-=1)normalized.charCodeAt(index)===45&&index>0&&candidates.push(normalized.slice(0,index));const regionalBudget=Math.max(0,MAX_LOCALE_CANDIDATES-candidates.length-1);candidates.push(...regionalFallbacks(normalized,regionalBudget,identity.wellFormed))}else if(identity.wellFormed){const separator=normalized.indexOf("-");separator>0&&candidates.push(normalized.slice(0,separator))}candidates.includes("en")||candidates.push("en");const frozen=Object.freeze([...candidates]);return normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH&&cacheBounded(localeCandidateCache,normalized,frozen),candidates}function lyraLocaleCatalogVersion(locale){return localeCandidates(locale).map(candidate=>localeCatalogRevisions.get(candidate)??0).join(",")}function getRegisteredLyraLocales(){const keys=new Set(["en",...localePublicTags.values()]);return Object.freeze([...keys].sort())}const NO_REGISTERED_LOCALE_KEYS=Object.freeze([]);function getRegisteredLyraLocaleKeys(locale){const identity=localeIdentity(locale);if(!identity.lookupKey)return NO_REGISTERED_LOCALE_KEYS;const catalog=locales.get(identity.lookupKey);return catalog?Object.freeze(Object.keys(catalog)):NO_REGISTERED_LOCALE_KEYS}function subscribeLyraLocaleRegistry(listener){return registryListeners.add(listener),()=>registryListeners.delete(listener)}const MAX_CATALOG_MESSAGES=4096,MAX_CATALOG_PROPERTY_READS=MAX_CATALOG_MESSAGES*2,MAX_MESSAGE_KEY_LENGTH=256,PLURAL_CATEGORIES=new Set(["zero","one","two","few","many","other"]),trustedMessageRecords=new WeakSet;function isPlainRecord(value){if(value===null||typeof value!="object"||Array.isArray(value))return!1;try{const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}catch{return!1}}function ownDataValue(record,key){try{const descriptor=Object.getOwnPropertyDescriptor(record,key);return!descriptor||!("value"in descriptor)?{found:!1}:{found:!0,value:descriptor.value}}catch{return{found:!1}}}function snapshotPluralMessage(value){if(!isPlainRecord(value))return;const snapshot=Object.create(null);let count=0;try{for(const key in value){if(++count>PLURAL_CATEGORIES.size||!PLURAL_CATEGORIES.has(key)||!Object.prototype.hasOwnProperty.call(value,key))return;const entry=ownDataValue(value,key);if(!entry.found||typeof entry.value!="string")return;snapshot[key]=entry.value}}catch{return}if(typeof snapshot.other!="string")return;const frozen=Object.freeze(snapshot);return trustedMessageRecords.add(frozen),frozen}function snapshotMessage(value){return typeof value=="string"?value:snapshotPluralMessage(value)}function snapshotCatalog(strings){const snapshot=Object.create(null);if(!isPlainRecord(strings)){const frozen2=Object.freeze(snapshot);return trustedMessageRecords.add(frozen2),frozen2}let keys;try{keys=Reflect.ownKeys(strings).slice(0,MAX_CATALOG_PROPERTY_READS)}catch{const frozen2=Object.freeze(snapshot);return trustedMessageRecords.add(frozen2),frozen2}let count=0;for(const key of keys){if(count>=MAX_CATALOG_MESSAGES)break;if(typeof key!="string"||!key||key.length>MAX_MESSAGE_KEY_LENGTH)continue;let descriptor;try{descriptor=Reflect.getOwnPropertyDescriptor(strings,key)}catch{continue}if(!descriptor?.enumerable||!("value"in descriptor))continue;count+=1;const message=snapshotMessage(descriptor.value);message!==void 0&&(snapshot[key]=message)}const frozen=Object.freeze(snapshot);return trustedMessageRecords.add(frozen),frozen}function mergeCatalogs(current,incoming){const merged=Object.assign(Object.create(null),current??{},incoming);return Object.freeze(merged),trustedMessageRecords.add(merged),merged}function snapshotLocaleMeta(meta){if(meta===void 0)return;if(!isPlainRecord(meta))return Object.freeze({});const snapshot={},dir=ownDataValue(meta,"dir");dir.found&&(dir.value==="ltr"||dir.value==="rtl")&&(snapshot.dir=dir.value);const name=ownDataValue(meta,"name");return name.found&&typeof name.value=="string"&&(snapshot.name=name.value),Object.freeze(snapshot)}function snapshotLyraLocaleStrings(strings){return snapshotCatalog(strings)}function safeMessageAt(source,key){if(!isPlainRecord(source))return;if(trustedMessageRecords.has(source))return source[key];const entry=ownDataValue(source,key);return entry.found?snapshotMessage(entry.value):void 0}function deliverLocaleListeners(groups,operation){const errors=[];for(const group of groups)for(const listener of group)try{listener()}catch(error){errors.push(error)}if(errors.length>0)throw new AggregateError(errors,`${operation} committed, but ${errors.length} locale subscriber${errors.length===1?"":"s"} failed.`)}function localeUsesCatalog(locale,lookupKey){return localeCandidates(locale).includes(lookupKey)}function ownerView(host){try{return host.ownerDocument.defaultView}catch{return}}function recordLyraOwnerDocumentConnection(host){ownerView(host)&&ownerDocumentsWithBrowsingContext.add(host.ownerDocument)}function forgetHostLocaleSubscription(subscription){hostLocaleListeners.delete(subscription),hostLocaleFinalizer.unregister(subscription)}function liveHostLocaleSubscriptions(){const live=[];for(const subscription of[...hostLocaleListeners]){const host=subscription.host.deref();if(!host||!host.isConnected||ownerDocumentsWithBrowsingContext.has(host.ownerDocument)&&ownerView(host)===null){forgetHostLocaleSubscription(subscription);continue}live.push({host})}return live}function registerLocale(locale,strings,meta,exactOnly){const identity=storedLocaleIdentity(locale,!0),key=identity.lookupKey,incomingStrings=snapshotCatalog(strings),incomingMeta=snapshotLocaleMeta(meta),isNewLocale=!locales.has(key),candidateTopologyChanged=isNewLocale||exactOnly&&!exactOnlyLocales.has(key)||identity.wellFormed&&!wellFormedLocales.has(key);exactOnly&&exactOnlyLocales.add(key),identity.wellFormed&&wellFormedLocales.add(key),locales.set(key,mergeCatalogs(locales.get(key),incomingStrings)),localePublicTags.set(key,identity.publicTag),incomingMeta&&localeMeta.set(key,Object.freeze({...localeMeta.get(key)??{},...incomingMeta})),localeCatalogRevisions.set(key,++catalogRevision),candidateTopologyChanged&&(pluralLocaleCache.clear(),localeCandidateCache.clear());const activeSnapshot=activeLocale&&localeUsesCatalog(activeLocale,key)?[...listeners]:[],hostSnapshot=liveHostLocaleSubscriptions().filter(({host})=>localeUsesCatalog(inheritedLocale(host),key)).map(({host})=>()=>host.requestUpdate()),registrySnapshot=isNewLocale?[...registryListeners]:[];deliverLocaleListeners([activeSnapshot,hostSnapshot,registrySnapshot],`registerLyraLocale(${JSON.stringify(identity.publicTag)})`)}function registerLyraLocale(locale,strings,meta){registerLocale(locale,strings,meta,!1)}function registerLyraExactLocale(locale,strings,meta){registerLocale(locale,strings,meta,!0)}function getLyraLocaleDirection(locale){const identity=localeIdentity(locale);if(!identity.publicTag)return"ltr";for(const candidate of localeCandidates(identity.publicTag)){const declared=localeMeta.get(candidate)?.dir;if(declared)return declared}try{const resolved=new Intl.Locale(identity.publicTag);return(resolved.textInfo?.direction??resolved.getTextInfo?.().direction)==="rtl"?"rtl":"ltr"}catch{return"ltr"}}function setLyraLocale(locale){const next=storedLocaleIdentity(locale,!1).publicTag;if(activeLocale===next)return;const hostSnapshot=liveHostLocaleSubscriptions(),previousHostLocales=hostSnapshot.map(({host})=>inheritedLocale(host));activeLocale=next;const affectedHostListeners=hostSnapshot.filter(({host},index)=>inheritedLocale(host)!==previousHostLocales[index]).map(({host})=>()=>host.requestUpdate());deliverLocaleListeners([[...listeners],affectedHostListeners],`setLyraLocale(${JSON.stringify(next)})`)}function getLyraLocale(){return activeLocale}function resolveActiveOrExplicitLocale(locale){const trimmed=locale?.trim();return trimmed&&trimmed.toLowerCase()!=="auto"?locale:activeLocale||void 0}function subscribeLyraLocale(listener){return listeners.add(listener),()=>listeners.delete(listener)}function subscribeLyraLocaleForHost(host){recordLyraOwnerDocumentConnection(host);const subscription={host:new WeakRef(host)};return hostLocaleListeners.add(subscription),hostLocaleFinalizer.register(host,subscription,subscription),()=>forgetHostLocaleSubscription(subscription)}function composedParentElement(element){if(element.parentElement)return element.parentElement;const root=element.getRootNode(),candidate=root.host;return root.nodeType===11&&candidate!==null&&typeof candidate=="object"&&typeof candidate.getAttribute=="function"?candidate:null}function flattenedParentElement(element){const slot=element.assignedSlot;return slot!==null&&typeof slot=="object"&&typeof slot.getAttribute=="function"?slot:composedParentElement(element)}function inheritedLocale(host){const explicit=host.getAttribute("locale")||host.getAttribute("lang");if(explicit)return canonicalizeLyraLocale(explicit);if(host.getAttribute("lang")==="")return activeLocale||"en";const documentElement=host.ownerDocument?.documentElement;let parent=composedParentElement(host);for(;parent;){const isDocumentElement=parent===documentElement,locale=isDocumentElement?parent.getAttribute("locale"):parent.getAttribute("locale")||parent.getAttribute("lang");if(locale)return canonicalizeLyraLocale(locale);if(!isDocumentElement&&parent.getAttribute("lang")==="")return activeLocale||"en";parent=composedParentElement(parent)}if(activeLocale)return activeLocale;const documentLocale=documentElement?.getAttribute("lang");return documentLocale?canonicalizeLyraLocale(documentLocale):"en"}const cacheableLocaleHosts=new WeakSet,resolvedLocaleCache=new WeakMap,resolvedDirectionCache=new WeakMap;function enableLyraLocaleCache(host){cacheableLocaleHosts.add(host)}function invalidateLyraLocaleCache(host){resolvedLocaleCache.delete(host),resolvedDirectionCache.delete(host)}function resolveLyraLocale(host){if(!cacheableLocaleHosts.has(host))return inheritedLocale(host);let locale=resolvedLocaleCache.get(host);return locale===void 0&&(locale=inheritedLocale(host),resolvedLocaleCache.set(host,locale)),locale}function inheritedDirection(host){const explicit=host.getAttribute("dir")?.toLowerCase();if(explicit==="rtl"||explicit==="ltr")return explicit;const view=ownerView(host);if(view)try{const getComputedStyle=view.getComputedStyle;if(typeof getComputedStyle=="function"){const computed=getComputedStyle.call(view,host).direction;if(computed==="rtl"||computed==="ltr")return computed}}catch{}let parent=flattenedParentElement(host);for(;parent;){const inherited=parent.getAttribute("dir")?.toLowerCase();if(inherited==="rtl"||inherited==="ltr")return inherited;parent=flattenedParentElement(parent)}return"ltr"}function resolveLyraDirection(host){if(!cacheableLocaleHosts.has(host))return inheritedDirection(host);let direction=resolvedDirectionCache.get(host);return direction===void 0&&(direction=inheritedDirection(host),resolvedDirectionCache.set(host,direction)),direction}function peekLyraLocale(host){return resolvedLocaleCache.get(host)}function peekLyraDirection(host){return resolvedDirectionCache.get(host)}const PLURAL_CATEGORY_FALLBACKS={zero:["zero","other"],one:["one","other"],two:["two","few","many","other"],few:["few","many","other"],many:["many","few","other"],other:["other"]};function pluralSelector(values){let raw;try{raw=values.pluralCount??values.count}catch{return}return typeof raw=="number"&&Number.isFinite(raw)?raw:void 0}const pluralLocaleCache=new Map,MAX_PLURAL_LOCALE_ENTRIES=64;function pluralLocale(locale){const cached=pluralLocaleCache.get(locale);if(cached!==void 0)return cached;const resolved=localeCandidates(locale)[0];return pluralLocaleCache.size>=MAX_PLURAL_LOCALE_ENTRIES&&pluralLocaleCache.clear(),pluralLocaleCache.set(locale,resolved),resolved}function selectPluralMessage(message,locale,count){if(count===void 0)return message.other;const tag=pluralLocale(locale),category=getPluralRules(tag).select(count);for(const candidate of PLURAL_CATEGORY_FALLBACKS[category]??PLURAL_CATEGORY_FALLBACKS.other){const text=message[candidate];if(text!==void 0)return text}return message.other}function isEnglishLocale(locale){const lower=locale.toLowerCase();return lower==="en"||lower.startsWith("en-")}function warnLocaleFallback(locale,key){isEnglishLocale(locale)||devWarnOnce(`lyra-locale-fallback:${locale}:${key}`,`Lyra localization: no "${key}" message registered for locale "${locale}"; falling back to the English default. Register it with registerLyraLocale(), or accept the fallback intentionally for a still-partial catalog.`)}function resolveLyraString(host,key,overrides,fallback,values,defaults){let message=safeMessageAt(overrides,key);message===void 0&&typeof fallback=="string"&&(message=fallback);let locale;if(message===void 0){locale=resolveLyraLocale(host);for(const candidate of localeCandidates(locale)){const registered=safeMessageAt(locales.get(candidate),key);if(registered!==void 0){message=registered;break}}message===void 0&&warnLocaleFallback(locale,key)}message??=safeMessageAt(defaults,key)??key;let text;return typeof message!="string"?(locale??=resolveLyraLocale(host),text=selectPluralMessage(message,locale,values?pluralSelector(values):void 0)):text=message,values?text.replace(/\{(\w+)\}/g,(match,name)=>{try{const value=values[name];return typeof value=="string"||typeof value=="number"?String(value):match}catch{return match}}):text}function resolveLocalizedParts(template,interpolate){const privateUse=new Set;for(let index=0;index<template.length;index+=1){const code=template.charCodeAt(index);code>=57344&&code<=63743&&privateUse.add(code)}let marker="";for(let code=57344;code<=63743;code+=1)if(!privateUse.has(code)){marker=String.fromCharCode(code);break}if(!marker){const counts=new Uint32Array(65536);for(let index=0;index<template.length;index+=1){const code=template.charCodeAt(index);counts[code]=(counts[code]??0)+1}let leastCode=0,leastCount=Number.POSITIVE_INFINITY;for(let code=0;code<counts.length;code+=1){const count=counts[code]??0;if(count===0){marker=String.fromCharCode(code);break}count<leastCount&&(leastCode=code,leastCount=count)}if(!marker){const followers=new Uint8Array(65536);for(let index=0;index+1<template.length;index+=1)template.charCodeAt(index)===leastCode&&(followers[template.charCodeAt(index+1)]=1);let follower=0;for(;follower<followers.length&&followers[follower]!==0;)follower+=1;marker=String.fromCharCode(leastCode,follower<followers.length?follower:leastCode)}}return interpolate(marker).split(marker)}export{canonicalizeLyraLocale,enableLyraLocaleCache,getLyraLocale,getLyraLocaleDirection,getRegisteredLyraLocaleKeys,getRegisteredLyraLocales,invalidateLyraLocaleCache,lyraLocaleCatalogVersion,peekLyraDirection,peekLyraLocale,recordLyraOwnerDocumentConnection,registerLyraExactLocale,registerLyraLocale,resolveActiveOrExplicitLocale,resolveLocalizedParts,resolveLyraDirection,resolveLyraLocale,resolveLyraString,setLyraLocale,snapshotLyraLocaleStrings,subscribeLyraLocale,subscribeLyraLocaleForHost,subscribeLyraLocaleRegistry};