@heartlandone/vega 2.95.0 → 2.96.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 (181) hide show
  1. package/dist/cjs/{app-globals-76815382.js → app-globals-38afea36.js} +7 -7
  2. package/dist/cjs/{code-block-493c7ce7.js → code-block-4126dc3b.js} +1501 -55
  3. package/dist/cjs/{component-value-history-controller-slimmer.abstract-ab21fcbf.js → component-value-history-controller-slimmer.abstract-38ba956e.js} +2 -2
  4. package/dist/cjs/{content-state-fc34a814.js → content-state-50e8a03c.js} +142 -580
  5. package/dist/cjs/{element-appender-slimmer-1d6323c2.js → element-appender-slimmer-7773fdab.js} +115 -0
  6. package/dist/cjs/{image-annotation-action-7c4cd316.js → image-annotation-action-89363de8.js} +2 -2
  7. package/dist/cjs/{image-extension-30a7c10f.js → image-extension-c881c454.js} +2 -2
  8. package/dist/cjs/index.cjs.js +10 -10
  9. package/dist/cjs/{link-extension-92a63cb7.js → link-extension-b7f99a52.js} +2 -2
  10. package/dist/cjs/loader.cjs.js +7 -7
  11. package/dist/cjs/{public-rules-9e1ea1d9.js → public-rules-72894208.js} +3 -3
  12. package/dist/cjs/{range-30219330.js → range-95d41dea.js} +1 -1
  13. package/dist/cjs/{rich-text-editor-required-rule-23bf7485.js → rich-text-editor-required-rule-4d6d2493.js} +1 -1
  14. package/dist/cjs/{split-cell-operation-43752212.js → split-cell-operation-70be116d.js} +2 -2
  15. package/dist/cjs/{token-extension-d123d9d0.js → token-extension-eb828948.js} +35 -11
  16. package/dist/cjs/vega-code-block.cjs.entry.js +3 -3
  17. package/dist/cjs/vega-date-picker_2.cjs.entry.js +1 -1
  18. package/dist/cjs/vega-dropdown_5.cjs.entry.js +27 -4
  19. package/dist/cjs/vega-env-manager-23b8b23c.js +2 -2
  20. package/dist/cjs/vega-popover_2.cjs.entry.js +1 -1
  21. package/dist/cjs/vega-rich-text-content.cjs.entry.js +58 -9
  22. package/dist/cjs/vega-rich-text-editor_4.cjs.entry.js +608 -90
  23. package/dist/cjs/vega-rich-text-table-properties_3.cjs.entry.js +3 -3
  24. package/dist/cjs/vega-section-title.cjs.entry.js +896 -14
  25. package/dist/cjs/vega-time-picker_2.cjs.entry.js +1 -1
  26. package/dist/cjs/vega-tooltip_2.cjs.entry.js +1 -1
  27. package/dist/cjs/vega.cjs.js +7 -7
  28. package/dist/collection/components/vega-combo-box/vega-combo-box.js +2 -2
  29. package/dist/collection/components/vega-dropdown/vega-dropdown.js +30 -7
  30. package/dist/collection/components/vega-input-select/vega-input-select.js +2 -2
  31. package/dist/collection/components/vega-rich-text-content/vega-rich-text-content.css +4 -0
  32. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/block-delete-node-content-strategy.js +29 -0
  33. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/block-delete-text-or-decorator-node-strategy.js +10 -1
  34. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/block-transform-to-list-strategy.js +8 -3
  35. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-annotation-strategy.abstract.js +60 -0
  36. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-item-replace-nest-list-strategy.js +36 -4
  37. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-items-strategy.abstract.js +27 -0
  38. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-nest-items-strategy.js +74 -0
  39. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-remove-list-item-strategy.js +81 -1
  40. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-selection.js +30 -0
  41. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-list-strategy.js +160 -9
  42. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-paragraph-strategy.js +376 -10
  43. package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-unnest-items-strategy.js +104 -0
  44. package/dist/collection/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.js +2 -0
  45. package/dist/collection/components/vega-rich-text-editor/dto/actions/nest-list-items-action.js +12 -0
  46. package/dist/collection/components/vega-rich-text-editor/dto/actions/unnest-list-items-action.js +12 -0
  47. package/dist/collection/components/vega-rich-text-editor/dto/annotations/list-annotation.js +12 -0
  48. package/dist/collection/components/vega-rich-text-editor/dto/blocks/list-block.js +10 -1
  49. package/dist/collection/components/vega-rich-text-editor/dto/blocks/list-item-block.js +11 -3
  50. package/dist/collection/components/vega-rich-text-editor/dto/content-state.js +7 -1
  51. package/dist/collection/components/vega-rich-text-editor/dto/filter-styles-strategies/list-block/list-block-filter-styles-strategy.js +8 -4
  52. package/dist/collection/components/vega-rich-text-editor/dto/renderers/blocks/list-block-renderer.js +34 -1
  53. package/dist/collection/components/vega-rich-text-editor/dto/renderers/blocks/list-item-block-renderer.js +20 -3
  54. package/dist/collection/components/vega-rich-text-editor/extensions/table/annotation-handler/table-annotation-handler-base.js +25 -1
  55. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/element-to-dto-strategy/li-to-rte-list-item-block-strategy.js +2 -0
  56. package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/abstract-delete-content-handler.js +29 -0
  57. package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/bullets-numbers-toolbar-button-slimmer.js +30 -1
  58. package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/abstract-list-keyboard-handler.js +204 -0
  59. package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-shift-tab-outdent-handler.js +42 -0
  60. package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-tab-indent-handler.js +34 -0
  61. package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/list-keyboard-slimmer.js +180 -0
  62. package/dist/collection/components/vega-section-title/slimmers/a11y-tree/build-section-title-a11y-tree.js +54 -0
  63. package/dist/collection/components/vega-section-title/slimmers/renderers/vega-section-title-renderer.js +4 -4
  64. package/dist/collection/components/vega-section-title/vega-section-title.js +18 -2
  65. package/dist/collection/helpers/a11y-tree/a11y-node-dto.js +210 -0
  66. package/dist/collection/helpers/a11y-tree/a11y-tree-applier.js +189 -0
  67. package/dist/collection/helpers/a11y-tree/a11y-tree.types.js +48 -0
  68. package/dist/collection/helpers/a11y-tree/strategies/baseline-strategy.js +78 -0
  69. package/dist/collection/helpers/a11y-tree/strategies/firefox-nvda-strategy.js +56 -0
  70. package/dist/collection/helpers/a11y-tree/strategies/webkit-voiceover-strategy.js +140 -0
  71. package/dist/collection/helpers/a11y-tree/strategy-resolver.js +172 -0
  72. package/dist/collection/helpers/slimmers/a11y-tree-slimmer.js +54 -0
  73. package/dist/collection/helpers/slimmers/element-appender/element-appender-slimmer.js +29 -0
  74. package/dist/collection/helpers/slimmers/element-appender/visibility-modifiers/clip-on-scroll-modifier.js +70 -0
  75. package/dist/collection/helpers/slimmers/element-appender/visibility-modifiers/visibility-modifier.interface.js +1 -0
  76. package/dist/collection/helpers/ui/element-appender.js +16 -0
  77. package/dist/esm/{app-globals-eafcc7a1.js → app-globals-d7b651c1.js} +7 -7
  78. package/dist/esm/{code-block-e12588fe.js → code-block-0a88b481.js} +1495 -51
  79. package/dist/esm/{component-value-history-controller-slimmer.abstract-4e8eb313.js → component-value-history-controller-slimmer.abstract-6846edfa.js} +2 -2
  80. package/dist/esm/{content-state-8032467a.js → content-state-79ca99e5.js} +105 -541
  81. package/dist/esm/{element-appender-slimmer-7fcb944b.js → element-appender-slimmer-73ad10ae.js} +115 -0
  82. package/dist/esm/{image-annotation-action-08a20d5e.js → image-annotation-action-bb299ef1.js} +2 -2
  83. package/dist/esm/{image-extension-b6c7e4a7.js → image-extension-48a96f98.js} +2 -2
  84. package/dist/esm/index.js +8 -8
  85. package/dist/esm/{link-extension-97fcb8fb.js → link-extension-09534514.js} +2 -2
  86. package/dist/esm/loader.js +7 -7
  87. package/dist/esm/{public-rules-c06f0d2a.js → public-rules-5eb03ef0.js} +3 -3
  88. package/dist/esm/{range-e999837f.js → range-d4deb7df.js} +1 -1
  89. package/dist/esm/{rich-text-editor-required-rule-71f8ee98.js → rich-text-editor-required-rule-5bbbce23.js} +1 -1
  90. package/dist/esm/{split-cell-operation-359f8082.js → split-cell-operation-7f3058ad.js} +2 -2
  91. package/dist/esm/{token-extension-f5bf9c21.js → token-extension-40c32bcc.js} +30 -6
  92. package/dist/esm/vega-code-block.entry.js +3 -3
  93. package/dist/esm/vega-date-picker_2.entry.js +1 -1
  94. package/dist/esm/vega-dropdown_5.entry.js +27 -4
  95. package/dist/esm/vega-env-manager-8f8dc473.js +2 -2
  96. package/dist/esm/vega-popover_2.entry.js +1 -1
  97. package/dist/esm/vega-rich-text-content.entry.js +58 -9
  98. package/dist/esm/vega-rich-text-editor_4.entry.js +604 -86
  99. package/dist/esm/vega-rich-text-table-properties_3.entry.js +3 -3
  100. package/dist/esm/vega-section-title.entry.js +897 -15
  101. package/dist/esm/vega-time-picker_2.entry.js +1 -1
  102. package/dist/esm/vega-tooltip_2.entry.js +1 -1
  103. package/dist/esm/vega.js +7 -7
  104. package/dist/sri/vega-sri-manifest.json +94 -94
  105. package/dist/types/components/vega-combo-box/vega-combo-box.d.ts +6 -6
  106. package/dist/types/components/vega-dropdown/types.d.ts +2 -2
  107. package/dist/types/components/vega-dropdown/vega-dropdown.d.ts +32 -9
  108. package/dist/types/components/vega-input-select/vega-input-select.d.ts +6 -6
  109. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-annotation-strategy.abstract.d.ts +36 -0
  110. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-item-replace-nest-list-strategy.d.ts +14 -2
  111. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-items-strategy.abstract.d.ts +22 -0
  112. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-nest-items-strategy.d.ts +21 -0
  113. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-remove-list-item-strategy.d.ts +14 -0
  114. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-selection.d.ts +15 -0
  115. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-list-strategy.d.ts +30 -3
  116. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-paragraph-strategy.d.ts +99 -3
  117. package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-unnest-items-strategy.d.ts +22 -0
  118. package/dist/types/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.d.ts +2 -0
  119. package/dist/types/components/vega-rich-text-editor/dto/actions/nest-list-items-action.d.ts +11 -0
  120. package/dist/types/components/vega-rich-text-editor/dto/actions/unnest-list-items-action.d.ts +11 -0
  121. package/dist/types/components/vega-rich-text-editor/dto/annotations/list-annotation.d.ts +8 -0
  122. package/dist/types/components/vega-rich-text-editor/dto/blocks/list-block.d.ts +6 -1
  123. package/dist/types/components/vega-rich-text-editor/dto/blocks/list-item-block.d.ts +5 -1
  124. package/dist/types/components/vega-rich-text-editor/dto/content-state.d.ts +2 -2
  125. package/dist/types/components/vega-rich-text-editor/dto/renderers/blocks/list-block-renderer.d.ts +2 -0
  126. package/dist/types/components/vega-rich-text-editor/dto/renderers/blocks/list-item-block-renderer.d.ts +8 -0
  127. package/dist/types/components/vega-rich-text-editor/extensions/table/annotation-handler/table-annotation-handler-base.d.ts +18 -0
  128. package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/bullets-numbers-toolbar-button-slimmer.d.ts +8 -0
  129. package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/abstract-list-keyboard-handler.d.ts +99 -0
  130. package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-shift-tab-outdent-handler.d.ts +15 -0
  131. package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-tab-indent-handler.d.ts +15 -0
  132. package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/list-keyboard-slimmer.d.ts +73 -0
  133. package/dist/types/components/vega-section-title/slimmers/a11y-tree/build-section-title-a11y-tree.d.ts +41 -0
  134. package/dist/types/components/vega-section-title/vega-section-title.d.ts +9 -0
  135. package/dist/types/components.d.ts +10 -10
  136. package/dist/types/helpers/a11y-tree/a11y-node-dto.d.ts +173 -0
  137. package/dist/types/helpers/a11y-tree/a11y-tree-applier.d.ts +28 -0
  138. package/dist/types/helpers/a11y-tree/a11y-tree.types.d.ts +137 -0
  139. package/dist/types/helpers/a11y-tree/strategies/baseline-strategy.d.ts +18 -0
  140. package/dist/types/helpers/a11y-tree/strategies/firefox-nvda-strategy.d.ts +16 -0
  141. package/dist/types/helpers/a11y-tree/strategies/webkit-voiceover-strategy.d.ts +23 -0
  142. package/dist/types/helpers/a11y-tree/strategy-resolver.d.ts +59 -0
  143. package/dist/types/helpers/slimmers/a11y-tree-slimmer.d.ts +49 -0
  144. package/dist/types/helpers/slimmers/element-appender/element-appender-slimmer.d.ts +9 -0
  145. package/dist/types/helpers/slimmers/element-appender/visibility-modifiers/clip-on-scroll-modifier.d.ts +37 -0
  146. package/dist/types/helpers/slimmers/element-appender/visibility-modifiers/visibility-modifier.interface.d.ts +56 -0
  147. package/dist/types/helpers/ui/element-appender.d.ts +7 -0
  148. package/dist/vega/index.esm.js +1 -1
  149. package/dist/vega/{p-9c39f90b.entry.js → p-1dfbc542.entry.js} +1 -1
  150. package/dist/vega/{p-e235020b.entry.js → p-22cc174e.entry.js} +1 -1
  151. package/dist/vega/{p-b187b82d.entry.js → p-2df5d59b.entry.js} +1 -1
  152. package/dist/vega/{p-f7e459cd.js → p-312d8205.js} +1 -1
  153. package/dist/vega/{p-a7209700.js → p-3345d903.js} +1 -1
  154. package/dist/vega/{p-02355de8.js → p-3c23ec90.js} +1 -1
  155. package/dist/vega/p-55e0014a.js +3 -0
  156. package/dist/vega/p-5f377954.js +1 -1
  157. package/dist/vega/p-65fee02f.entry.js +1 -0
  158. package/dist/vega/p-6a51d720.js +1 -0
  159. package/dist/vega/{p-fe24b459.js → p-6c7b6d45.js} +1 -1
  160. package/dist/vega/{p-579cdeae.js → p-84b7a775.js} +1 -1
  161. package/dist/vega/{p-df828d90.entry.js → p-96da7d30.entry.js} +1 -1
  162. package/dist/vega/{p-88be9ec5.js → p-9d3f69cb.js} +1 -1
  163. package/dist/vega/{p-8a001caa.js → p-9f11b579.js} +1 -1
  164. package/dist/vega/{p-ba2b9663.entry.js → p-acaff62d.entry.js} +1 -1
  165. package/dist/vega/p-b63319e9.entry.js +1 -0
  166. package/dist/vega/{p-c079c935.entry.js → p-b660f38c.entry.js} +1 -1
  167. package/dist/vega/p-b8ffa42f.entry.js +1 -0
  168. package/dist/vega/{p-4fe40b76.js → p-c4564904.js} +1 -1
  169. package/dist/vega/p-d9158512.js +1 -0
  170. package/dist/vega/p-e62d41ee.js +1 -0
  171. package/dist/vega/{p-9f7154d2.js → p-ec5dee32.js} +1 -1
  172. package/dist/vega/{p-05d04c07.entry.js → p-f29d9707.entry.js} +1 -1
  173. package/dist/vega/vega.esm.js +1 -1
  174. package/package.json +3 -2
  175. package/dist/vega/p-0be4df0a.js +0 -1
  176. package/dist/vega/p-38c9d782.js +0 -1
  177. package/dist/vega/p-513bc0d9.js +0 -1
  178. package/dist/vega/p-8d4b85e7.entry.js +0 -1
  179. package/dist/vega/p-c5d3b008.entry.js +0 -1
  180. package/dist/vega/p-d25ca0c3.entry.js +0 -1
  181. package/dist/vega/p-f4da615a.js +0 -3
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Semantic DTO layer for the A11y Tree.
3
+ *
4
+ * Authoring an A11y Tree with raw `A11yNode` literals asks the developer to
5
+ * think in ARIA terms (`role: 'group'`, `decorative: true`, etc.). The DTO
6
+ * classes here provide a higher-level vocabulary that names the *content's
7
+ * meaning* — "this is a container", "this is a heading", "this is a
8
+ * decorative icon" — and lets the strategy layer translate intent into ARIA.
9
+ *
10
+ * ## Design (Visitor / Strategy + typed semantic DTOs)
11
+ *
12
+ * - DTOs are *type-holders for semantic intent*. They do NOT contain ARIA
13
+ * generation logic themselves.
14
+ * - Each DTO compiles to an `A11yNode` whose `kind` field carries the
15
+ * semantic discriminator. Strategies can then dispatch on `kind`
16
+ * (preferred) or fall back to `role` (for plain `A11yNode` authors).
17
+ * - This keeps strategies pure and independently testable, while letting
18
+ * authors write:
19
+ *
20
+ * ```ts
21
+ * new A11yContainerNode('st-root', { label, description })
22
+ * .childrenWith(
23
+ * new A11yHeadingNode('st-heading', { level: 2, label }),
24
+ * new A11yIconNode('st-icon'),
25
+ * );
26
+ * ```
27
+ *
28
+ * instead of hand-shaping `{ role: 'group', label, description, … }`.
29
+ *
30
+ * ## Migration path
31
+ *
32
+ * Phase 1 (this file): DTOs are an additive layer on top of `A11yNode`.
33
+ * Existing strategies continue to work unchanged because each DTO emits
34
+ * a fully-populated `A11yNode` with `role` set correctly.
35
+ *
36
+ * Phase 2 (follow-up): strategies grow `compileNode(node)` methods that
37
+ * dispatch on `node.kind` for cases where semantic intent is richer than
38
+ * `role` alone can express.
39
+ */
40
+ /**
41
+ * Base class for all semantic DTO nodes. Provides the `childrenWith()`
42
+ * composition helper and the abstract `toA11yNode()` contract.
43
+ */
44
+ export class A11yNodeDto {
45
+ constructor() {
46
+ this.childDtos = [];
47
+ }
48
+ /**
49
+ * Declare the semantic children of this node in reading order.
50
+ *
51
+ * @param {...A11yNodeDto} children - Semantic child DTOs in reading order.
52
+ * @returns {this} `this`, for fluent chaining.
53
+ */
54
+ childrenWith(...children) {
55
+ this.childDtos = children;
56
+ return this;
57
+ }
58
+ /**
59
+ * Compile the declared child DTOs into their `A11yNode` representations.
60
+ *
61
+ * @returns {A11yNode[] | undefined} The compiled children, or `undefined` when none.
62
+ */
63
+ compileChildren() {
64
+ if (this.childDtos.length === 0)
65
+ return undefined;
66
+ return this.childDtos.map((c) => c.toA11yNode());
67
+ }
68
+ }
69
+ /**
70
+ * A generic container that groups related content. Maps to `role="group"`
71
+ * by default; strategies may upgrade to `role="region"` when a description
72
+ * is present and the platform benefits (e.g. Firefox+NVDA landmark
73
+ * navigation — see `firefox-nvda-strategy.ts`).
74
+ */
75
+ export class A11yContainerNode extends A11yNodeDto {
76
+ constructor(id, opts = {}) {
77
+ super();
78
+ this.id = id;
79
+ this.opts = opts;
80
+ this.kind = 'container';
81
+ }
82
+ /**
83
+ * Compile this DTO into its `A11yNode` representation.
84
+ *
85
+ * @returns {A11yNode} The compiled semantic node.
86
+ */
87
+ toA11yNode() {
88
+ return {
89
+ id: this.id,
90
+ kind: this.kind,
91
+ role: 'group',
92
+ label: this.opts.label,
93
+ description: this.opts.description,
94
+ children: this.compileChildren(),
95
+ };
96
+ }
97
+ }
98
+ /**
99
+ * A navigable / discoverable section (landmark). Always renders as
100
+ * `role="region"` so it appears in AT landmark navigation.
101
+ */
102
+ export class A11yLandmarkNode extends A11yNodeDto {
103
+ constructor(id, opts = {}) {
104
+ super();
105
+ this.id = id;
106
+ this.opts = opts;
107
+ this.kind = 'landmark';
108
+ }
109
+ /**
110
+ * Compile this DTO into its `A11yNode` representation.
111
+ *
112
+ * @returns {A11yNode} The compiled semantic node.
113
+ */
114
+ toA11yNode() {
115
+ return {
116
+ id: this.id,
117
+ kind: this.kind,
118
+ role: 'region',
119
+ label: this.opts.label,
120
+ description: this.opts.description,
121
+ children: this.compileChildren(),
122
+ };
123
+ }
124
+ }
125
+ /**
126
+ * A heading at the given level (1–6, defaults to 2).
127
+ *
128
+ * Use this instead of a raw `{ role: 'heading', level: 2 }` literal to
129
+ * benefit from the default-level guard and the `kind` discriminator.
130
+ */
131
+ export class A11yHeadingNode extends A11yNodeDto {
132
+ constructor(id, opts = {}) {
133
+ super();
134
+ this.id = id;
135
+ this.opts = opts;
136
+ this.kind = 'heading';
137
+ }
138
+ /**
139
+ * Compile this DTO into its `A11yNode` representation.
140
+ *
141
+ * @returns {A11yNode} The compiled semantic node.
142
+ */
143
+ toA11yNode() {
144
+ var _a;
145
+ return {
146
+ id: this.id,
147
+ kind: this.kind,
148
+ role: 'heading',
149
+ level: (_a = this.opts.level) !== null && _a !== void 0 ? _a : 2,
150
+ label: this.opts.label,
151
+ children: this.compileChildren(),
152
+ };
153
+ }
154
+ }
155
+ /**
156
+ * A purely decorative icon. `decorative` is always `true` so authors never
157
+ * have to remember the flag — that is the whole point of this DTO class.
158
+ *
159
+ * Produces `aria-hidden="true"` via the baseline strategy; webkit-voiceover
160
+ * additionally sets `role="none"` as a belt-and-suspenders guard.
161
+ */
162
+ export class A11yIconNode extends A11yNodeDto {
163
+ constructor(id) {
164
+ super();
165
+ this.id = id;
166
+ this.kind = 'icon';
167
+ }
168
+ /**
169
+ * Compile this DTO into its `A11yNode` representation.
170
+ *
171
+ * @returns {A11yNode} The compiled semantic node.
172
+ */
173
+ toA11yNode() {
174
+ return {
175
+ id: this.id,
176
+ kind: this.kind,
177
+ role: 'img',
178
+ decorative: true,
179
+ children: this.compileChildren(),
180
+ };
181
+ }
182
+ }
183
+ /**
184
+ * An informative image that requires an accessible label (alt text).
185
+ *
186
+ * Produces `role="img"` + `aria-label` via the baseline strategy.
187
+ * Contrast with `A11yIconNode` which is always decorative.
188
+ */
189
+ export class A11yImageNode extends A11yNodeDto {
190
+ constructor(id, opts) {
191
+ super();
192
+ this.id = id;
193
+ this.opts = opts;
194
+ this.kind = 'image';
195
+ }
196
+ /**
197
+ * Compile this DTO into its `A11yNode` representation.
198
+ *
199
+ * @returns {A11yNode} The compiled semantic node.
200
+ */
201
+ toA11yNode() {
202
+ return {
203
+ id: this.id,
204
+ kind: this.kind,
205
+ role: 'img',
206
+ label: this.opts.label,
207
+ children: this.compileChildren(),
208
+ };
209
+ }
210
+ }
@@ -0,0 +1,189 @@
1
+ import { resolveStrategy } from './strategy-resolver';
2
+ import { tryGetDocument } from '../../utils/try-get-document';
3
+ /**
4
+ * Applies an A11y Tree to a shadow root by:
5
+ *
6
+ * 1. Resolving the `A11yTreeStrategy` that best matches the current
7
+ * browser engine / AT environment.
8
+ * 2. Compiling the semantic tree into a flat list of `AriaPatch`
9
+ * instructions.
10
+ * 3. Clearing any previously managed ARIA attributes (`data-a11y-managed`).
11
+ * 4. Applying each patch to the `data-a11y-id` target node in the shadow.
12
+ * 5. Materialising one visually-hidden description `<span>` per patch that
13
+ * references `aria-describedby` and whose node carries description text.
14
+ * 6. Stamping `data-a11y-strategy-applied` on the host for observability.
15
+ *
16
+ * This is the generic, component-agnostic projection step. Components
17
+ * interact with it indirectly through `A11yTreeSlimmer`.
18
+ *
19
+ * @param {A11yNode} root - The root `A11yNode` of the semantic tree.
20
+ * @param {HTMLElement} host - The component's host element. Must have a `shadowRoot`.
21
+ * If `shadowRoot` is null (e.g. light-DOM component or early call before first
22
+ * render), the function returns immediately without throwing.
23
+ * @example
24
+ * ```ts
25
+ * // Called once per render from A11yTreeSlimmer.projectA11yTree():
26
+ * applyA11yTree(buildSectionTitleA11yTree({ titleText, description }), this.host);
27
+ * ```
28
+ */
29
+ export function applyA11yTree(root, host) {
30
+ const shadow = host.shadowRoot;
31
+ if (!shadow)
32
+ return;
33
+ const strategy = resolveStrategy(host);
34
+ const patches = strategy.compile(root);
35
+ clearPreviousPatches(shadow);
36
+ for (const patch of patches) {
37
+ applyPatch(shadow, patch);
38
+ }
39
+ // Materialise a visually-hidden description node when any patch
40
+ // references aria-describedby. This node is what the AT reads via
41
+ // the describedby relationship.
42
+ maybeRenderDescriptionNode(root, shadow, patches);
43
+ host.setAttribute('data-a11y-strategy-applied', strategy.name);
44
+ }
45
+ /**
46
+ * Remove all ARIA attributes that were set by a previous `applyA11yTree`
47
+ * call. The `data-a11y-managed` attribute on each node acts as a manifest
48
+ * of which attributes were set so we can clean up exactly those — and only
49
+ * those — without disturbing hand-authored ARIA.
50
+ *
51
+ * @param {ShadowRoot} shadow - The shadow root to clean previously managed ARIA from.
52
+ */
53
+ function clearPreviousPatches(shadow) {
54
+ shadow.querySelectorAll('[data-a11y-managed]').forEach((el) => {
55
+ var _a;
56
+ /* istanbul ignore next -- the [data-a11y-managed] selector guarantees the attribute is present, so the `?? ''` fallback is unreachable defensive code */
57
+ const attrs = ((_a = el.getAttribute('data-a11y-managed')) !== null && _a !== void 0 ? _a : '').split(' ').filter(Boolean);
58
+ attrs.forEach((a) => el.removeAttribute(a));
59
+ el.removeAttribute('data-a11y-managed');
60
+ });
61
+ }
62
+ /**
63
+ * Apply a single `AriaPatch` to the matching `data-a11y-id` element.
64
+ * Records every attribute written in `data-a11y-managed` so
65
+ * `clearPreviousPatches` can undo it on the next render.
66
+ *
67
+ * When `patch.value === null` the attribute is removed instead of set.
68
+ *
69
+ * @param {ShadowRoot} shadow - The shadow root containing the target element.
70
+ * @param {AriaPatch} patch - The ARIA patch to apply.
71
+ */
72
+ function applyPatch(shadow, patch) {
73
+ var _a;
74
+ const target = shadow.querySelector(`[data-a11y-id="${patch.targetId}"]`);
75
+ if (!target)
76
+ return;
77
+ if (patch.value === null) {
78
+ target.removeAttribute(patch.attribute);
79
+ }
80
+ else {
81
+ target.setAttribute(patch.attribute, patch.value);
82
+ }
83
+ // Track which attributes we wrote so we can clean them up later.
84
+ const prev = (_a = target.getAttribute('data-a11y-managed')) !== null && _a !== void 0 ? _a : '';
85
+ if (!prev.split(' ').includes(patch.attribute)) {
86
+ target.setAttribute('data-a11y-managed', (prev + ' ' + patch.attribute).trim());
87
+ }
88
+ }
89
+ /**
90
+ * Materialise a visually-hidden `<span>` description node for every strategy
91
+ * patch that references `aria-describedby`. Each `<span>` carries the
92
+ * description text so assistive technology can read it via the describedby
93
+ * relationship.
94
+ *
95
+ * Spans are created once and reused on subsequent renders; their text content
96
+ * is updated in place. Spans whose `aria-describedby` reference is dropped on
97
+ * a later render are pruned by `pruneStaleDescriptionNodes`.
98
+ *
99
+ * Visually-hidden styles follow the `.sr-only` pattern (not `display:none`
100
+ * which would suppress AT reading).
101
+ *
102
+ * @param {A11yNode} root - The root of the semantic tree (source of description text).
103
+ * @param {ShadowRoot} shadow - The shadow root to append/update description nodes in.
104
+ * @param {AriaPatch[]} patches - The compiled patch list to scan for `aria-describedby`.
105
+ */
106
+ function maybeRenderDescriptionNode(root, shadow, patches) {
107
+ // Collect every aria-describedby patch that has a live string target id —
108
+ // one hidden span is required per described node.
109
+ const describedByPatches = patches.filter((p) => p.attribute === 'aria-describedby' && typeof p.value === 'string');
110
+ const keepIds = new Set(describedByPatches.map((p) => p.value));
111
+ // Remove any previously-materialised description spans that are no longer
112
+ // referenced by a live aria-describedby patch — e.g. the `description` prop
113
+ // was cleared, or the description moved to a different node. Without this,
114
+ // orphaned visually-hidden spans linger in the shadow DOM and are still
115
+ // announced by AT during linear (non-describedby) traversal.
116
+ pruneStaleDescriptionNodes(shadow, keepIds);
117
+ for (const patch of describedByPatches) {
118
+ const node = findById(root, patch.targetId);
119
+ /* istanbul ignore next -- describedby patches are only emitted for nodes that carry a description, so this guard is unreachable defensive code */
120
+ if (!(node === null || node === void 0 ? void 0 : node.description))
121
+ continue;
122
+ ensureDescriptionSpan(shadow, patch.value, node.description);
123
+ }
124
+ }
125
+ /**
126
+ * Create (or update in place) a visually-hidden `<span>` carrying description
127
+ * text for a single `aria-describedby` reference.
128
+ *
129
+ * @param {ShadowRoot} shadow - The shadow root to append/update the span in.
130
+ * @param {string} id - The span id, matching the `aria-describedby` value.
131
+ * @param {string} text - The description text to expose to AT.
132
+ */
133
+ function ensureDescriptionSpan(shadow, id, text) {
134
+ let descEl = shadow.getElementById(id);
135
+ if (!descEl) {
136
+ const doc = tryGetDocument();
137
+ /* istanbul ignore next -- document is always present in the browser render path */
138
+ if (!doc)
139
+ return;
140
+ descEl = doc.createElement('span');
141
+ descEl.id = id;
142
+ // Stamp the span so pruneStaleDescriptionNodes can find and clean it up
143
+ // on a later render when it is no longer referenced.
144
+ descEl.setAttribute('data-a11y-desc', '');
145
+ descEl.style.position = 'absolute';
146
+ descEl.style.width = '1px';
147
+ descEl.style.height = '1px';
148
+ descEl.style.overflow = 'hidden';
149
+ // `clip` is kept for legacy engines; `clip-path` + `white-space: nowrap`
150
+ // cover modern engines and prevent a 1px phantom scrollbar.
151
+ descEl.style.clip = 'rect(0 0 0 0)';
152
+ descEl.style.clipPath = 'inset(50%)';
153
+ descEl.style.whiteSpace = 'nowrap';
154
+ shadow.appendChild(descEl);
155
+ }
156
+ descEl.textContent = text;
157
+ }
158
+ /**
159
+ * Remove visually-hidden description `<span>`s (stamped `data-a11y-desc`)
160
+ * that are no longer referenced by a live `aria-describedby` patch.
161
+ *
162
+ * @param {ShadowRoot} shadow - The shadow root to prune stale description nodes from.
163
+ * @param {Set<string>} keepIds - Ids of spans still referenced this render; all
164
+ * other stamped spans are removed.
165
+ */
166
+ function pruneStaleDescriptionNodes(shadow, keepIds) {
167
+ shadow.querySelectorAll('[data-a11y-desc]').forEach((el) => {
168
+ if (!keepIds.has(el.id))
169
+ el.remove();
170
+ });
171
+ }
172
+ /**
173
+ * Depth-first search for a node by `id`.
174
+ *
175
+ * @param {A11yNode} node - Node to search from.
176
+ * @param {string} id - The `id` to find.
177
+ * @returns {A11yNode | undefined} The matching node, or `undefined` when not found.
178
+ */
179
+ function findById(node, id) {
180
+ var _a;
181
+ if (node.id === id)
182
+ return node;
183
+ for (const c of (_a = node.children) !== null && _a !== void 0 ? _a : []) {
184
+ const hit = findById(c, id);
185
+ if (hit)
186
+ return hit;
187
+ }
188
+ return undefined;
189
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * A11y Tree — generic type definitions.
3
+ *
4
+ * The A11y Tree is a browser-agnostic description of the *semantic* a11y
5
+ * structure of a component. Each node captures the intent (role, label,
6
+ * description, level, etc.) and a stable `id` that the strategy layer
7
+ * can use to project ARIA attributes onto the real DOM.
8
+ *
9
+ * ## Architecture overview
10
+ *
11
+ * ```
12
+ * Component (TSX)
13
+ * ↓ builds semantic tree via DTO helpers (a11y-node-dto.ts)
14
+ * A11yNode tree (this file)
15
+ * ↓ compiled by an A11yTreeStrategy
16
+ * AriaPatch[]
17
+ * ↓ applied by a11y-tree-applier.ts
18
+ * Shadow DOM (ARIA attributes on data-a11y-id elements)
19
+ * ```
20
+ *
21
+ * The A11y Tree is NOT rendered itself. It is consumed by an
22
+ * `A11yTreeStrategy` that decides, per browser/AT, which ARIA attributes
23
+ * to attach to which DOM nodes.
24
+ *
25
+ * ## Browser-engine strategy contract
26
+ *
27
+ * Assistive technology (AT) cannot be detected from JavaScript (by design,
28
+ * for user privacy). The strategy resolver therefore branches on *browser
29
+ * engine* as a coarse proxy for the most likely AT pairing:
30
+ *
31
+ * | Engine | Assumed AT | Confidence |
32
+ * |-----------|-------------------|---------------------|
33
+ * | WebKit | VoiceOver (macOS/iOS) | medium on Apple, low elsewhere |
34
+ * | Gecko | NVDA (Windows), Orca (Linux) | medium on Win, low elsewhere |
35
+ * | Chromium | JAWS / NVDA / TalkBack | high on non-Apple, medium on Apple |
36
+ *
37
+ * **Confidence semantics** (see `A11yStrategyConfidence`):
38
+ * - `high` — direct signal (explicit override or confirmed UA).
39
+ * - `medium` — plausible proxy; AT pairing is an assumption that covers the
40
+ * majority of users on that engine+platform combination.
41
+ * - `low` — unknown UA or atypical engine/platform combo; dev-mode warning
42
+ * fires once per (strategy, reason) tuple via `resolveStrategy`.
43
+ *
44
+ * Consumers who know the AT environment (e.g. automated tests, a storybook
45
+ * knob) can pin a strategy explicitly via `data-a11y-strategy` on the host
46
+ * element — this is always treated as `high` confidence.
47
+ */
48
+ export {};
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Baseline strategy: spec-compliant ARIA, works on evergreen Chromium,
3
+ * Firefox, and Safari with their default AT pairings (NVDA, Orca,
4
+ * VoiceOver-macOS). Used as the default when no engine-specific override
5
+ * matches.
6
+ *
7
+ * ## Mapping rules
8
+ *
9
+ * | Node role | ARIA output |
10
+ * |---------------|----------------------------------------------------|
11
+ * | heading | `role="heading"` + `aria-level` |
12
+ * | group/region | `role` + `aria-label` (if present) + `aria-describedby` (if description) |
13
+ * | img (decorative) | `aria-hidden="true"` |
14
+ * | img (labelled) | `role="img"` + `aria-label` |
15
+ * | presentation/none | `role="presentation"` |
16
+ */
17
+ export const baselineStrategy = {
18
+ name: 'baseline',
19
+ /**
20
+ * Compile the semantic tree into spec-compliant ARIA patches.
21
+ *
22
+ * @param {A11yNode} root - Root of the semantic A11y Tree to compile.
23
+ * @returns {AriaPatch[]} Flat list of ARIA attribute patches to apply.
24
+ */
25
+ compile(root) {
26
+ const patches = [];
27
+ walk(root, patches);
28
+ return patches;
29
+ },
30
+ };
31
+ /**
32
+ * Recursively translate a node and its children into ARIA patches.
33
+ *
34
+ * @param {A11yNode} node - Current node being translated.
35
+ * @param {AriaPatch[]} patches - Accumulator the produced patches are pushed onto.
36
+ */
37
+ function walk(node, patches) {
38
+ var _a, _b;
39
+ switch (node.role) {
40
+ case 'heading':
41
+ patches.push({ targetId: node.id, attribute: 'role', value: 'heading' });
42
+ patches.push({
43
+ targetId: node.id,
44
+ attribute: 'aria-level',
45
+ value: String((_a = node.level) !== null && _a !== void 0 ? _a : 2),
46
+ });
47
+ break;
48
+ case 'group':
49
+ case 'region':
50
+ patches.push({ targetId: node.id, attribute: 'role', value: node.role });
51
+ if (node.label) {
52
+ patches.push({ targetId: node.id, attribute: 'aria-label', value: node.label });
53
+ }
54
+ if (node.description) {
55
+ // Baseline AT: describedby works reliably on group/region.
56
+ patches.push({
57
+ targetId: node.id,
58
+ attribute: 'aria-describedby',
59
+ value: `${node.id}__desc`,
60
+ });
61
+ }
62
+ break;
63
+ case 'img':
64
+ if (node.decorative) {
65
+ patches.push({ targetId: node.id, attribute: 'aria-hidden', value: 'true' });
66
+ }
67
+ else if (node.label) {
68
+ patches.push({ targetId: node.id, attribute: 'role', value: 'img' });
69
+ patches.push({ targetId: node.id, attribute: 'aria-label', value: node.label });
70
+ }
71
+ break;
72
+ case 'presentation':
73
+ case 'none':
74
+ patches.push({ targetId: node.id, attribute: 'role', value: 'presentation' });
75
+ break;
76
+ }
77
+ (_b = node.children) === null || _b === void 0 ? void 0 : _b.forEach((c) => walk(c, patches));
78
+ }
@@ -0,0 +1,56 @@
1
+ import { baselineStrategy } from './baseline-strategy';
2
+ /**
3
+ * Firefox + NVDA strategy.
4
+ *
5
+ * Firefox/NVDA generally handles spec-compliant ARIA correctly. The one
6
+ * known quirk for the Vega component family:
7
+ *
8
+ * **NVDA browse-mode may skip `aria-describedby` on `role="group"`.**
9
+ * When a group container carries a description, NVDA in browse (reading)
10
+ * mode sometimes does not announce it. Workaround: promote the container to
11
+ * `role="region"`, which is part of the landmark navigation set and is
12
+ * reliably announced by NVDA when encountered during linear reading.
13
+ *
14
+ * All other node types fall back to baseline behaviour.
15
+ */
16
+ export const firefoxNvdaStrategy = {
17
+ name: 'firefox-nvda',
18
+ /**
19
+ * Compile ARIA patches, applying the NVDA group-description workaround.
20
+ *
21
+ * @param {A11yNode} root - Root of the semantic A11y Tree to compile.
22
+ * @returns {AriaPatch[]} ARIA patches with group promoted to region when needed.
23
+ */
24
+ compile(root) {
25
+ const patches = baselineStrategy.compile(root);
26
+ // Promote all described groups to region (not just the first one).
27
+ for (const group of collectDescribedGroups(root)) {
28
+ for (const p of patches) {
29
+ if (p.targetId === group.id && p.attribute === 'role' && p.value === 'group') {
30
+ p.value = 'region';
31
+ }
32
+ }
33
+ }
34
+ return patches;
35
+ },
36
+ };
37
+ /**
38
+ * Collect every `group` node in the tree that carries a description,
39
+ * in depth-first order. Includes nested described groups.
40
+ *
41
+ * @param {A11yNode} node - Node to search from.
42
+ * @returns {A11yNode[]} All described group nodes, including nested ones.
43
+ */
44
+ function collectDescribedGroups(node) {
45
+ var _a;
46
+ const out = [];
47
+ // Check if this node is a described group
48
+ if (node.role === 'group' && node.description) {
49
+ out.push(node);
50
+ }
51
+ // Always recurse into children to find nested described groups
52
+ for (const c of (_a = node.children) !== null && _a !== void 0 ? _a : []) {
53
+ out.push(...collectDescribedGroups(c));
54
+ }
55
+ return out;
56
+ }