@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
@@ -6,8 +6,9 @@ const index = require('./index-58ea899e.js');
6
6
  const component = require('./component-1e352960.js');
7
7
  const globalSlimmerRegistry = require('./global-slimmer-registry-b3bce7e0.js');
8
8
  const componentUsageRuntimeMetrics = require('./component-usage-runtime-metrics-389d1548.js');
9
+ const tryGetDocument = require('./try-get-document-c0ebd39a.js');
9
10
 
10
- var __decorate$1 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
11
+ var __decorate$2 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
11
12
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
12
13
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
13
14
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
@@ -15,13 +16,13 @@ var __decorate$1 = (undefined && undefined.__decorate) || function (decorators,
15
16
  };
16
17
  class VegaSectionTitleRenderer extends globalSlimmerRegistry.VegaSlimmer {
17
18
  render() {
18
- return (index.h("vega-flex", { "aria-hidden": "true", "align-items": "start", "justify-content": "start", gap: "size-8", class: this.size === 'small' ? 'section-title-small' : undefined },
19
+ return (index.h("vega-flex", { "data-a11y-id": "st-root", "align-items": "start", "justify-content": "start", gap: "size-8", class: this.size === 'small' ? 'section-title-small' : undefined },
19
20
  this.renderPrefixIcon(),
20
21
  this.renderText()));
21
22
  }
22
23
  renderPrefixIcon() {
23
24
  return (this.icon &&
24
- this.iconAlign === 'left' && index.h("div", { class: "section-title-icon-container" }, this.renderIcon()));
25
+ this.iconAlign === 'left' && (index.h("div", { "data-a11y-id": "st-icon", class: "section-title-icon-container" }, this.renderIcon())));
25
26
  }
26
27
  renderText() {
27
28
  return (index.h("vega-flex", { class: "vega-flex-grow", direction: "col", "align-items": "start", "justify-content": "start", gap: "size-4" },
@@ -30,7 +31,7 @@ class VegaSectionTitleRenderer extends globalSlimmerRegistry.VegaSlimmer {
30
31
  }
31
32
  renderTitle() {
32
33
  return (index.h("div", { class: "section-title-text vega-flex-grow" },
33
- index.h("span", null, this.titleText),
34
+ index.h("span", { "data-a11y-id": "st-heading" }, this.titleText),
34
35
  this.renderSuffixIcon()));
35
36
  }
36
37
  renderDescription() {
@@ -38,34 +39,901 @@ class VegaSectionTitleRenderer extends globalSlimmerRegistry.VegaSlimmer {
38
39
  }
39
40
  renderSuffixIcon() {
40
41
  return (this.icon &&
41
- this.iconAlign === 'right' && index.h("div", { class: "right-icon-container" }, this.renderIcon()));
42
+ this.iconAlign === 'right' && (index.h("div", { "data-a11y-id": "st-icon", class: "right-icon-container" }, this.renderIcon())));
42
43
  }
43
44
  renderIcon() {
44
45
  return (index.h("vega-icon", { icon: this.icon, color: this.iconColor, size: this.size === 'small' ? 'size-16' : 'size-20', class: "vega-flex-shrink-0" }));
45
46
  }
46
47
  }
47
- __decorate$1([
48
+ __decorate$2([
48
49
  globalSlimmerRegistry.MapToComponentField()
49
50
  ], VegaSectionTitleRenderer.prototype, "host", void 0);
50
- __decorate$1([
51
+ __decorate$2([
51
52
  globalSlimmerRegistry.MapToComponentField()
52
53
  ], VegaSectionTitleRenderer.prototype, "titleText", void 0);
53
- __decorate$1([
54
+ __decorate$2([
54
55
  globalSlimmerRegistry.MapToComponentField()
55
56
  ], VegaSectionTitleRenderer.prototype, "description", void 0);
56
- __decorate$1([
57
+ __decorate$2([
57
58
  globalSlimmerRegistry.MapToComponentField()
58
59
  ], VegaSectionTitleRenderer.prototype, "icon", void 0);
59
- __decorate$1([
60
+ __decorate$2([
60
61
  globalSlimmerRegistry.MapToComponentField()
61
62
  ], VegaSectionTitleRenderer.prototype, "iconAlign", void 0);
62
- __decorate$1([
63
+ __decorate$2([
63
64
  globalSlimmerRegistry.MapToComponentField()
64
65
  ], VegaSectionTitleRenderer.prototype, "iconColor", void 0);
65
- __decorate$1([
66
+ __decorate$2([
66
67
  globalSlimmerRegistry.MapToComponentField()
67
68
  ], VegaSectionTitleRenderer.prototype, "size", void 0);
68
69
 
70
+ /**
71
+ * Baseline strategy: spec-compliant ARIA, works on evergreen Chromium,
72
+ * Firefox, and Safari with their default AT pairings (NVDA, Orca,
73
+ * VoiceOver-macOS). Used as the default when no engine-specific override
74
+ * matches.
75
+ *
76
+ * ## Mapping rules
77
+ *
78
+ * | Node role | ARIA output |
79
+ * |---------------|----------------------------------------------------|
80
+ * | heading | `role="heading"` + `aria-level` |
81
+ * | group/region | `role` + `aria-label` (if present) + `aria-describedby` (if description) |
82
+ * | img (decorative) | `aria-hidden="true"` |
83
+ * | img (labelled) | `role="img"` + `aria-label` |
84
+ * | presentation/none | `role="presentation"` |
85
+ */
86
+ const baselineStrategy = {
87
+ name: 'baseline',
88
+ /**
89
+ * Compile the semantic tree into spec-compliant ARIA patches.
90
+ *
91
+ * @param {A11yNode} root - Root of the semantic A11y Tree to compile.
92
+ * @returns {AriaPatch[]} Flat list of ARIA attribute patches to apply.
93
+ */
94
+ compile(root) {
95
+ const patches = [];
96
+ walk(root, patches);
97
+ return patches;
98
+ },
99
+ };
100
+ /**
101
+ * Recursively translate a node and its children into ARIA patches.
102
+ *
103
+ * @param {A11yNode} node - Current node being translated.
104
+ * @param {AriaPatch[]} patches - Accumulator the produced patches are pushed onto.
105
+ */
106
+ function walk(node, patches) {
107
+ var _a, _b;
108
+ switch (node.role) {
109
+ case 'heading':
110
+ patches.push({ targetId: node.id, attribute: 'role', value: 'heading' });
111
+ patches.push({
112
+ targetId: node.id,
113
+ attribute: 'aria-level',
114
+ value: String((_a = node.level) !== null && _a !== void 0 ? _a : 2),
115
+ });
116
+ break;
117
+ case 'group':
118
+ case 'region':
119
+ patches.push({ targetId: node.id, attribute: 'role', value: node.role });
120
+ if (node.label) {
121
+ patches.push({ targetId: node.id, attribute: 'aria-label', value: node.label });
122
+ }
123
+ if (node.description) {
124
+ // Baseline AT: describedby works reliably on group/region.
125
+ patches.push({
126
+ targetId: node.id,
127
+ attribute: 'aria-describedby',
128
+ value: `${node.id}__desc`,
129
+ });
130
+ }
131
+ break;
132
+ case 'img':
133
+ if (node.decorative) {
134
+ patches.push({ targetId: node.id, attribute: 'aria-hidden', value: 'true' });
135
+ }
136
+ else if (node.label) {
137
+ patches.push({ targetId: node.id, attribute: 'role', value: 'img' });
138
+ patches.push({ targetId: node.id, attribute: 'aria-label', value: node.label });
139
+ }
140
+ break;
141
+ case 'presentation':
142
+ case 'none':
143
+ patches.push({ targetId: node.id, attribute: 'role', value: 'presentation' });
144
+ break;
145
+ }
146
+ (_b = node.children) === null || _b === void 0 ? void 0 : _b.forEach((c) => walk(c, patches));
147
+ }
148
+
149
+ /**
150
+ * Firefox + NVDA strategy.
151
+ *
152
+ * Firefox/NVDA generally handles spec-compliant ARIA correctly. The one
153
+ * known quirk for the Vega component family:
154
+ *
155
+ * **NVDA browse-mode may skip `aria-describedby` on `role="group"`.**
156
+ * When a group container carries a description, NVDA in browse (reading)
157
+ * mode sometimes does not announce it. Workaround: promote the container to
158
+ * `role="region"`, which is part of the landmark navigation set and is
159
+ * reliably announced by NVDA when encountered during linear reading.
160
+ *
161
+ * All other node types fall back to baseline behaviour.
162
+ */
163
+ const firefoxNvdaStrategy = {
164
+ name: 'firefox-nvda',
165
+ /**
166
+ * Compile ARIA patches, applying the NVDA group-description workaround.
167
+ *
168
+ * @param {A11yNode} root - Root of the semantic A11y Tree to compile.
169
+ * @returns {AriaPatch[]} ARIA patches with group promoted to region when needed.
170
+ */
171
+ compile(root) {
172
+ const patches = baselineStrategy.compile(root);
173
+ // Promote all described groups to region (not just the first one).
174
+ for (const group of collectDescribedGroups(root)) {
175
+ for (const p of patches) {
176
+ if (p.targetId === group.id && p.attribute === 'role' && p.value === 'group') {
177
+ p.value = 'region';
178
+ }
179
+ }
180
+ }
181
+ return patches;
182
+ },
183
+ };
184
+ /**
185
+ * Collect every `group` node in the tree that carries a description,
186
+ * in depth-first order. Includes nested described groups.
187
+ *
188
+ * @param {A11yNode} node - Node to search from.
189
+ * @returns {A11yNode[]} All described group nodes, including nested ones.
190
+ */
191
+ function collectDescribedGroups(node) {
192
+ var _a;
193
+ const out = [];
194
+ // Check if this node is a described group
195
+ if (node.role === 'group' && node.description) {
196
+ out.push(node);
197
+ }
198
+ // Always recurse into children to find nested described groups
199
+ for (const c of (_a = node.children) !== null && _a !== void 0 ? _a : []) {
200
+ out.push(...collectDescribedGroups(c));
201
+ }
202
+ return out;
203
+ }
204
+
205
+ /**
206
+ * WebKit + VoiceOver strategy.
207
+ *
208
+ * Applies on top of the baseline to work around two known VoiceOver quirks:
209
+ *
210
+ * **Quirk #1 — `aria-describedby` on non-focusable containers is skipped.**
211
+ * VoiceOver on Safari often does not read `aria-describedby` on non-focusable
212
+ * `role="group"` (A11yContainerNode) or `role="region"` (A11yLandmarkNode)
213
+ * containers. Workaround: fold the description text directly into the
214
+ * heading's `aria-label` (joined with `. `) so it is read together with the
215
+ * title, and remove the orphaned `aria-describedby` patch.
216
+ *
217
+ * **Quirk #2 — Decorative `<vega-icon>` announced twice.**
218
+ * Safari occasionally announces a decorative icon twice when only
219
+ * `aria-hidden` is set on the host. We additionally set `role="none"` as a
220
+ * belt-and-suspenders guard that suppresses the extra announcement.
221
+ *
222
+ * These adjustments are applied as a *diff* on top of the baseline patch
223
+ * list — the A11y Tree itself is unchanged. Other node types fall back to
224
+ * baseline behaviour.
225
+ */
226
+ const webkitVoiceOverStrategy = {
227
+ name: 'webkit-voiceover',
228
+ /**
229
+ * Compile ARIA patches, applying the two VoiceOver workarounds.
230
+ *
231
+ * @param {A11yNode} root - Root of the semantic A11y Tree to compile.
232
+ * @returns {AriaPatch[]} ARIA patches adjusted for WebKit + VoiceOver.
233
+ */
234
+ compile(root) {
235
+ var _a;
236
+ const patches = baselineStrategy.compile(root);
237
+ // Quirk #1: fold each described container's description into its heading's
238
+ // aria-label. The non-focusable-container quirk affects both role="group"
239
+ // (A11yContainerNode) and role="region" (A11yLandmarkNode). Generalized to
240
+ // iterate every described container so components with multiple described
241
+ // groups/regions all get folded correctly instead of only the first pair.
242
+ for (const container of collectDescribedContainers(root)) {
243
+ // Use the first heading owned by this container (not crossing nested
244
+ // described-container boundaries), or fall back to the container itself.
245
+ const heading = (_a = findOwnedHeading(container)) !== null && _a !== void 0 ? _a : container;
246
+ const combined = [heading.label, container.description].filter(Boolean).join('. ');
247
+ // Emit an explicit removal patch (value: null) for the container's
248
+ // aria-describedby. VoiceOver double-announces the description when it
249
+ // is both folded into the heading label AND referenced via
250
+ // aria-describedby, so we untrack the attribute declaratively (rather
251
+ // than silently dropping the patch) to keep re-render cleanup correct.
252
+ //
253
+ // When folding onto the container itself (no owned heading found), also
254
+ // update the existing aria-label patch in-place so we do not produce a
255
+ // duplicate patch that would leave the old value visible to consumers
256
+ // using Array.find().
257
+ const foldingOntoContainer = heading.id === container.id;
258
+ for (const p of patches) {
259
+ if (p.targetId === container.id && p.attribute === 'aria-describedby') {
260
+ p.value = null;
261
+ }
262
+ if (foldingOntoContainer && p.targetId === container.id && p.attribute === 'aria-label') {
263
+ p.value = combined;
264
+ }
265
+ }
266
+ if (!foldingOntoContainer) {
267
+ patches.push({ targetId: heading.id, attribute: 'aria-label', value: combined });
268
+ }
269
+ }
270
+ // Quirk #2: harden decorative icons with role="none".
271
+ walkIcons(root, (n) => {
272
+ if (n.decorative) {
273
+ patches.push({ targetId: n.id, attribute: 'role', value: 'none' });
274
+ }
275
+ });
276
+ return patches;
277
+ },
278
+ };
279
+ /**
280
+ * Find the first heading node owned directly by a described container,
281
+ * stopping at nested described-container boundaries.
282
+ *
283
+ * A heading "owned" by a container is one that lives in that container's
284
+ * direct subtree but NOT inside a nested described group/region. Those inner
285
+ * headings belong to the inner container's own fold pass, so crossing their
286
+ * boundary would cause the outer container's description to overwrite the
287
+ * inner heading's aria-label and then be lost when the inner pass runs.
288
+ *
289
+ * If no owned heading is found, the caller falls back to the container itself
290
+ * (the `?? container` in compile()), folding the description onto the
291
+ * container's own aria-label.
292
+ *
293
+ * @param {A11yNode} node - The container to search within.
294
+ * @returns {A11yNode | undefined} First heading owned by this container, if any.
295
+ */
296
+ function findOwnedHeading(node) {
297
+ var _a;
298
+ for (const c of (_a = node.children) !== null && _a !== void 0 ? _a : []) {
299
+ // Stop at nested described-container boundaries — their headings belong
300
+ // to those containers' own fold passes, not this one.
301
+ if ((c.role === 'group' || c.role === 'region') && c.description) {
302
+ continue;
303
+ }
304
+ if (c.role === 'heading')
305
+ return c;
306
+ const hit = findOwnedHeading(c);
307
+ if (hit)
308
+ return hit;
309
+ }
310
+ return undefined;
311
+ }
312
+ /**
313
+ * Visit every image node in the tree, invoking the callback on each.
314
+ *
315
+ * @param {A11yNode} node - Node to walk from.
316
+ * @param {(n: A11yNode) => void} fn - Callback invoked for each image node.
317
+ */
318
+ function walkIcons(node, fn) {
319
+ var _a;
320
+ if (node.role === 'img')
321
+ fn(node);
322
+ (_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach((c) => walkIcons(c, fn));
323
+ }
324
+ /**
325
+ * Collect every `group` or `region` node in the tree that carries a
326
+ * description, in depth-first order. Includes nested described containers.
327
+ *
328
+ * @param {A11yNode} node - Node to search from.
329
+ * @returns {A11yNode[]} All described container nodes, including nested ones.
330
+ */
331
+ function collectDescribedContainers(node) {
332
+ var _a;
333
+ const out = [];
334
+ // Check if this node is a described container
335
+ if ((node.role === 'group' || node.role === 'region') && node.description) {
336
+ out.push(node);
337
+ }
338
+ // Always recurse into children to find nested described containers
339
+ for (const c of (_a = node.children) !== null && _a !== void 0 ? _a : []) {
340
+ out.push(...collectDescribedContainers(c));
341
+ }
342
+ return out;
343
+ }
344
+
345
+ /**
346
+ * All registered strategies. The resolver picks from this list; callers that
347
+ * need exhaustive enumeration (e.g. tests, Storybook knobs) can import this
348
+ * constant directly.
349
+ */
350
+ const ALL_A11Y_STRATEGIES = [
351
+ baselineStrategy,
352
+ webkitVoiceOverStrategy,
353
+ firefoxNvdaStrategy,
354
+ ];
355
+ /**
356
+ * Picks an `A11yTreeStrategy` from the runtime environment and returns the
357
+ * full `A11yStrategyResolution` including confidence and a reason string.
358
+ *
359
+ * ## Browser-engine detection
360
+ *
361
+ * AT cannot be detected from JS (user privacy). We branch on *browser engine*
362
+ * as a coarse proxy for the most likely AT pairing on each platform:
363
+ *
364
+ * | Engine | Assumed AT | Confidence |
365
+ * |-----------|------------------------------|-------------------------|
366
+ * | WebKit | VoiceOver (macOS/iOS) | medium on Apple, low elsewhere |
367
+ * | Gecko | NVDA (Win), Orca (Linux) | medium on Win32, low elsewhere |
368
+ * | Chromium | JAWS / NVDA / TalkBack | high on non-Apple, medium on Apple |
369
+ *
370
+ * An explicit `data-a11y-strategy` attribute on the host element is always
371
+ * treated as `high` confidence (known override). If the override value does
372
+ * not match any registered strategy name, the resolver falls back to baseline
373
+ * with `low` confidence and logs an actionable warning.
374
+ *
375
+ * @param {HTMLElement} [host] - The component host element. When provided, its
376
+ * `data-a11y-strategy` attribute is checked first.
377
+ * @returns {A11yStrategyResolution} The resolved strategy with confidence and reason.
378
+ */
379
+ function resolveStrategyDetailed(host) {
380
+ var _a, _b;
381
+ // Explicit override takes precedence over UA detection.
382
+ const override = (_a = host === null || host === void 0 ? void 0 : host.getAttribute('data-a11y-strategy')) !== null && _a !== void 0 ? _a : null;
383
+ if (override) {
384
+ const found = ALL_A11Y_STRATEGIES.find((s) => s.name === override);
385
+ if (found) {
386
+ return {
387
+ strategy: found,
388
+ confidence: 'high',
389
+ reason: `explicit override via data-a11y-strategy="${override}"`,
390
+ };
391
+ }
392
+ // Unknown override name — warn and fall back to baseline.
393
+ return {
394
+ strategy: baselineStrategy,
395
+ confidence: 'low',
396
+ reason: `unknown data-a11y-strategy="${override}"; known strategies: ${ALL_A11Y_STRATEGIES.map((s) => s.name).join(', ')}. Falling back to baseline.`,
397
+ };
398
+ }
399
+ // Read the runtime navigator explicitly from `globalThis` (not the bare
400
+ // `navigator` identifier, which build tooling may substitute). Delegate the
401
+ // pure UA→strategy mapping to `resolveStrategyFromEnv` so it can be unit
402
+ // tested deterministically without mocking globals.
403
+ const nav = globalThis.navigator;
404
+ return resolveStrategyFromEnv(nav === null || nav === void 0 ? void 0 : nav.userAgent, (_b = nav === null || nav === void 0 ? void 0 : nav.platform) !== null && _b !== void 0 ? _b : '');
405
+ }
406
+ /**
407
+ * Pure UA→strategy mapping. Separated from `resolveStrategyDetailed` so the
408
+ * browser-engine detection table can be unit tested deterministically by
409
+ * passing explicit `userAgent` / `platform` values instead of mocking the
410
+ * global `navigator` (which build/test tooling may sandbox).
411
+ *
412
+ * @param {string | undefined} userAgent - The `navigator.userAgent` string, or
413
+ * `undefined` for an SSR / non-browser environment.
414
+ * @param {string} platform - The `navigator.platform` string (empty string when
415
+ * unavailable).
416
+ * @returns {A11yStrategyResolution} The resolved strategy with confidence and reason.
417
+ */
418
+ function resolveStrategyFromEnv(userAgent, platform) {
419
+ // SSR / non-browser environment: no UA available.
420
+ if (userAgent === undefined) {
421
+ return {
422
+ strategy: baselineStrategy,
423
+ confidence: 'medium',
424
+ reason: 'no navigator (SSR or non-browser environment); baseline assumed',
425
+ };
426
+ }
427
+ const ua = userAgent;
428
+ // Order matters: Safari UA contains "Safari" but Chrome UA also does.
429
+ if (/\bFirefox\//.test(ua)) {
430
+ // Firefox + NVDA is the canonical pairing on Windows; on other
431
+ // platforms (macOS VoiceOver, Linux Orca, Windows JAWS) this is a
432
+ // probabilistic guess.
433
+ const isWindows = /Win/i.test(platform);
434
+ return {
435
+ strategy: firefoxNvdaStrategy,
436
+ confidence: isWindows ? 'medium' : 'low',
437
+ reason: isWindows
438
+ ? 'Firefox on Windows — assumed NVDA (most common pairing on Win32)'
439
+ : 'Firefox on non-Windows platform — AT pairing is a guess (may be Orca, VoiceOver, or JAWS)',
440
+ };
441
+ }
442
+ if (/^((?!chrome|android).)*safari/i.test(ua)) {
443
+ const isApple = /Mac|iPhone|iPad|iPod/i.test(platform);
444
+ return {
445
+ strategy: webkitVoiceOverStrategy,
446
+ confidence: isApple ? 'medium' : 'low',
447
+ reason: isApple
448
+ ? 'WebKit on Apple platform — assumed VoiceOver'
449
+ : 'WebKit on non-Apple platform — AT pairing is a guess',
450
+ };
451
+ }
452
+ // Chromium (Edge/Chrome). On macOS, Chromium routes through VoiceOver's
453
+ // accessibility tree; baseline covers most users but VoiceOver quirks may
454
+ // surface. Surfaced as medium confidence so the override path stays
455
+ // discoverable.
456
+ const onApple = /Mac|iPhone|iPad|iPod/i.test(platform);
457
+ return {
458
+ strategy: baselineStrategy,
459
+ confidence: onApple ? 'medium' : 'high',
460
+ reason: onApple
461
+ ? 'Chromium on Apple platform — VoiceOver may diverge from Chromium baseline'
462
+ : 'Chromium on non-Apple platform — baseline is the expected AT mapping',
463
+ };
464
+ }
465
+ /**
466
+ * Convenience wrapper for callers that only need the resolved strategy.
467
+ * Equivalent to `resolveStrategyDetailed(host).strategy` but additionally
468
+ * emits a **dev-mode console warning** for `low`-confidence resolutions,
469
+ * pointing engineers at the `data-a11y-strategy` override mechanism.
470
+ *
471
+ * The warning is rate-limited per `(strategyName, reason)` tuple to avoid
472
+ * log spam on every render cycle.
473
+ *
474
+ * @param {HTMLElement} [host] - The component host element (optional). Used for
475
+ * the `data-a11y-strategy` override check.
476
+ * @returns {A11yTreeStrategy} The resolved strategy.
477
+ */
478
+ function resolveStrategy(host) {
479
+ const resolution = resolveStrategyDetailed(host);
480
+ if (resolution.confidence === 'low') {
481
+ warnOnce(resolution.strategy.name, resolution.reason);
482
+ }
483
+ return resolution.strategy;
484
+ }
485
+ const warnedKeys = new Set();
486
+ /**
487
+ * Emit a console.warn once per (strategy, reason) tuple. Suppressed in
488
+ * production builds and when `console` is unavailable (SSR).
489
+ *
490
+ * @param {string} strategyName - Name of the resolved strategy.
491
+ * @param {string} reason - Human-readable reason for the resolution.
492
+ * @internal
493
+ */
494
+ function warnOnce(strategyName, reason) {
495
+ var _a, _b;
496
+ if (typeof console === 'undefined')
497
+ return;
498
+ // Only warn in dev mode. Production builds set NODE_ENV=production;
499
+ // the guard below also handles minified bundles where `process` may
500
+ // be undefined.
501
+ const env = (_b = (_a = globalThis.process) === null || _a === void 0 ? void 0 : _a.env) === null || _b === void 0 ? void 0 : _b.NODE_ENV;
502
+ if (env === 'production')
503
+ return;
504
+ const key = `${strategyName}::${reason}`;
505
+ if (warnedKeys.has(key))
506
+ return;
507
+ warnedKeys.add(key);
508
+ console.warn(`[vega a11y-tree] Low-confidence strategy resolution: using "${strategyName}". ` +
509
+ `Reason: ${reason}. ` +
510
+ `Pin via data-a11y-strategy="<strategy-name>" to silence this warning ` +
511
+ `when you know the correct AT pairing. ` +
512
+ `Known strategies: ${ALL_A11Y_STRATEGIES.map((s) => s.name).join(', ')}.`);
513
+ }
514
+
515
+ /**
516
+ * Applies an A11y Tree to a shadow root by:
517
+ *
518
+ * 1. Resolving the `A11yTreeStrategy` that best matches the current
519
+ * browser engine / AT environment.
520
+ * 2. Compiling the semantic tree into a flat list of `AriaPatch`
521
+ * instructions.
522
+ * 3. Clearing any previously managed ARIA attributes (`data-a11y-managed`).
523
+ * 4. Applying each patch to the `data-a11y-id` target node in the shadow.
524
+ * 5. Materialising one visually-hidden description `<span>` per patch that
525
+ * references `aria-describedby` and whose node carries description text.
526
+ * 6. Stamping `data-a11y-strategy-applied` on the host for observability.
527
+ *
528
+ * This is the generic, component-agnostic projection step. Components
529
+ * interact with it indirectly through `A11yTreeSlimmer`.
530
+ *
531
+ * @param {A11yNode} root - The root `A11yNode` of the semantic tree.
532
+ * @param {HTMLElement} host - The component's host element. Must have a `shadowRoot`.
533
+ * If `shadowRoot` is null (e.g. light-DOM component or early call before first
534
+ * render), the function returns immediately without throwing.
535
+ * @example
536
+ * ```ts
537
+ * // Called once per render from A11yTreeSlimmer.projectA11yTree():
538
+ * applyA11yTree(buildSectionTitleA11yTree({ titleText, description }), this.host);
539
+ * ```
540
+ */
541
+ function applyA11yTree(root, host) {
542
+ const shadow = host.shadowRoot;
543
+ if (!shadow)
544
+ return;
545
+ const strategy = resolveStrategy(host);
546
+ const patches = strategy.compile(root);
547
+ clearPreviousPatches(shadow);
548
+ for (const patch of patches) {
549
+ applyPatch(shadow, patch);
550
+ }
551
+ // Materialise a visually-hidden description node when any patch
552
+ // references aria-describedby. This node is what the AT reads via
553
+ // the describedby relationship.
554
+ maybeRenderDescriptionNode(root, shadow, patches);
555
+ host.setAttribute('data-a11y-strategy-applied', strategy.name);
556
+ }
557
+ /**
558
+ * Remove all ARIA attributes that were set by a previous `applyA11yTree`
559
+ * call. The `data-a11y-managed` attribute on each node acts as a manifest
560
+ * of which attributes were set so we can clean up exactly those — and only
561
+ * those — without disturbing hand-authored ARIA.
562
+ *
563
+ * @param {ShadowRoot} shadow - The shadow root to clean previously managed ARIA from.
564
+ */
565
+ function clearPreviousPatches(shadow) {
566
+ shadow.querySelectorAll('[data-a11y-managed]').forEach((el) => {
567
+ var _a;
568
+ /* istanbul ignore next -- the [data-a11y-managed] selector guarantees the attribute is present, so the `?? ''` fallback is unreachable defensive code */
569
+ const attrs = ((_a = el.getAttribute('data-a11y-managed')) !== null && _a !== void 0 ? _a : '').split(' ').filter(Boolean);
570
+ attrs.forEach((a) => el.removeAttribute(a));
571
+ el.removeAttribute('data-a11y-managed');
572
+ });
573
+ }
574
+ /**
575
+ * Apply a single `AriaPatch` to the matching `data-a11y-id` element.
576
+ * Records every attribute written in `data-a11y-managed` so
577
+ * `clearPreviousPatches` can undo it on the next render.
578
+ *
579
+ * When `patch.value === null` the attribute is removed instead of set.
580
+ *
581
+ * @param {ShadowRoot} shadow - The shadow root containing the target element.
582
+ * @param {AriaPatch} patch - The ARIA patch to apply.
583
+ */
584
+ function applyPatch(shadow, patch) {
585
+ var _a;
586
+ const target = shadow.querySelector(`[data-a11y-id="${patch.targetId}"]`);
587
+ if (!target)
588
+ return;
589
+ if (patch.value === null) {
590
+ target.removeAttribute(patch.attribute);
591
+ }
592
+ else {
593
+ target.setAttribute(patch.attribute, patch.value);
594
+ }
595
+ // Track which attributes we wrote so we can clean them up later.
596
+ const prev = (_a = target.getAttribute('data-a11y-managed')) !== null && _a !== void 0 ? _a : '';
597
+ if (!prev.split(' ').includes(patch.attribute)) {
598
+ target.setAttribute('data-a11y-managed', (prev + ' ' + patch.attribute).trim());
599
+ }
600
+ }
601
+ /**
602
+ * Materialise a visually-hidden `<span>` description node for every strategy
603
+ * patch that references `aria-describedby`. Each `<span>` carries the
604
+ * description text so assistive technology can read it via the describedby
605
+ * relationship.
606
+ *
607
+ * Spans are created once and reused on subsequent renders; their text content
608
+ * is updated in place. Spans whose `aria-describedby` reference is dropped on
609
+ * a later render are pruned by `pruneStaleDescriptionNodes`.
610
+ *
611
+ * Visually-hidden styles follow the `.sr-only` pattern (not `display:none`
612
+ * which would suppress AT reading).
613
+ *
614
+ * @param {A11yNode} root - The root of the semantic tree (source of description text).
615
+ * @param {ShadowRoot} shadow - The shadow root to append/update description nodes in.
616
+ * @param {AriaPatch[]} patches - The compiled patch list to scan for `aria-describedby`.
617
+ */
618
+ function maybeRenderDescriptionNode(root, shadow, patches) {
619
+ // Collect every aria-describedby patch that has a live string target id —
620
+ // one hidden span is required per described node.
621
+ const describedByPatches = patches.filter((p) => p.attribute === 'aria-describedby' && typeof p.value === 'string');
622
+ const keepIds = new Set(describedByPatches.map((p) => p.value));
623
+ // Remove any previously-materialised description spans that are no longer
624
+ // referenced by a live aria-describedby patch — e.g. the `description` prop
625
+ // was cleared, or the description moved to a different node. Without this,
626
+ // orphaned visually-hidden spans linger in the shadow DOM and are still
627
+ // announced by AT during linear (non-describedby) traversal.
628
+ pruneStaleDescriptionNodes(shadow, keepIds);
629
+ for (const patch of describedByPatches) {
630
+ const node = findById(root, patch.targetId);
631
+ /* istanbul ignore next -- describedby patches are only emitted for nodes that carry a description, so this guard is unreachable defensive code */
632
+ if (!(node === null || node === void 0 ? void 0 : node.description))
633
+ continue;
634
+ ensureDescriptionSpan(shadow, patch.value, node.description);
635
+ }
636
+ }
637
+ /**
638
+ * Create (or update in place) a visually-hidden `<span>` carrying description
639
+ * text for a single `aria-describedby` reference.
640
+ *
641
+ * @param {ShadowRoot} shadow - The shadow root to append/update the span in.
642
+ * @param {string} id - The span id, matching the `aria-describedby` value.
643
+ * @param {string} text - The description text to expose to AT.
644
+ */
645
+ function ensureDescriptionSpan(shadow, id, text) {
646
+ let descEl = shadow.getElementById(id);
647
+ if (!descEl) {
648
+ const doc = tryGetDocument.tryGetDocument();
649
+ /* istanbul ignore next -- document is always present in the browser render path */
650
+ if (!doc)
651
+ return;
652
+ descEl = doc.createElement('span');
653
+ descEl.id = id;
654
+ // Stamp the span so pruneStaleDescriptionNodes can find and clean it up
655
+ // on a later render when it is no longer referenced.
656
+ descEl.setAttribute('data-a11y-desc', '');
657
+ descEl.style.position = 'absolute';
658
+ descEl.style.width = '1px';
659
+ descEl.style.height = '1px';
660
+ descEl.style.overflow = 'hidden';
661
+ // `clip` is kept for legacy engines; `clip-path` + `white-space: nowrap`
662
+ // cover modern engines and prevent a 1px phantom scrollbar.
663
+ descEl.style.clip = 'rect(0 0 0 0)';
664
+ descEl.style.clipPath = 'inset(50%)';
665
+ descEl.style.whiteSpace = 'nowrap';
666
+ shadow.appendChild(descEl);
667
+ }
668
+ descEl.textContent = text;
669
+ }
670
+ /**
671
+ * Remove visually-hidden description `<span>`s (stamped `data-a11y-desc`)
672
+ * that are no longer referenced by a live `aria-describedby` patch.
673
+ *
674
+ * @param {ShadowRoot} shadow - The shadow root to prune stale description nodes from.
675
+ * @param {Set<string>} keepIds - Ids of spans still referenced this render; all
676
+ * other stamped spans are removed.
677
+ */
678
+ function pruneStaleDescriptionNodes(shadow, keepIds) {
679
+ shadow.querySelectorAll('[data-a11y-desc]').forEach((el) => {
680
+ if (!keepIds.has(el.id))
681
+ el.remove();
682
+ });
683
+ }
684
+ /**
685
+ * Depth-first search for a node by `id`.
686
+ *
687
+ * @param {A11yNode} node - Node to search from.
688
+ * @param {string} id - The `id` to find.
689
+ * @returns {A11yNode | undefined} The matching node, or `undefined` when not found.
690
+ */
691
+ function findById(node, id) {
692
+ var _a;
693
+ if (node.id === id)
694
+ return node;
695
+ for (const c of (_a = node.children) !== null && _a !== void 0 ? _a : []) {
696
+ const hit = findById(c, id);
697
+ if (hit)
698
+ return hit;
699
+ }
700
+ return undefined;
701
+ }
702
+
703
+ var __decorate$1 = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
704
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
705
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
706
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
707
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
708
+ };
709
+ /**
710
+ * Generic A11y Tree slimmer.
711
+ *
712
+ * Hooks `componentDidRender` and projects the component's semantic A11y
713
+ * Tree onto its shadow DOM using the strategy resolved for the current
714
+ * browser engine.
715
+ *
716
+ * ## Opt-in steps for a component
717
+ *
718
+ * 1. Tag render targets with `data-a11y-id="<stable-id>"` in the renderer.
719
+ * 2. Author a `build<Component>A11yTree(host)` function (see
720
+ * `a11y-node-dto.ts` for the DTO helpers that make this ergonomic).
721
+ * 3. Inject this slimmer with `@InjectVegaSlimmer()`:
722
+ *
723
+ * ```ts
724
+ * @InjectVegaSlimmer()
725
+ * protected a11yTreeSlimmer = new A11yTreeSlimmer<HTMLVegaFooElement>(
726
+ * host => buildFooA11yTree({ title: host.title, description: host.description }),
727
+ * );
728
+ * ```
729
+ *
730
+ * The slimmer handles strategy selection, patch application, and cleanup
731
+ * on every subsequent render.
732
+ *
733
+ * @template T - The concrete `HTMLElement` subtype for the component host.
734
+ */
735
+ class A11yTreeSlimmer extends globalSlimmerRegistry.VegaSlimmer {
736
+ constructor(buildA11yTree) {
737
+ super();
738
+ this.buildA11yTree = buildA11yTree;
739
+ }
740
+ /**
741
+ * Called by Stencil after each render. Projects the semantic A11y Tree
742
+ * onto the shadow DOM via the resolved browser-engine strategy.
743
+ */
744
+ projectA11yTree() {
745
+ const tree = this.buildA11yTree(this.host);
746
+ applyA11yTree(tree, this.host);
747
+ }
748
+ }
749
+ __decorate$1([
750
+ globalSlimmerRegistry.MapToComponentField()
751
+ ], A11yTreeSlimmer.prototype, "host", void 0);
752
+ __decorate$1([
753
+ globalSlimmerRegistry.MapToComponentMethod('componentDidRender')
754
+ ], A11yTreeSlimmer.prototype, "projectA11yTree", null);
755
+
756
+ /**
757
+ * Semantic DTO layer for the A11y Tree.
758
+ *
759
+ * Authoring an A11y Tree with raw `A11yNode` literals asks the developer to
760
+ * think in ARIA terms (`role: 'group'`, `decorative: true`, etc.). The DTO
761
+ * classes here provide a higher-level vocabulary that names the *content's
762
+ * meaning* — "this is a container", "this is a heading", "this is a
763
+ * decorative icon" — and lets the strategy layer translate intent into ARIA.
764
+ *
765
+ * ## Design (Visitor / Strategy + typed semantic DTOs)
766
+ *
767
+ * - DTOs are *type-holders for semantic intent*. They do NOT contain ARIA
768
+ * generation logic themselves.
769
+ * - Each DTO compiles to an `A11yNode` whose `kind` field carries the
770
+ * semantic discriminator. Strategies can then dispatch on `kind`
771
+ * (preferred) or fall back to `role` (for plain `A11yNode` authors).
772
+ * - This keeps strategies pure and independently testable, while letting
773
+ * authors write:
774
+ *
775
+ * ```ts
776
+ * new A11yContainerNode('st-root', { label, description })
777
+ * .childrenWith(
778
+ * new A11yHeadingNode('st-heading', { level: 2, label }),
779
+ * new A11yIconNode('st-icon'),
780
+ * );
781
+ * ```
782
+ *
783
+ * instead of hand-shaping `{ role: 'group', label, description, … }`.
784
+ *
785
+ * ## Migration path
786
+ *
787
+ * Phase 1 (this file): DTOs are an additive layer on top of `A11yNode`.
788
+ * Existing strategies continue to work unchanged because each DTO emits
789
+ * a fully-populated `A11yNode` with `role` set correctly.
790
+ *
791
+ * Phase 2 (follow-up): strategies grow `compileNode(node)` methods that
792
+ * dispatch on `node.kind` for cases where semantic intent is richer than
793
+ * `role` alone can express.
794
+ */
795
+ /**
796
+ * Base class for all semantic DTO nodes. Provides the `childrenWith()`
797
+ * composition helper and the abstract `toA11yNode()` contract.
798
+ */
799
+ class A11yNodeDto {
800
+ constructor() {
801
+ this.childDtos = [];
802
+ }
803
+ /**
804
+ * Declare the semantic children of this node in reading order.
805
+ *
806
+ * @param {...A11yNodeDto} children - Semantic child DTOs in reading order.
807
+ * @returns {this} `this`, for fluent chaining.
808
+ */
809
+ childrenWith(...children) {
810
+ this.childDtos = children;
811
+ return this;
812
+ }
813
+ /**
814
+ * Compile the declared child DTOs into their `A11yNode` representations.
815
+ *
816
+ * @returns {A11yNode[] | undefined} The compiled children, or `undefined` when none.
817
+ */
818
+ compileChildren() {
819
+ if (this.childDtos.length === 0)
820
+ return undefined;
821
+ return this.childDtos.map((c) => c.toA11yNode());
822
+ }
823
+ }
824
+ /**
825
+ * A heading at the given level (1–6, defaults to 2).
826
+ *
827
+ * Use this instead of a raw `{ role: 'heading', level: 2 }` literal to
828
+ * benefit from the default-level guard and the `kind` discriminator.
829
+ */
830
+ class A11yHeadingNode extends A11yNodeDto {
831
+ constructor(id, opts = {}) {
832
+ super();
833
+ this.id = id;
834
+ this.opts = opts;
835
+ this.kind = 'heading';
836
+ }
837
+ /**
838
+ * Compile this DTO into its `A11yNode` representation.
839
+ *
840
+ * @returns {A11yNode} The compiled semantic node.
841
+ */
842
+ toA11yNode() {
843
+ var _a;
844
+ return {
845
+ id: this.id,
846
+ kind: this.kind,
847
+ role: 'heading',
848
+ level: (_a = this.opts.level) !== null && _a !== void 0 ? _a : 2,
849
+ label: this.opts.label,
850
+ children: this.compileChildren(),
851
+ };
852
+ }
853
+ }
854
+ /**
855
+ * A purely decorative icon. `decorative` is always `true` so authors never
856
+ * have to remember the flag — that is the whole point of this DTO class.
857
+ *
858
+ * Produces `aria-hidden="true"` via the baseline strategy; webkit-voiceover
859
+ * additionally sets `role="none"` as a belt-and-suspenders guard.
860
+ */
861
+ class A11yIconNode extends A11yNodeDto {
862
+ constructor(id) {
863
+ super();
864
+ this.id = id;
865
+ this.kind = 'icon';
866
+ }
867
+ /**
868
+ * Compile this DTO into its `A11yNode` representation.
869
+ *
870
+ * @returns {A11yNode} The compiled semantic node.
871
+ */
872
+ toA11yNode() {
873
+ return {
874
+ id: this.id,
875
+ kind: this.kind,
876
+ role: 'img',
877
+ decorative: true,
878
+ children: this.compileChildren(),
879
+ };
880
+ }
881
+ }
882
+
883
+ /**
884
+ * Build the semantic A11y Tree for a `vega-section-title` instance.
885
+ *
886
+ * The structure uses a presentation wrapper so the container is transparent to
887
+ * assistive technology — the heading is the semantic anchor:
888
+ *
889
+ * ```
890
+ * presentation "st-root" (role=none — AT-transparent wrapper)
891
+ * ├── heading "st-heading" (titleText, level=2 by default)
892
+ * └── icon "st-icon" (decorative — only when an icon prop is set)
893
+ * ```
894
+ *
895
+ * Description text is not wired into the A11y tree. It is exposed as plain
896
+ * visible text in the component's shadow DOM, read by screen readers via normal
897
+ * linear traversal. This avoids three VoiceOver regressions introduced when the
898
+ * container carried `role="group"` with `aria-label` + `aria-describedby`:
899
+ *
900
+ * - Bug 1 (Safari): webkit folded the description into the heading `aria-label`,
901
+ * so focusing the H2 announced both title AND description together.
902
+ * - Bug 2 (Chrome, no description): `role="group"` created an extra navigation
903
+ * boundary and announced the title twice (group label + heading).
904
+ * - Bug 3 (Chrome, with description): description read twice — once via the
905
+ * hidden `aria-describedby` span on the group, once via the visible div.
906
+ *
907
+ * **No inline ARIA / no double projection**: this function must NOT set
908
+ * `aria-*` or `role` attributes directly on the component. The A11y Tree
909
+ * slimmer (`A11yTreeSlimmer`) calls `applyA11yTree()` on every render to
910
+ * project the semantic intent through the chosen strategy.
911
+ *
912
+ * @param {BuildArgs} args - Section-title fields used to author the semantic tree.
913
+ * @returns {A11yNode} The semantic A11y Tree root for the section title.
914
+ */
915
+ function buildSectionTitleA11yTree(args) {
916
+ var _a;
917
+ const children = [];
918
+ // Only add heading if titleText is provided; avoid empty heading elements
919
+ // that cause cross-browser inconsistencies (Chrome skips them, Firefox may
920
+ // announce an empty group). The A11y Tree projection (via strategy) onto
921
+ // shadow DOM handles all ARIA semantics; no host-level ARIA is used.
922
+ if (args.titleText) {
923
+ children.push(new A11yHeadingNode('st-heading', {
924
+ level: (_a = args.headingLevel) !== null && _a !== void 0 ? _a : 2,
925
+ }).toA11yNode());
926
+ }
927
+ if (args.icon) {
928
+ children.push(new A11yIconNode('st-icon').toA11yNode());
929
+ }
930
+ return {
931
+ id: 'st-root',
932
+ role: 'none',
933
+ children,
934
+ };
935
+ }
936
+
69
937
  const vegaSectionTitleCss = ":host{display:block}.section-title-text{color:rgba(var(--v-text-primary, 32, 54, 69, 1));font-family:\"Inter\", sans-serif;font-size:20px;font-weight:700;line-height:28px;letter-spacing:0px}@media screen and (min-width: 768px) and (max-width: 1023px){.section-title-text{font-family:\"Inter\", sans-serif;font-size:20px;font-weight:700;line-height:28px;letter-spacing:0px}}@media screen and (min-width: 1024px) and (max-width: 1439px){.section-title-text{font-family:\"Inter\", sans-serif;font-size:20px;font-weight:700;line-height:28px;letter-spacing:0px}}@media screen and (min-width: 1440px) and (max-width: 9999px){.section-title-text{font-family:\"Inter\", sans-serif;font-size:20px;font-weight:700;line-height:28px;letter-spacing:0px}}.section-title-description{font-family:\"Inter\", sans-serif;font-size:18px;font-weight:500;line-height:28px;letter-spacing:0px;color:rgba(var(--v-text-secondary, 107, 116, 125, 1))}@media screen and (min-width: 768px) and (max-width: 1023px){.section-title-description{font-family:\"Inter\", sans-serif;font-size:16px;font-weight:500;line-height:22px;letter-spacing:0px}}@media screen and (min-width: 1024px) and (max-width: 1439px){.section-title-description{font-family:\"Inter\", sans-serif;font-size:16px;font-weight:500;line-height:22px;letter-spacing:0px}}@media screen and (min-width: 1440px) and (max-width: 9999px){.section-title-description{font-family:\"Inter\", sans-serif;font-size:16px;font-weight:500;line-height:22px;letter-spacing:0px}}.section-title-icon-container{margin-top:4px}.right-icon-container{display:inline-block;margin-left:8px;margin-top:4px;vertical-align:middle}.section-title-small .section-title-text{font-family:\"Inter\", sans-serif;font-size:18px;font-weight:700;line-height:25px;letter-spacing:0px}@media screen and (min-width: 768px) and (max-width: 1023px){.section-title-small .section-title-text{font-family:\"Inter\", sans-serif;font-size:18px;font-weight:700;line-height:25px;letter-spacing:0px}}@media screen and (min-width: 1024px) and (max-width: 1439px){.section-title-small .section-title-text{font-family:\"Inter\", sans-serif;font-size:18px;font-weight:700;line-height:25px;letter-spacing:0px}}@media screen and (min-width: 1440px) and (max-width: 9999px){.section-title-small .section-title-text{font-family:\"Inter\", sans-serif;font-size:18px;font-weight:700;line-height:25px;letter-spacing:0px}}";
70
938
 
71
939
  var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
@@ -84,6 +952,18 @@ const VegaSectionTitle = class {
84
952
  this.globalSlimmers = {};
85
953
  this.renderer = new VegaSectionTitleRenderer();
86
954
  this.vegaComponentUsageRuntimeMetricsSlimmer = new componentUsageRuntimeMetrics.VegaComponentUsageRuntimeMetricsSlimmer();
955
+ /**
956
+ * Projects the component's semantic accessibility intent onto the shadow
957
+ * DOM via the A11y Tree foundation. Replaces the previous inline `role` /
958
+ * `aria-label` on the host element so ARIA is authored once, in
959
+ * `buildSectionTitleA11yTree`, and projected through the browser-engine
960
+ * strategy layer (no double projection).
961
+ */
962
+ this.a11yTreeSlimmer = new A11yTreeSlimmer((host) => buildSectionTitleA11yTree({
963
+ titleText: host.titleText,
964
+ icon: host.icon,
965
+ iconAlign: host.iconAlign,
966
+ }));
87
967
  /**
88
968
  * Specifies the text content of the title displayed
89
969
  * within the section title.
@@ -112,8 +992,7 @@ const VegaSectionTitle = class {
112
992
  this.size = 'default';
113
993
  }
114
994
  render() {
115
- const ariaLabel = [this.titleText, this.description].filter(Boolean).join(', ');
116
- return component.sanitizeVegaComponent(index.h(index.Host, { role: ariaLabel ? 'group' : undefined, "aria-label": ariaLabel || undefined }, this.renderer.render()), this.host);
995
+ return component.sanitizeVegaComponent(index.h(index.Host, null, this.renderer.render()), this.host);
117
996
  }
118
997
  get host() { return index.getElement(this); }
119
998
  };
@@ -126,6 +1005,9 @@ __decorate([
126
1005
  __decorate([
127
1006
  globalSlimmerRegistry.InjectVegaSlimmer()
128
1007
  ], VegaSectionTitle.prototype, "vegaComponentUsageRuntimeMetricsSlimmer", void 0);
1008
+ __decorate([
1009
+ globalSlimmerRegistry.InjectVegaSlimmer()
1010
+ ], VegaSectionTitle.prototype, "a11yTreeSlimmer", void 0);
129
1011
  VegaSectionTitle.style = vegaSectionTitleCss;
130
1012
 
131
1013
  exports.vega_section_title = VegaSectionTitle;