@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.
- package/dist/cjs/{app-globals-76815382.js → app-globals-38afea36.js} +7 -7
- package/dist/cjs/{code-block-493c7ce7.js → code-block-4126dc3b.js} +1501 -55
- package/dist/cjs/{component-value-history-controller-slimmer.abstract-ab21fcbf.js → component-value-history-controller-slimmer.abstract-38ba956e.js} +2 -2
- package/dist/cjs/{content-state-fc34a814.js → content-state-50e8a03c.js} +142 -580
- package/dist/cjs/{element-appender-slimmer-1d6323c2.js → element-appender-slimmer-7773fdab.js} +115 -0
- package/dist/cjs/{image-annotation-action-7c4cd316.js → image-annotation-action-89363de8.js} +2 -2
- package/dist/cjs/{image-extension-30a7c10f.js → image-extension-c881c454.js} +2 -2
- package/dist/cjs/index.cjs.js +10 -10
- package/dist/cjs/{link-extension-92a63cb7.js → link-extension-b7f99a52.js} +2 -2
- package/dist/cjs/loader.cjs.js +7 -7
- package/dist/cjs/{public-rules-9e1ea1d9.js → public-rules-72894208.js} +3 -3
- package/dist/cjs/{range-30219330.js → range-95d41dea.js} +1 -1
- package/dist/cjs/{rich-text-editor-required-rule-23bf7485.js → rich-text-editor-required-rule-4d6d2493.js} +1 -1
- package/dist/cjs/{split-cell-operation-43752212.js → split-cell-operation-70be116d.js} +2 -2
- package/dist/cjs/{token-extension-d123d9d0.js → token-extension-eb828948.js} +35 -11
- package/dist/cjs/vega-code-block.cjs.entry.js +3 -3
- package/dist/cjs/vega-date-picker_2.cjs.entry.js +1 -1
- package/dist/cjs/vega-dropdown_5.cjs.entry.js +27 -4
- package/dist/cjs/vega-env-manager-23b8b23c.js +2 -2
- package/dist/cjs/vega-popover_2.cjs.entry.js +1 -1
- package/dist/cjs/vega-rich-text-content.cjs.entry.js +58 -9
- package/dist/cjs/vega-rich-text-editor_4.cjs.entry.js +608 -90
- package/dist/cjs/vega-rich-text-table-properties_3.cjs.entry.js +3 -3
- package/dist/cjs/vega-section-title.cjs.entry.js +896 -14
- package/dist/cjs/vega-time-picker_2.cjs.entry.js +1 -1
- package/dist/cjs/vega-tooltip_2.cjs.entry.js +1 -1
- package/dist/cjs/vega.cjs.js +7 -7
- package/dist/collection/components/vega-combo-box/vega-combo-box.js +2 -2
- package/dist/collection/components/vega-dropdown/vega-dropdown.js +30 -7
- package/dist/collection/components/vega-input-select/vega-input-select.js +2 -2
- package/dist/collection/components/vega-rich-text-content/vega-rich-text-content.css +4 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/block-delete-node-content-strategy.js +29 -0
- 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
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/block-transform-to-list-strategy.js +8 -3
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-annotation-strategy.abstract.js +60 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-item-replace-nest-list-strategy.js +36 -4
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-items-strategy.abstract.js +27 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-nest-items-strategy.js +74 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-remove-list-item-strategy.js +81 -1
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-selection.js +30 -0
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-list-strategy.js +160 -9
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-paragraph-strategy.js +376 -10
- package/dist/collection/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-unnest-items-strategy.js +104 -0
- package/dist/collection/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.js +2 -0
- package/dist/collection/components/vega-rich-text-editor/dto/actions/nest-list-items-action.js +12 -0
- package/dist/collection/components/vega-rich-text-editor/dto/actions/unnest-list-items-action.js +12 -0
- package/dist/collection/components/vega-rich-text-editor/dto/annotations/list-annotation.js +12 -0
- package/dist/collection/components/vega-rich-text-editor/dto/blocks/list-block.js +10 -1
- package/dist/collection/components/vega-rich-text-editor/dto/blocks/list-item-block.js +11 -3
- package/dist/collection/components/vega-rich-text-editor/dto/content-state.js +7 -1
- package/dist/collection/components/vega-rich-text-editor/dto/filter-styles-strategies/list-block/list-block-filter-styles-strategy.js +8 -4
- package/dist/collection/components/vega-rich-text-editor/dto/renderers/blocks/list-block-renderer.js +34 -1
- package/dist/collection/components/vega-rich-text-editor/dto/renderers/blocks/list-item-block-renderer.js +20 -3
- package/dist/collection/components/vega-rich-text-editor/extensions/table/annotation-handler/table-annotation-handler-base.js +25 -1
- 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
- package/dist/collection/components/vega-rich-text-editor/slimmers/controllers/helper/input-event-handler/abstract-delete-content-handler.js +29 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/bullets-numbers-toolbar-button-slimmer.js +30 -1
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/abstract-list-keyboard-handler.js +204 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-shift-tab-outdent-handler.js +42 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-tab-indent-handler.js +34 -0
- package/dist/collection/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/list-keyboard-slimmer.js +180 -0
- package/dist/collection/components/vega-section-title/slimmers/a11y-tree/build-section-title-a11y-tree.js +54 -0
- package/dist/collection/components/vega-section-title/slimmers/renderers/vega-section-title-renderer.js +4 -4
- package/dist/collection/components/vega-section-title/vega-section-title.js +18 -2
- package/dist/collection/helpers/a11y-tree/a11y-node-dto.js +210 -0
- package/dist/collection/helpers/a11y-tree/a11y-tree-applier.js +189 -0
- package/dist/collection/helpers/a11y-tree/a11y-tree.types.js +48 -0
- package/dist/collection/helpers/a11y-tree/strategies/baseline-strategy.js +78 -0
- package/dist/collection/helpers/a11y-tree/strategies/firefox-nvda-strategy.js +56 -0
- package/dist/collection/helpers/a11y-tree/strategies/webkit-voiceover-strategy.js +140 -0
- package/dist/collection/helpers/a11y-tree/strategy-resolver.js +172 -0
- package/dist/collection/helpers/slimmers/a11y-tree-slimmer.js +54 -0
- package/dist/collection/helpers/slimmers/element-appender/element-appender-slimmer.js +29 -0
- package/dist/collection/helpers/slimmers/element-appender/visibility-modifiers/clip-on-scroll-modifier.js +70 -0
- package/dist/collection/helpers/slimmers/element-appender/visibility-modifiers/visibility-modifier.interface.js +1 -0
- package/dist/collection/helpers/ui/element-appender.js +16 -0
- package/dist/esm/{app-globals-eafcc7a1.js → app-globals-d7b651c1.js} +7 -7
- package/dist/esm/{code-block-e12588fe.js → code-block-0a88b481.js} +1495 -51
- package/dist/esm/{component-value-history-controller-slimmer.abstract-4e8eb313.js → component-value-history-controller-slimmer.abstract-6846edfa.js} +2 -2
- package/dist/esm/{content-state-8032467a.js → content-state-79ca99e5.js} +105 -541
- package/dist/esm/{element-appender-slimmer-7fcb944b.js → element-appender-slimmer-73ad10ae.js} +115 -0
- package/dist/esm/{image-annotation-action-08a20d5e.js → image-annotation-action-bb299ef1.js} +2 -2
- package/dist/esm/{image-extension-b6c7e4a7.js → image-extension-48a96f98.js} +2 -2
- package/dist/esm/index.js +8 -8
- package/dist/esm/{link-extension-97fcb8fb.js → link-extension-09534514.js} +2 -2
- package/dist/esm/loader.js +7 -7
- package/dist/esm/{public-rules-c06f0d2a.js → public-rules-5eb03ef0.js} +3 -3
- package/dist/esm/{range-e999837f.js → range-d4deb7df.js} +1 -1
- package/dist/esm/{rich-text-editor-required-rule-71f8ee98.js → rich-text-editor-required-rule-5bbbce23.js} +1 -1
- package/dist/esm/{split-cell-operation-359f8082.js → split-cell-operation-7f3058ad.js} +2 -2
- package/dist/esm/{token-extension-f5bf9c21.js → token-extension-40c32bcc.js} +30 -6
- package/dist/esm/vega-code-block.entry.js +3 -3
- package/dist/esm/vega-date-picker_2.entry.js +1 -1
- package/dist/esm/vega-dropdown_5.entry.js +27 -4
- package/dist/esm/vega-env-manager-8f8dc473.js +2 -2
- package/dist/esm/vega-popover_2.entry.js +1 -1
- package/dist/esm/vega-rich-text-content.entry.js +58 -9
- package/dist/esm/vega-rich-text-editor_4.entry.js +604 -86
- package/dist/esm/vega-rich-text-table-properties_3.entry.js +3 -3
- package/dist/esm/vega-section-title.entry.js +897 -15
- package/dist/esm/vega-time-picker_2.entry.js +1 -1
- package/dist/esm/vega-tooltip_2.entry.js +1 -1
- package/dist/esm/vega.js +7 -7
- package/dist/sri/vega-sri-manifest.json +94 -94
- package/dist/types/components/vega-combo-box/vega-combo-box.d.ts +6 -6
- package/dist/types/components/vega-dropdown/types.d.ts +2 -2
- package/dist/types/components/vega-dropdown/vega-dropdown.d.ts +32 -9
- package/dist/types/components/vega-input-select/vega-input-select.d.ts +6 -6
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-annotation-strategy.abstract.d.ts +36 -0
- 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
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-items-strategy.abstract.d.ts +22 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-nest-items-strategy.d.ts +21 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-remove-list-item-strategy.d.ts +14 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-selection.d.ts +15 -0
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-list-strategy.d.ts +30 -3
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-transform-to-paragraph-strategy.d.ts +99 -3
- package/dist/types/components/vega-rich-text-editor/dto/action-handle-strategies/modify-content-strategies/list-unnest-items-strategy.d.ts +22 -0
- package/dist/types/components/vega-rich-text-editor/dto/actions/modify-content-action.abstract.d.ts +2 -0
- package/dist/types/components/vega-rich-text-editor/dto/actions/nest-list-items-action.d.ts +11 -0
- package/dist/types/components/vega-rich-text-editor/dto/actions/unnest-list-items-action.d.ts +11 -0
- package/dist/types/components/vega-rich-text-editor/dto/annotations/list-annotation.d.ts +8 -0
- package/dist/types/components/vega-rich-text-editor/dto/blocks/list-block.d.ts +6 -1
- package/dist/types/components/vega-rich-text-editor/dto/blocks/list-item-block.d.ts +5 -1
- package/dist/types/components/vega-rich-text-editor/dto/content-state.d.ts +2 -2
- package/dist/types/components/vega-rich-text-editor/dto/renderers/blocks/list-block-renderer.d.ts +2 -0
- package/dist/types/components/vega-rich-text-editor/dto/renderers/blocks/list-item-block-renderer.d.ts +8 -0
- package/dist/types/components/vega-rich-text-editor/extensions/table/annotation-handler/table-annotation-handler-base.d.ts +18 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/bullets-numbers-toolbar-button-slimmer.d.ts +8 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/abstract-list-keyboard-handler.d.ts +99 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-shift-tab-outdent-handler.d.ts +15 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/helper/list-tab-indent-handler.d.ts +15 -0
- package/dist/types/components/vega-rich-text-editor/slimmers/renderers/tools/bullets-numbers/list-keyboard-slimmer.d.ts +73 -0
- package/dist/types/components/vega-section-title/slimmers/a11y-tree/build-section-title-a11y-tree.d.ts +41 -0
- package/dist/types/components/vega-section-title/vega-section-title.d.ts +9 -0
- package/dist/types/components.d.ts +10 -10
- package/dist/types/helpers/a11y-tree/a11y-node-dto.d.ts +173 -0
- package/dist/types/helpers/a11y-tree/a11y-tree-applier.d.ts +28 -0
- package/dist/types/helpers/a11y-tree/a11y-tree.types.d.ts +137 -0
- package/dist/types/helpers/a11y-tree/strategies/baseline-strategy.d.ts +18 -0
- package/dist/types/helpers/a11y-tree/strategies/firefox-nvda-strategy.d.ts +16 -0
- package/dist/types/helpers/a11y-tree/strategies/webkit-voiceover-strategy.d.ts +23 -0
- package/dist/types/helpers/a11y-tree/strategy-resolver.d.ts +59 -0
- package/dist/types/helpers/slimmers/a11y-tree-slimmer.d.ts +49 -0
- package/dist/types/helpers/slimmers/element-appender/element-appender-slimmer.d.ts +9 -0
- package/dist/types/helpers/slimmers/element-appender/visibility-modifiers/clip-on-scroll-modifier.d.ts +37 -0
- package/dist/types/helpers/slimmers/element-appender/visibility-modifiers/visibility-modifier.interface.d.ts +56 -0
- package/dist/types/helpers/ui/element-appender.d.ts +7 -0
- package/dist/vega/index.esm.js +1 -1
- package/dist/vega/{p-9c39f90b.entry.js → p-1dfbc542.entry.js} +1 -1
- package/dist/vega/{p-e235020b.entry.js → p-22cc174e.entry.js} +1 -1
- package/dist/vega/{p-b187b82d.entry.js → p-2df5d59b.entry.js} +1 -1
- package/dist/vega/{p-f7e459cd.js → p-312d8205.js} +1 -1
- package/dist/vega/{p-a7209700.js → p-3345d903.js} +1 -1
- package/dist/vega/{p-02355de8.js → p-3c23ec90.js} +1 -1
- package/dist/vega/p-55e0014a.js +3 -0
- package/dist/vega/p-5f377954.js +1 -1
- package/dist/vega/p-65fee02f.entry.js +1 -0
- package/dist/vega/p-6a51d720.js +1 -0
- package/dist/vega/{p-fe24b459.js → p-6c7b6d45.js} +1 -1
- package/dist/vega/{p-579cdeae.js → p-84b7a775.js} +1 -1
- package/dist/vega/{p-df828d90.entry.js → p-96da7d30.entry.js} +1 -1
- package/dist/vega/{p-88be9ec5.js → p-9d3f69cb.js} +1 -1
- package/dist/vega/{p-8a001caa.js → p-9f11b579.js} +1 -1
- package/dist/vega/{p-ba2b9663.entry.js → p-acaff62d.entry.js} +1 -1
- package/dist/vega/p-b63319e9.entry.js +1 -0
- package/dist/vega/{p-c079c935.entry.js → p-b660f38c.entry.js} +1 -1
- package/dist/vega/p-b8ffa42f.entry.js +1 -0
- package/dist/vega/{p-4fe40b76.js → p-c4564904.js} +1 -1
- package/dist/vega/p-d9158512.js +1 -0
- package/dist/vega/p-e62d41ee.js +1 -0
- package/dist/vega/{p-9f7154d2.js → p-ec5dee32.js} +1 -1
- package/dist/vega/{p-05d04c07.entry.js → p-f29d9707.entry.js} +1 -1
- package/dist/vega/vega.esm.js +1 -1
- package/package.json +3 -2
- package/dist/vega/p-0be4df0a.js +0 -1
- package/dist/vega/p-38c9d782.js +0 -1
- package/dist/vega/p-513bc0d9.js +0 -1
- package/dist/vega/p-8d4b85e7.entry.js +0 -1
- package/dist/vega/p-c5d3b008.entry.js +0 -1
- package/dist/vega/p-d25ca0c3.entry.js +0 -1
- package/dist/vega/p-f4da615a.js +0 -3
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { RTEListItemBlock } from '../../../../../dto/blocks/list-item-block';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract base for list keyboard (Tab / Shift+Tab) handlers.
|
|
4
|
+
* Provides shared selection-normalization utilities used by both the indent
|
|
5
|
+
* and outdent concrete handlers.
|
|
6
|
+
*/
|
|
7
|
+
export class AbstractListKeyboardHandler {
|
|
8
|
+
/**
|
|
9
|
+
* Filter the ordered selection down to only the "root" items —
|
|
10
|
+
* items whose ancestor is not also present in the selection.
|
|
11
|
+
*
|
|
12
|
+
* @param {RTEListItemBlock[]} selection - Ordered selected list items.
|
|
13
|
+
* @returns {RTEListItemBlock[]} Root items that do not have selected ancestors.
|
|
14
|
+
*/
|
|
15
|
+
getOutdentRoots(selection) {
|
|
16
|
+
const selectedItems = new Set(selection);
|
|
17
|
+
return selection.filter((item) => !this.hasSelectedAncestor(item, selectedItems));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check whether a list item has an ancestor that is also selected.
|
|
21
|
+
*
|
|
22
|
+
* @param {RTEListItemBlock} item - Item to inspect.
|
|
23
|
+
* @param {Set<RTEListItemBlock>} selectedItems - Selected items lookup set.
|
|
24
|
+
* @returns {boolean} True when an ancestor item is selected.
|
|
25
|
+
*/
|
|
26
|
+
hasSelectedAncestor(item, selectedItems) {
|
|
27
|
+
var _a, _b;
|
|
28
|
+
let currentParent = (_a = item.parent) === null || _a === void 0 ? void 0 : _a.parent;
|
|
29
|
+
while (currentParent instanceof RTEListItemBlock) {
|
|
30
|
+
if (selectedItems.has(currentParent)) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
currentParent = (_b = currentParent.parent) === null || _b === void 0 ? void 0 : _b.parent;
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Split an ordered flat list of items into groups that share the same
|
|
39
|
+
* parent list and are contiguous siblings.
|
|
40
|
+
*
|
|
41
|
+
* @param {RTEListItemBlock[]} selection - Ordered list-item selection.
|
|
42
|
+
* @returns {RTEListItemBlock[][]} Contiguous parent-based segments.
|
|
43
|
+
*/
|
|
44
|
+
splitSelectionIntoParentSegments(selection) {
|
|
45
|
+
const segments = [];
|
|
46
|
+
let currentSegment = [];
|
|
47
|
+
selection.forEach((item) => {
|
|
48
|
+
if (currentSegment.length === 0) {
|
|
49
|
+
currentSegment.push(item);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const previousItem = currentSegment[currentSegment.length - 1];
|
|
53
|
+
const isSameParent = previousItem.parent === item.parent;
|
|
54
|
+
const isContiguousSibling = isSameParent &&
|
|
55
|
+
item.parent.children.indexOf(item) - item.parent.children.indexOf(previousItem) === 1;
|
|
56
|
+
if (isContiguousSibling) {
|
|
57
|
+
currentSegment.push(item);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
segments.push(currentSegment);
|
|
61
|
+
currentSegment = [item];
|
|
62
|
+
});
|
|
63
|
+
if (currentSegment.length > 0) {
|
|
64
|
+
segments.push(currentSegment);
|
|
65
|
+
}
|
|
66
|
+
return segments;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Normalize the selection and split into parent-based contiguous segments.
|
|
70
|
+
* Returns null when the result is empty.
|
|
71
|
+
*
|
|
72
|
+
* @param {RTEBlock[]} selectedBlocks - Raw selected blocks.
|
|
73
|
+
* @returns {RTEListItemBlock[][] | null} Contiguous segments or null when invalid.
|
|
74
|
+
*/
|
|
75
|
+
normalizeToSegments(selectedBlocks) {
|
|
76
|
+
const normalizedSelection = this.getOrderedListItems(selectedBlocks);
|
|
77
|
+
if (!normalizedSelection) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const roots = this.getOutdentRoots(normalizedSelection);
|
|
81
|
+
const segments = this.splitSelectionIntoParentSegments(roots);
|
|
82
|
+
return segments.length ? segments : null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Return the first and last RTETextNode spanning the provided blocks,
|
|
86
|
+
* or null when either boundary cannot be resolved.
|
|
87
|
+
*
|
|
88
|
+
* @param {RTEBlock[]} blocks - Blocks defining the range boundary.
|
|
89
|
+
* @returns {Nullable<[RTETextNode, RTETextNode]>} First and last boundary nodes.
|
|
90
|
+
*/
|
|
91
|
+
getSelectionBoundary(blocks) {
|
|
92
|
+
var _a, _b, _c, _d;
|
|
93
|
+
const firstNode = (_b = (_a = blocks[0]) === null || _a === void 0 ? void 0 : _a.getFirstNode()) !== null && _b !== void 0 ? _b : null;
|
|
94
|
+
const lastNode = (_d = (_c = blocks[blocks.length - 1]) === null || _c === void 0 ? void 0 : _c.getLastNode()) !== null && _d !== void 0 ? _d : null;
|
|
95
|
+
if (!firstNode || !lastNode) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
return [firstNode, lastNode];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Normalize the raw selectedBlocks into an ordered list of RTEListItemBlocks,
|
|
102
|
+
* truncating at the first non-list block. Returns null when no list items
|
|
103
|
+
* are present.
|
|
104
|
+
*
|
|
105
|
+
* @param {RTEBlock[]} selectedBlocks - Raw selected blocks.
|
|
106
|
+
* @returns {RTEListItemBlock[] | null} Ordered list items or null.
|
|
107
|
+
*/
|
|
108
|
+
getOrderedListItems(selectedBlocks) {
|
|
109
|
+
const selectedListItems = this.getSelectedListItemsUntilFirstNonList(selectedBlocks);
|
|
110
|
+
if (!selectedListItems.length) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return [...selectedListItems].sort((a, b) => this.compareTreePath(this.getTreePath(a), this.getTreePath(b)));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Collect contiguous selected list items until a non-list block is found.
|
|
117
|
+
*
|
|
118
|
+
* @param {RTEBlock[]} selectedBlocks - Raw selected blocks.
|
|
119
|
+
* @returns {RTEListItemBlock[]} Selected list items up to first non-list block.
|
|
120
|
+
*/
|
|
121
|
+
getSelectedListItemsUntilFirstNonList(selectedBlocks) {
|
|
122
|
+
const selectedListItems = [];
|
|
123
|
+
for (const block of selectedBlocks) {
|
|
124
|
+
if (!(block instanceof RTEListItemBlock)) {
|
|
125
|
+
if (selectedListItems.length > 0) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
selectedListItems.push(block);
|
|
131
|
+
}
|
|
132
|
+
return selectedListItems;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Build a hierarchical index path for a list item in the list tree.
|
|
136
|
+
*
|
|
137
|
+
* @param {RTEListItemBlock} item - Item whose tree path is being resolved.
|
|
138
|
+
* @returns {number[]} Tree index path from root to the item.
|
|
139
|
+
*/
|
|
140
|
+
getTreePath(item) {
|
|
141
|
+
var _a;
|
|
142
|
+
const path = [];
|
|
143
|
+
const visitedLists = new Set();
|
|
144
|
+
let currentItem = item;
|
|
145
|
+
let currentList = item.parent;
|
|
146
|
+
while (currentList && this.hasChildren(currentList) && !visitedLists.has(currentList)) {
|
|
147
|
+
visitedLists.add(currentList);
|
|
148
|
+
const itemIndex = currentList.children.indexOf(currentItem);
|
|
149
|
+
if (itemIndex < 0) {
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
path.unshift(itemIndex);
|
|
153
|
+
const listParent = currentList.parent;
|
|
154
|
+
if (listParent instanceof RTEListItemBlock) {
|
|
155
|
+
const nestListIndex = ((_a = listParent.nestList) !== null && _a !== void 0 ? _a : []).indexOf(currentList);
|
|
156
|
+
if (nestListIndex < 0) {
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
path.unshift(nestListIndex);
|
|
160
|
+
currentItem = listParent;
|
|
161
|
+
currentList = listParent.parent;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
let child = currentList;
|
|
165
|
+
let container = listParent;
|
|
166
|
+
while (container && this.hasChildren(container)) {
|
|
167
|
+
const childIndex = container.children.indexOf(child);
|
|
168
|
+
if (childIndex < 0) {
|
|
169
|
+
return path;
|
|
170
|
+
}
|
|
171
|
+
path.unshift(childIndex);
|
|
172
|
+
child = container;
|
|
173
|
+
container = container.parent;
|
|
174
|
+
}
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
return path;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Compare two list-item tree paths.
|
|
181
|
+
*
|
|
182
|
+
* @param {number[]} a - First tree path.
|
|
183
|
+
* @param {number[]} b - Second tree path.
|
|
184
|
+
* @returns {number} Negative when a < b, positive when a > b, otherwise 0.
|
|
185
|
+
*/
|
|
186
|
+
compareTreePath(a, b) {
|
|
187
|
+
const length = Math.min(a.length, b.length);
|
|
188
|
+
for (let i = 0; i < length; i++) {
|
|
189
|
+
if (a[i] !== b[i]) {
|
|
190
|
+
return a[i] - b[i];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return a.length - b.length;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Check whether a value exposes a children array.
|
|
197
|
+
*
|
|
198
|
+
* @param {unknown} entity - Candidate value.
|
|
199
|
+
* @returns {boolean} True when entity has children array.
|
|
200
|
+
*/
|
|
201
|
+
hasChildren(entity) {
|
|
202
|
+
return !!entity && Array.isArray(entity.children);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { RTEListItemBlock } from '../../../../../dto/blocks/list-item-block';
|
|
2
|
+
import { UnnestListItemsAction } from '../../../../../dto/actions/unnest-list-items-action';
|
|
3
|
+
import { TransformParagraphAction } from '../../../../../dto/actions/transform-paragraph-action';
|
|
4
|
+
import { VegaRTEContent } from '../../../../../dto/content-state';
|
|
5
|
+
import { RTEHtmlBlock } from '../../../../../dto/blocks/html-block';
|
|
6
|
+
import { AbstractListKeyboardHandler } from './abstract-list-keyboard-handler';
|
|
7
|
+
/**
|
|
8
|
+
* Handles Shift+Tab key list outdent.
|
|
9
|
+
* Normalizes the selection, then promotes each segment, either moving nested
|
|
10
|
+
* items or promoting top-level items to paragraphs.
|
|
11
|
+
*/
|
|
12
|
+
export class ListShiftTabOutdentHandler extends AbstractListKeyboardHandler {
|
|
13
|
+
/**
|
|
14
|
+
* @inheritDoc
|
|
15
|
+
*/
|
|
16
|
+
execute(selectedBlocks) {
|
|
17
|
+
const segments = this.normalizeToSegments(selectedBlocks);
|
|
18
|
+
if (!segments) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const segmentSelectionBoundaries = new Array(segments.length).fill(null);
|
|
22
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
23
|
+
const segment = segments[i];
|
|
24
|
+
const parentList = segment[0].parent;
|
|
25
|
+
if (parentList.parent instanceof VegaRTEContent || parentList.parent instanceof RTEHtmlBlock) {
|
|
26
|
+
// Capture boundary before action moves text nodes into new paragraphs
|
|
27
|
+
const boundary = this.getSelectionBoundary(segment);
|
|
28
|
+
parentList.apply(new TransformParagraphAction(segment));
|
|
29
|
+
segmentSelectionBoundaries[i] = boundary;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (parentList.parent instanceof RTEListItemBlock) {
|
|
33
|
+
parentList.apply(new UnnestListItemsAction(segment));
|
|
34
|
+
segmentSelectionBoundaries[i] = this.getSelectionBoundary(segment);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (segmentSelectionBoundaries.some(Boolean)) {
|
|
38
|
+
return segmentSelectionBoundaries;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { NestListItemsAction } from '../../../../../dto/actions/nest-list-items-action';
|
|
2
|
+
import { AbstractListKeyboardHandler } from './abstract-list-keyboard-handler';
|
|
3
|
+
/**
|
|
4
|
+
* Handles Tab key list indentation.
|
|
5
|
+
* Normalizes the selection, applies a command-style gate on the first
|
|
6
|
+
* eligible segment, then nests each qualifying segment.
|
|
7
|
+
*/
|
|
8
|
+
export class ListTabIndentHandler extends AbstractListKeyboardHandler {
|
|
9
|
+
/**
|
|
10
|
+
* @inheritDoc
|
|
11
|
+
*/
|
|
12
|
+
execute(selectedBlocks) {
|
|
13
|
+
const segments = this.normalizeToSegments(selectedBlocks);
|
|
14
|
+
if (!segments) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const firstSegment = segments[0];
|
|
18
|
+
const firstParentList = firstSegment[0].parent;
|
|
19
|
+
if (firstParentList.children.indexOf(firstSegment[0]) <= 0) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const segmentSelectionBoundaries = new Array(segments.length).fill(null);
|
|
23
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
24
|
+
const segment = segments[i];
|
|
25
|
+
const parentList = segment[0].parent;
|
|
26
|
+
if (parentList.children.indexOf(segment[0]) <= 0) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
parentList.apply(new NestListItemsAction(segment));
|
|
30
|
+
segmentSelectionBoundaries[i] = this.getSelectionBoundary(segment);
|
|
31
|
+
}
|
|
32
|
+
return segmentSelectionBoundaries.some(Boolean) ? segmentSelectionBoundaries : null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { MapToComponentField, MapToComponentMethod, VegaSlimmer } from 'vega-slimmer/core';
|
|
8
|
+
import { RTETextNode } from '../../../../dto/nodes/text-node';
|
|
9
|
+
import { ListTabIndentHandler } from './helper/list-tab-indent-handler';
|
|
10
|
+
import { ListShiftTabOutdentHandler } from './helper/list-shift-tab-outdent-handler';
|
|
11
|
+
const LIST_TOOLBAR_ITEMS = ['bullets', 'numbers', 'bulletsNumbers'];
|
|
12
|
+
/**
|
|
13
|
+
* Handles list keyboard shortcuts (Tab/Shift+Tab) for list tooling.
|
|
14
|
+
*/
|
|
15
|
+
export class ListKeyboardSlimmer extends VegaSlimmer {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.isKeyboardListenerBound = false;
|
|
19
|
+
this.listTabIndentHandler = new ListTabIndentHandler();
|
|
20
|
+
this.listShiftTabOutdentHandler = new ListShiftTabOutdentHandler();
|
|
21
|
+
// Keyboard action execution
|
|
22
|
+
/**
|
|
23
|
+
* Handle Tab and Shift+Tab list keyboard interactions.
|
|
24
|
+
*
|
|
25
|
+
* @param {KeyboardEvent} e - Keyboard event to process.
|
|
26
|
+
* @returns {void}
|
|
27
|
+
*/
|
|
28
|
+
this.handleListKeyboardAction = (e) => {
|
|
29
|
+
if (e.key !== 'Tab') {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (this.hasNonShiftModifierForTab(e)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const selectedBlocks = this.selectionController.getSelectedBlocks();
|
|
36
|
+
const currentRange = this.selectionController.getCurrentRange().clone();
|
|
37
|
+
if (e.shiftKey) {
|
|
38
|
+
const selectionBoundaries = this.listShiftTabOutdentHandler.execute(selectedBlocks);
|
|
39
|
+
if (selectionBoundaries) {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
void this.valueController.flushChanges(this.value).then(() => {
|
|
42
|
+
this.restoreListSelection(selectionBoundaries, currentRange.startNode instanceof RTETextNode ? currentRange.startNode : null, currentRange.endNode instanceof RTETextNode ? currentRange.endNode : null, currentRange.startOffset, currentRange.endOffset);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const selectionBoundaries = this.listTabIndentHandler.execute(selectedBlocks);
|
|
48
|
+
if (!selectionBoundaries) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
void this.valueController.flushChanges(this.value).then(() => {
|
|
53
|
+
this.restoreListSelection(selectionBoundaries, currentRange.startNode instanceof RTETextNode ? currentRange.startNode : null, currentRange.endNode instanceof RTETextNode ? currentRange.endNode : null, currentRange.startOffset, currentRange.endOffset);
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Listener lifecycle and gating
|
|
58
|
+
/**
|
|
59
|
+
* @inheritDoc
|
|
60
|
+
*/
|
|
61
|
+
disconnectedCallback() {
|
|
62
|
+
this.removeListKeyboardListener();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* @inheritDoc
|
|
66
|
+
*/
|
|
67
|
+
componentDidLoad() {
|
|
68
|
+
this.syncListKeyboardListener();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Re-sync keyboard listener when toolbarItems prop changes at runtime,
|
|
72
|
+
* ensuring list shortcuts are bound/unbound as tools are added/removed.
|
|
73
|
+
*/
|
|
74
|
+
watchToolbarItems() {
|
|
75
|
+
this.syncListKeyboardListener();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Synchronize the DOM keydown listener with the configured toolbar items.
|
|
79
|
+
*/
|
|
80
|
+
syncListKeyboardListener() {
|
|
81
|
+
if (this.hasListToolbarConfigured()) {
|
|
82
|
+
this.addListKeyboardListener();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
this.removeListKeyboardListener();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Determine whether any list keyboard controls are enabled in the toolbar.
|
|
89
|
+
*
|
|
90
|
+
* @returns {boolean} True when any list toolbar item is configured.
|
|
91
|
+
*/
|
|
92
|
+
hasListToolbarConfigured() {
|
|
93
|
+
const flatToolbarItems = this.toolbarItems.flat();
|
|
94
|
+
return flatToolbarItems.some((item) => LIST_TOOLBAR_ITEMS.includes(item));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Attach the keydown listener to the current editable element when available.
|
|
98
|
+
* Handles element ref changes by rebinding when the target element differs.
|
|
99
|
+
*/
|
|
100
|
+
addListKeyboardListener() {
|
|
101
|
+
const editableElement = this.vegaRichTextEditorRenderer.getRTEEditableElementRef();
|
|
102
|
+
if (this.isKeyboardListenerBound && this.boundEditableElement === editableElement) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (this.isKeyboardListenerBound) {
|
|
106
|
+
this.removeListKeyboardListener();
|
|
107
|
+
}
|
|
108
|
+
if (!editableElement) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
editableElement.addEventListener('keydown', this.handleListKeyboardAction);
|
|
112
|
+
this.boundEditableElement = editableElement;
|
|
113
|
+
this.isKeyboardListenerBound = true;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Detach the keydown listener from the previously bound editable element.
|
|
117
|
+
*/
|
|
118
|
+
removeListKeyboardListener() {
|
|
119
|
+
if (!this.isKeyboardListenerBound || !this.boundEditableElement) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
this.boundEditableElement.removeEventListener('keydown', this.handleListKeyboardAction);
|
|
123
|
+
this.boundEditableElement = null;
|
|
124
|
+
this.isKeyboardListenerBound = false;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Check whether the Tab event includes modifiers other than Shift.
|
|
128
|
+
*
|
|
129
|
+
* @param {KeyboardEvent} e - Keyboard event to inspect.
|
|
130
|
+
* @returns {boolean} True when non-shift modifier keys are pressed.
|
|
131
|
+
*/
|
|
132
|
+
hasNonShiftModifierForTab(e) {
|
|
133
|
+
return e.altKey || e.ctrlKey || e.metaKey || e.getModifierState('AltGraph');
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Restore the logical selection after a list keyboard action completes.
|
|
137
|
+
*
|
|
138
|
+
* @param {Array<Nullable<[RTETextNode, RTETextNode]>>} selectionBoundaries - Boundaries produced by the handler.
|
|
139
|
+
* @param {Nullable<RTETextNode>} preferredStartNode - Preferred start node from prior selection.
|
|
140
|
+
* @param {Nullable<RTETextNode>} preferredEndNode - Preferred end node from prior selection.
|
|
141
|
+
* @param {number} startOffset - Preferred start offset.
|
|
142
|
+
* @param {number} endOffset - Preferred end offset.
|
|
143
|
+
* @returns {void}
|
|
144
|
+
*/
|
|
145
|
+
restoreListSelection(selectionBoundaries, preferredStartNode, preferredEndNode, startOffset, endOffset) {
|
|
146
|
+
var _a, _b, _c, _d;
|
|
147
|
+
const firstBoundary = (_a = selectionBoundaries.find(Boolean)) !== null && _a !== void 0 ? _a : null;
|
|
148
|
+
const lastBoundary = (_b = [...selectionBoundaries].reverse().find(Boolean)) !== null && _b !== void 0 ? _b : null;
|
|
149
|
+
const firstNode = (_c = preferredStartNode !== null && preferredStartNode !== void 0 ? preferredStartNode : firstBoundary === null || firstBoundary === void 0 ? void 0 : firstBoundary[0]) !== null && _c !== void 0 ? _c : null;
|
|
150
|
+
const lastNode = (_d = preferredEndNode !== null && preferredEndNode !== void 0 ? preferredEndNode : lastBoundary === null || lastBoundary === void 0 ? void 0 : lastBoundary[1]) !== null && _d !== void 0 ? _d : null;
|
|
151
|
+
if (!firstNode || !lastNode) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
this.selectionController.enqueueSelectionRangeFutureState(firstNode, Math.min(startOffset, firstNode.getRangeEndOffset()), lastNode, Math.min(endOffset, lastNode.getRangeEndOffset()), true);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
__decorate([
|
|
158
|
+
MapToComponentField()
|
|
159
|
+
], ListKeyboardSlimmer.prototype, "selectionController", void 0);
|
|
160
|
+
__decorate([
|
|
161
|
+
MapToComponentField()
|
|
162
|
+
], ListKeyboardSlimmer.prototype, "valueController", void 0);
|
|
163
|
+
__decorate([
|
|
164
|
+
MapToComponentField()
|
|
165
|
+
], ListKeyboardSlimmer.prototype, "value", void 0);
|
|
166
|
+
__decorate([
|
|
167
|
+
MapToComponentField()
|
|
168
|
+
], ListKeyboardSlimmer.prototype, "toolbarItems", void 0);
|
|
169
|
+
__decorate([
|
|
170
|
+
MapToComponentField()
|
|
171
|
+
], ListKeyboardSlimmer.prototype, "vegaRichTextEditorRenderer", void 0);
|
|
172
|
+
__decorate([
|
|
173
|
+
MapToComponentMethod('disconnectedCallback')
|
|
174
|
+
], ListKeyboardSlimmer.prototype, "disconnectedCallback", null);
|
|
175
|
+
__decorate([
|
|
176
|
+
MapToComponentMethod('componentDidLoad')
|
|
177
|
+
], ListKeyboardSlimmer.prototype, "componentDidLoad", null);
|
|
178
|
+
__decorate([
|
|
179
|
+
MapToComponentMethod('watchToolbarItems')
|
|
180
|
+
], ListKeyboardSlimmer.prototype, "watchToolbarItems", null);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { A11yHeadingNode, A11yIconNode } from '../../../../helpers/a11y-tree/a11y-node-dto';
|
|
2
|
+
/**
|
|
3
|
+
* Build the semantic A11y Tree for a `vega-section-title` instance.
|
|
4
|
+
*
|
|
5
|
+
* The structure uses a presentation wrapper so the container is transparent to
|
|
6
|
+
* assistive technology — the heading is the semantic anchor:
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* presentation "st-root" (role=none — AT-transparent wrapper)
|
|
10
|
+
* ├── heading "st-heading" (titleText, level=2 by default)
|
|
11
|
+
* └── icon "st-icon" (decorative — only when an icon prop is set)
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Description text is not wired into the A11y tree. It is exposed as plain
|
|
15
|
+
* visible text in the component's shadow DOM, read by screen readers via normal
|
|
16
|
+
* linear traversal. This avoids three VoiceOver regressions introduced when the
|
|
17
|
+
* container carried `role="group"` with `aria-label` + `aria-describedby`:
|
|
18
|
+
*
|
|
19
|
+
* - Bug 1 (Safari): webkit folded the description into the heading `aria-label`,
|
|
20
|
+
* so focusing the H2 announced both title AND description together.
|
|
21
|
+
* - Bug 2 (Chrome, no description): `role="group"` created an extra navigation
|
|
22
|
+
* boundary and announced the title twice (group label + heading).
|
|
23
|
+
* - Bug 3 (Chrome, with description): description read twice — once via the
|
|
24
|
+
* hidden `aria-describedby` span on the group, once via the visible div.
|
|
25
|
+
*
|
|
26
|
+
* **No inline ARIA / no double projection**: this function must NOT set
|
|
27
|
+
* `aria-*` or `role` attributes directly on the component. The A11y Tree
|
|
28
|
+
* slimmer (`A11yTreeSlimmer`) calls `applyA11yTree()` on every render to
|
|
29
|
+
* project the semantic intent through the chosen strategy.
|
|
30
|
+
*
|
|
31
|
+
* @param {BuildArgs} args - Section-title fields used to author the semantic tree.
|
|
32
|
+
* @returns {A11yNode} The semantic A11y Tree root for the section title.
|
|
33
|
+
*/
|
|
34
|
+
export function buildSectionTitleA11yTree(args) {
|
|
35
|
+
var _a;
|
|
36
|
+
const children = [];
|
|
37
|
+
// Only add heading if titleText is provided; avoid empty heading elements
|
|
38
|
+
// that cause cross-browser inconsistencies (Chrome skips them, Firefox may
|
|
39
|
+
// announce an empty group). The A11y Tree projection (via strategy) onto
|
|
40
|
+
// shadow DOM handles all ARIA semantics; no host-level ARIA is used.
|
|
41
|
+
if (args.titleText) {
|
|
42
|
+
children.push(new A11yHeadingNode('st-heading', {
|
|
43
|
+
level: (_a = args.headingLevel) !== null && _a !== void 0 ? _a : 2,
|
|
44
|
+
}).toA11yNode());
|
|
45
|
+
}
|
|
46
|
+
if (args.icon) {
|
|
47
|
+
children.push(new A11yIconNode('st-icon').toA11yNode());
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
id: 'st-root',
|
|
51
|
+
role: 'none',
|
|
52
|
+
children,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -8,13 +8,13 @@ import { h } from '@stencil/core';
|
|
|
8
8
|
import { MapToComponentField, VegaSlimmer } from 'vega-slimmer/core';
|
|
9
9
|
export class VegaSectionTitleRenderer extends VegaSlimmer {
|
|
10
10
|
render() {
|
|
11
|
-
return (h("vega-flex", { "
|
|
11
|
+
return (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 },
|
|
12
12
|
this.renderPrefixIcon(),
|
|
13
13
|
this.renderText()));
|
|
14
14
|
}
|
|
15
15
|
renderPrefixIcon() {
|
|
16
16
|
return (this.icon &&
|
|
17
|
-
this.iconAlign === 'left' && h("div", { class: "section-title-icon-container" }, this.renderIcon()));
|
|
17
|
+
this.iconAlign === 'left' && (h("div", { "data-a11y-id": "st-icon", class: "section-title-icon-container" }, this.renderIcon())));
|
|
18
18
|
}
|
|
19
19
|
renderText() {
|
|
20
20
|
return (h("vega-flex", { class: "vega-flex-grow", direction: "col", "align-items": "start", "justify-content": "start", gap: "size-4" },
|
|
@@ -23,7 +23,7 @@ export class VegaSectionTitleRenderer extends VegaSlimmer {
|
|
|
23
23
|
}
|
|
24
24
|
renderTitle() {
|
|
25
25
|
return (h("div", { class: "section-title-text vega-flex-grow" },
|
|
26
|
-
h("span",
|
|
26
|
+
h("span", { "data-a11y-id": "st-heading" }, this.titleText),
|
|
27
27
|
this.renderSuffixIcon()));
|
|
28
28
|
}
|
|
29
29
|
renderDescription() {
|
|
@@ -31,7 +31,7 @@ export class VegaSectionTitleRenderer extends VegaSlimmer {
|
|
|
31
31
|
}
|
|
32
32
|
renderSuffixIcon() {
|
|
33
33
|
return (this.icon &&
|
|
34
|
-
this.iconAlign === 'right' && h("div", { class: "right-icon-container" }, this.renderIcon()));
|
|
34
|
+
this.iconAlign === 'right' && (h("div", { "data-a11y-id": "st-icon", class: "right-icon-container" }, this.renderIcon())));
|
|
35
35
|
}
|
|
36
36
|
renderIcon() {
|
|
37
37
|
return (h("vega-icon", { icon: this.icon, color: this.iconColor, size: this.size === 'small' ? 'size-16' : 'size-20', class: "vega-flex-shrink-0" }));
|
|
@@ -9,6 +9,8 @@ import { sanitizeVegaComponent } from '../../utils/component';
|
|
|
9
9
|
import { InjectVegaGlobalSlimmer, InjectVegaSlimmer } from 'vega-slimmer/core';
|
|
10
10
|
import { VegaSectionTitleRenderer } from './slimmers/renderers/vega-section-title-renderer';
|
|
11
11
|
import { VegaComponentUsageRuntimeMetricsSlimmer } from '../../helpers/slimmers/component-usage-runtime-metrics';
|
|
12
|
+
import { A11yTreeSlimmer } from '../../helpers/slimmers/a11y-tree-slimmer';
|
|
13
|
+
import { buildSectionTitleA11yTree } from './slimmers/a11y-tree/build-section-title-a11y-tree';
|
|
12
14
|
/**
|
|
13
15
|
* @vegaVersion 2.1.0
|
|
14
16
|
*/
|
|
@@ -17,6 +19,18 @@ export class VegaSectionTitle {
|
|
|
17
19
|
this.globalSlimmers = {};
|
|
18
20
|
this.renderer = new VegaSectionTitleRenderer();
|
|
19
21
|
this.vegaComponentUsageRuntimeMetricsSlimmer = new VegaComponentUsageRuntimeMetricsSlimmer();
|
|
22
|
+
/**
|
|
23
|
+
* Projects the component's semantic accessibility intent onto the shadow
|
|
24
|
+
* DOM via the A11y Tree foundation. Replaces the previous inline `role` /
|
|
25
|
+
* `aria-label` on the host element so ARIA is authored once, in
|
|
26
|
+
* `buildSectionTitleA11yTree`, and projected through the browser-engine
|
|
27
|
+
* strategy layer (no double projection).
|
|
28
|
+
*/
|
|
29
|
+
this.a11yTreeSlimmer = new A11yTreeSlimmer((host) => buildSectionTitleA11yTree({
|
|
30
|
+
titleText: host.titleText,
|
|
31
|
+
icon: host.icon,
|
|
32
|
+
iconAlign: host.iconAlign,
|
|
33
|
+
}));
|
|
20
34
|
/**
|
|
21
35
|
* Specifies the text content of the title displayed
|
|
22
36
|
* within the section title.
|
|
@@ -45,8 +59,7 @@ export class VegaSectionTitle {
|
|
|
45
59
|
this.size = 'default';
|
|
46
60
|
}
|
|
47
61
|
render() {
|
|
48
|
-
|
|
49
|
-
return sanitizeVegaComponent(h(Host, { role: ariaLabel ? 'group' : undefined, "aria-label": ariaLabel || undefined }, this.renderer.render()), this.host);
|
|
62
|
+
return sanitizeVegaComponent(h(Host, null, this.renderer.render()), this.host);
|
|
50
63
|
}
|
|
51
64
|
static get is() { return "vega-section-title"; }
|
|
52
65
|
static get encapsulation() { return "shadow"; }
|
|
@@ -208,3 +221,6 @@ __decorate([
|
|
|
208
221
|
__decorate([
|
|
209
222
|
InjectVegaSlimmer()
|
|
210
223
|
], VegaSectionTitle.prototype, "vegaComponentUsageRuntimeMetricsSlimmer", void 0);
|
|
224
|
+
__decorate([
|
|
225
|
+
InjectVegaSlimmer()
|
|
226
|
+
], VegaSectionTitle.prototype, "a11yTreeSlimmer", void 0);
|