@threadlabs/looma 0.14.8 → 0.15.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/components/shared/icons.js +5 -0
- package/components/shared/menu-navigation.js +49 -0
- package/components/shared/overlay.js +33 -60
- package/components/ui-avatar/ui-avatar.html +19 -2
- package/components/ui-avatar/ui-avatar.js +7 -1
- package/components/ui-avatar-group/ui-avatar-group.html +8 -3
- package/components/ui-avatar-group/ui-avatar-group.js +6 -2
- package/components/ui-badge/ui-badge.html +70 -4
- package/components/ui-button/ui-button.html +21 -5
- package/components/ui-button/ui-button.js +10 -0
- package/components/ui-callout/ui-callout.html +13 -5
- package/components/ui-checkbox/ui-checkbox.html +11 -0
- package/components/ui-combobox/ui-combobox.html +46 -10
- package/components/ui-combobox/ui-combobox.js +5 -5
- package/components/ui-context-menu/ui-context-menu.html +33 -5
- package/components/ui-context-menu/ui-context-menu.js +26 -17
- package/components/ui-dialog/ui-dialog.html +51 -8
- package/components/ui-dialog/ui-dialog.js +28 -7
- package/components/ui-disclosure/ui-disclosure.html +14 -5
- package/components/ui-disclosure/ui-disclosure.js +51 -4
- package/components/ui-editable/ui-editable.html +17 -3
- package/components/ui-editable/ui-editable.js +7 -0
- package/components/ui-editor-insert-table-grid/ui-editor-insert-table-grid.html +48 -14
- package/components/ui-editor-insert-table-grid/ui-editor-insert-table-grid.js +40 -6
- package/components/ui-editor-mention-menu/ui-editor-mention-menu.html +22 -9
- package/components/ui-editor-mention-menu/ui-editor-mention-menu.js +33 -11
- package/components/ui-editor-mention-menu-item/ui-editor-mention-menu-item.html +67 -0
- package/components/ui-editor-slash-menu/ui-editor-slash-menu.html +33 -30
- package/components/ui-editor-slash-menu/ui-editor-slash-menu.js +42 -8
- package/components/ui-editor-slash-menu-group/ui-editor-slash-menu-group.html +31 -0
- package/components/ui-editor-slash-menu-item/ui-editor-slash-menu-item.html +75 -0
- package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.html +16 -5
- package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.js +10 -2
- package/components/ui-editor-table-overlay/ui-editor-table-overlay.html +5 -5
- package/components/ui-editor-table-overlay/ui-editor-table-overlay.js +5 -2
- package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.html +14 -4
- package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.js +2 -2
- package/components/ui-editor-toolbar/ui-editor-toolbar.html +1 -1
- package/components/ui-editor-toolbar/ui-editor-toolbar.js +46 -0
- package/components/ui-floating-action-button/ui-floating-action-button.html +1 -1
- package/components/ui-form-field/ui-form-field.html +16 -3
- package/components/ui-form-field/ui-form-field.js +1 -1
- package/components/ui-grid/ui-grid.html +17 -2
- package/components/ui-icon/ui-icon.html +5 -0
- package/components/ui-icon-button/ui-icon-button.html +25 -6
- package/components/ui-icon-button/ui-icon-button.js +11 -1
- package/components/ui-input/ui-input.html +3 -3
- package/components/ui-input-group/ui-input-group.html +18 -4
- package/components/ui-listbox/ui-listbox.html +81 -0
- package/components/ui-listbox/ui-listbox.js +27 -0
- package/components/ui-menu/ui-menu.html +33 -5
- package/components/ui-menu/ui-menu.js +18 -12
- package/components/ui-menu-group/ui-menu-group.html +27 -0
- package/components/ui-menu-item/ui-menu-item.html +80 -8
- package/components/ui-menu-item/ui-menu-item.js +47 -0
- package/components/ui-popover/ui-popover.html +33 -5
- package/components/ui-popover/ui-popover.js +9 -1
- package/components/ui-radio-group/ui-radio-group.html +13 -1
- package/components/ui-search-shell/ui-search-shell.html +6 -6
- package/components/ui-search-shell/ui-search-shell.js +21 -5
- package/components/ui-select/ui-select.html +14 -4
- package/components/ui-switch/ui-switch.html +2 -2
- package/components/ui-switcher/ui-switcher.html +8 -1
- package/components/ui-switcher/ui-switcher.js +15 -0
- package/components/ui-tabs/ui-tabs.html +17 -12
- package/components/ui-tabs/ui-tabs.js +43 -7
- package/components/ui-textarea/ui-textarea.html +28 -5
- package/components/ui-toast/ui-toast.html +88 -0
- package/components/ui-toast/ui-toast.js +68 -0
- package/components/ui-toast-region/ui-toast-region.html +102 -19
- package/components/ui-toast-region/ui-toast-region.js +10 -18
- package/components/ui-tooltip/ui-tooltip.html +51 -7
- package/components/ui-tooltip/ui-tooltip.js +29 -3
- package/components/ui-tree/ui-tree.html +12 -0
- package/components/ui-tree/ui-tree.js +191 -12
- package/components/ui-tree-item/ui-tree-item.html +87 -8
- package/components/ui-tree-item/ui-tree-item.js +3 -1
- package/dist/index.js +38 -32
- package/editor/chunks/extensions.js +82 -2
- package/editor/extensions/table-commands.d.ts +8 -0
- package/editor/icons.d.ts +5 -0
- package/editor/index.js +7 -2
- package/editor/insert-table-grid.d.ts +1 -1
- package/editor/mention-menu.d.ts +2 -0
- package/editor/slash-menu.d.ts +3 -0
- package/editor/table-context-menu.d.ts +1 -1
- package/editor/table-overlay.d.ts +2 -2
- package/package.json +1 -1
- package/styles/ui-avatar-group.css +1 -2
- package/styles/ui-avatar.css +11 -1
- package/styles/ui-badge.css +73 -1
- package/styles/ui-button.css +9 -1
- package/styles/ui-callout.css +1 -1
- package/styles/ui-checkbox.css +9 -0
- package/styles/ui-combobox.css +38 -7
- package/styles/ui-context-menu.css +32 -4
- package/styles/ui-dialog.css +42 -5
- package/styles/ui-editor-insert-table-grid.css +48 -11
- package/styles/ui-editor-mention-menu-item.css +57 -0
- package/styles/ui-editor-mention-menu.css +11 -1
- package/styles/ui-editor-slash-menu-group.css +21 -0
- package/styles/ui-editor-slash-menu-item.css +62 -0
- package/styles/ui-editor-slash-menu.css +10 -21
- package/styles/ui-editor-table-context-menu.css +1 -1
- package/styles/ui-floating-action-button.css +1 -1
- package/styles/ui-form-field.css +14 -1
- package/styles/ui-grid.css +14 -1
- package/styles/ui-icon-button.css +17 -5
- package/styles/ui-input-group.css +18 -4
- package/styles/ui-input.css +3 -3
- package/styles/ui-listbox.css +69 -0
- package/styles/ui-menu-group.css +19 -0
- package/styles/ui-menu-item.css +48 -9
- package/styles/ui-menu.css +32 -4
- package/styles/ui-popover.css +28 -4
- package/styles/ui-radio-group.css +9 -0
- package/styles/ui-search-shell.css +5 -5
- package/styles/ui-select.css +14 -4
- package/styles/ui-switch.css +2 -2
- package/styles/ui-switcher.css +4 -0
- package/styles/ui-textarea.css +27 -4
- package/styles/ui-toast-region.css +88 -4
- package/styles/ui-toast.css +74 -0
- package/styles/ui-tooltip.css +46 -6
- package/styles/ui-tree-item.css +72 -4
- package/styles/ui-tree.css +8 -0
- package/tokens.css +3 -0
- package/vanilla/UiAvatar.d.ts +2 -0
- package/vanilla/UiAvatar.js +8 -1
- package/vanilla/UiAvatarGroup.d.ts +2 -0
- package/vanilla/UiAvatarGroup.js +1 -1
- package/vanilla/UiBadge.d.ts +1 -1
- package/vanilla/UiBadge.js +1 -1
- package/vanilla/UiButton.d.ts +1 -0
- package/vanilla/UiButton.js +22 -6
- package/vanilla/UiCallout.d.ts +1 -1
- package/vanilla/UiCallout.js +1 -1
- package/vanilla/UiCheckbox.d.ts +1 -0
- package/vanilla/UiCheckbox.js +12 -9
- package/vanilla/UiCombobox.d.ts +3 -0
- package/vanilla/UiCombobox.js +30 -15
- package/vanilla/UiContextMenu.d.ts +1 -1
- package/vanilla/UiContextMenu.js +1 -1
- package/vanilla/UiDialog.d.ts +5 -2
- package/vanilla/UiDialog.js +1 -1
- package/vanilla/UiDisclosure.d.ts +2 -0
- package/vanilla/UiDisclosure.js +32 -18
- package/vanilla/UiEditable.d.ts +5 -0
- package/vanilla/UiEditable.js +7 -3
- package/vanilla/UiEditorInsertTableGrid.js +1 -6
- package/vanilla/UiEditorMentionMenu.d.ts +4 -2
- package/vanilla/UiEditorMentionMenu.js +49 -31
- package/vanilla/UiEditorMentionMenuItem.d.ts +16 -0
- package/vanilla/UiEditorMentionMenuItem.js +56 -0
- package/vanilla/UiEditorSlashMenu.d.ts +4 -3
- package/vanilla/UiEditorSlashMenu.js +59 -46
- package/vanilla/UiEditorSlashMenuGroup.d.ts +14 -0
- package/vanilla/UiEditorSlashMenuGroup.js +48 -0
- package/vanilla/UiEditorSlashMenuItem.d.ts +18 -0
- package/vanilla/UiEditorSlashMenuItem.js +57 -0
- package/vanilla/UiEditorTableContextMenu.d.ts +5 -2
- package/vanilla/UiEditorTableContextMenu.js +1 -2
- package/vanilla/UiEditorTableOverlay.d.ts +1 -1
- package/vanilla/UiEditorTableOverlay.js +5 -5
- package/vanilla/UiEditorTableToolbar.d.ts +4 -2
- package/vanilla/UiEditorTableToolbar.js +1 -2
- package/vanilla/UiEditorToolbar.js +2 -0
- package/vanilla/UiGrid.d.ts +1 -0
- package/vanilla/UiGrid.js +8 -7
- package/vanilla/UiIcon.js +1 -1
- package/vanilla/UiIconButton.d.ts +1 -0
- package/vanilla/UiIconButton.js +11 -2
- package/vanilla/UiListbox.d.ts +20 -0
- package/vanilla/UiListbox.js +45 -0
- package/vanilla/UiMenu.d.ts +1 -1
- package/vanilla/UiMenu.js +1 -1
- package/vanilla/UiMenuGroup.d.ts +14 -0
- package/vanilla/UiMenuGroup.js +35 -0
- package/vanilla/UiMenuItem.d.ts +5 -1
- package/vanilla/UiMenuItem.js +91 -30
- package/vanilla/UiPopover.d.ts +1 -1
- package/vanilla/UiPopover.js +1 -1
- package/vanilla/UiRadioGroup.d.ts +1 -0
- package/vanilla/UiRadioGroup.js +6 -3
- package/vanilla/UiSwitcher.d.ts +1 -0
- package/vanilla/UiSwitcher.js +7 -9
- package/vanilla/UiTabs.d.ts +1 -0
- package/vanilla/UiTabs.js +9 -1
- package/vanilla/UiTextarea.d.ts +1 -0
- package/vanilla/UiTextarea.js +4 -1
- package/vanilla/UiToast.d.ts +16 -0
- package/vanilla/UiToast.js +53 -0
- package/vanilla/UiToastRegion.d.ts +1 -4
- package/vanilla/UiToastRegion.js +3 -11
- package/vanilla/UiTooltip.d.ts +1 -1
- package/vanilla/UiTooltip.js +1 -1
- package/vanilla/UiTree.d.ts +2 -0
- package/vanilla/UiTree.js +1 -1
- package/vanilla/UiTreeItem.d.ts +1 -0
- package/vanilla/UiTreeItem.js +45 -31
- package/vanilla/index.js +6 -0
- package/vue/UiAvatar.d.ts +4 -0
- package/vue/UiAvatar.vue +23 -3
- package/vue/UiAvatarGroup.d.ts +3 -0
- package/vue/UiAvatarGroup.vue +7 -4
- package/vue/UiBadge.d.ts +2 -2
- package/vue/UiBadge.vue +74 -2
- package/vue/UiButton.d.ts +5 -3
- package/vue/UiButton.vue +41 -7
- package/vue/UiCallout.d.ts +2 -2
- package/vue/UiCallout.vue +3 -2
- package/vue/UiCheckbox.d.ts +2 -0
- package/vue/UiCheckbox.vue +16 -0
- package/vue/UiCombobox.d.ts +11 -3
- package/vue/UiCombobox.vue +60 -11
- package/vue/UiContextMenu.d.ts +2 -0
- package/vue/UiContextMenu.vue +47 -6
- package/vue/UiDialog.d.ts +18 -4
- package/vue/UiDialog.vue +86 -11
- package/vue/UiDisclosure.d.ts +8 -2
- package/vue/UiDisclosure.vue +38 -14
- package/vue/UiEditable.d.ts +10 -0
- package/vue/UiEditable.vue +14 -2
- package/vue/UiEditorInsertTableGrid.vue +52 -15
- package/vue/UiEditorMentionMenu.d.ts +24 -2
- package/vue/UiEditorMentionMenu.vue +27 -11
- package/vue/UiEditorMentionMenuItem.d.ts +24 -0
- package/vue/UiEditorMentionMenuItem.js +2 -0
- package/vue/UiEditorMentionMenuItem.vue +88 -0
- package/vue/UiEditorSlashMenu.d.ts +24 -1
- package/vue/UiEditorSlashMenu.vue +33 -33
- package/vue/UiEditorSlashMenuGroup.d.ts +18 -0
- package/vue/UiEditorSlashMenuGroup.js +2 -0
- package/vue/UiEditorSlashMenuGroup.vue +43 -0
- package/vue/UiEditorSlashMenuItem.d.ts +26 -0
- package/vue/UiEditorSlashMenuItem.js +2 -0
- package/vue/UiEditorSlashMenuItem.vue +101 -0
- package/vue/UiEditorTableContextMenu.d.ts +9 -3
- package/vue/UiEditorTableContextMenu.vue +53 -3
- package/vue/UiEditorTableOverlay.d.ts +2 -2
- package/vue/UiEditorTableOverlay.vue +8 -6
- package/vue/UiEditorTableToolbar.d.ts +7 -3
- package/vue/UiEditorTableToolbar.vue +50 -2
- package/vue/UiEditorToolbar.vue +14 -1
- package/vue/UiFloatingActionButton.vue +1 -1
- package/vue/UiFormField.vue +28 -3
- package/vue/UiGrid.d.ts +1 -0
- package/vue/UiGrid.vue +26 -2
- package/vue/UiIcon.vue +16 -0
- package/vue/UiIconButton.d.ts +5 -3
- package/vue/UiIconButton.vue +40 -6
- package/vue/UiInput.vue +10 -3
- package/vue/UiInputGroup.vue +32 -11
- package/vue/UiListbox.d.ts +33 -0
- package/vue/UiListbox.js +2 -0
- package/vue/UiListbox.vue +131 -0
- package/vue/UiMenu.d.ts +2 -0
- package/vue/UiMenu.vue +43 -6
- package/vue/UiMenuGroup.d.ts +18 -0
- package/vue/UiMenuGroup.js +2 -0
- package/vue/UiMenuGroup.vue +39 -0
- package/vue/UiMenuItem.d.ts +34 -2
- package/vue/UiMenuItem.vue +145 -9
- package/vue/UiPopover.d.ts +2 -2
- package/vue/UiPopover.vue +44 -5
- package/vue/UiRadioGroup.d.ts +2 -0
- package/vue/UiRadioGroup.vue +17 -0
- package/vue/UiSearchShell.vue +12 -5
- package/vue/UiSelect.vue +18 -4
- package/vue/UiSwitch.vue +2 -2
- package/vue/UiSwitcher.d.ts +1 -0
- package/vue/UiSwitcher.vue +22 -1
- package/vue/UiTabs.d.ts +6 -2
- package/vue/UiTabs.vue +14 -12
- package/vue/UiTextarea.d.ts +2 -0
- package/vue/UiTextarea.vue +32 -4
- package/vue/UiToast.d.ts +34 -0
- package/vue/UiToast.js +2 -0
- package/vue/UiToast.vue +173 -0
- package/vue/UiToastRegion.d.ts +2 -18
- package/vue/UiToastRegion.vue +123 -48
- package/vue/UiTooltip.d.ts +2 -2
- package/vue/UiTooltip.vue +67 -12
- package/vue/UiTree.d.ts +10 -0
- package/vue/UiTree.vue +27 -0
- package/vue/UiTreeItem.d.ts +2 -0
- package/vue/UiTreeItem.vue +96 -4
- package/vue/chunks/UiAvatar.js +19 -5
- package/vue/chunks/UiAvatarGroup.js +10 -4
- package/vue/chunks/UiBadge.js +1 -1
- package/vue/chunks/UiButton.js +58 -11
- package/vue/chunks/UiCallout.js +2 -2
- package/vue/chunks/UiCheckbox.js +12 -2
- package/vue/chunks/UiCombobox.js +29 -13
- package/vue/chunks/UiContextMenu.js +6 -2
- package/vue/chunks/UiDialog.js +25 -8
- package/vue/chunks/UiDisclosure.js +36 -12
- package/vue/chunks/UiEditable.js +22 -8
- package/vue/chunks/UiEditorInsertTableGrid.js +11 -14
- package/vue/chunks/UiEditorMentionMenu.js +30 -19
- package/vue/chunks/UiEditorMentionMenuItem.js +36 -0
- package/vue/chunks/UiEditorSlashMenu.js +33 -35
- package/vue/chunks/UiEditorSlashMenuGroup.js +26 -0
- package/vue/chunks/UiEditorSlashMenuItem.js +51 -0
- package/vue/chunks/UiEditorTableContextMenu.js +39 -5
- package/vue/chunks/UiEditorTableOverlay.js +6 -6
- package/vue/chunks/UiEditorTableToolbar.js +37 -4
- package/vue/chunks/UiEditorToolbar.js +18 -4
- package/vue/chunks/UiFloatingActionButton.js +1 -1
- package/vue/chunks/UiFormField.js +13 -9
- package/vue/chunks/UiGrid.js +6 -2
- package/vue/chunks/UiIcon.js +40 -2
- package/vue/chunks/UiIconButton.js +35 -4
- package/vue/chunks/UiInput.js +1 -1
- package/vue/chunks/UiInputGroup.js +1 -1
- package/vue/chunks/UiListbox.js +70 -0
- package/vue/chunks/UiMenu.js +6 -2
- package/vue/chunks/UiMenuGroup.js +25 -0
- package/vue/chunks/UiMenuItem.js +128 -7
- package/vue/chunks/UiPopover.js +1 -1
- package/vue/chunks/UiRadioGroup.js +8 -2
- package/vue/chunks/UiSearchShell.js +1 -1
- package/vue/chunks/UiSelect.js +1 -1
- package/vue/chunks/UiSwitch.js +1 -1
- package/vue/chunks/UiSwitcher.js +20 -3
- package/vue/chunks/UiTabs.js +4 -3
- package/vue/chunks/UiTextarea.js +7 -2
- package/vue/chunks/UiToast.js +81 -0
- package/vue/chunks/UiToastRegion.js +25 -49
- package/vue/chunks/UiTooltip.js +3 -7
- package/vue/chunks/UiTree.js +8 -4
- package/vue/chunks/UiTreeItem.js +28 -10
- package/vue/components.css +1840 -851
- package/vue/editor/index.js +263 -2
- package/vue/index.d.ts +6 -0
- package/vue/index.js +9 -3
|
@@ -29,10 +29,19 @@ export default function controller(host) {
|
|
|
29
29
|
let tabStop = null;
|
|
30
30
|
let hoverTimer = null;
|
|
31
31
|
let hoverKey = null;
|
|
32
|
+
let typed = "";
|
|
33
|
+
let lastTyped = 0;
|
|
34
|
+
let moveMode = false;
|
|
35
|
+
const announcer = document.createElement("span");
|
|
36
|
+
announcer.setAttribute("role", "status");
|
|
37
|
+
announcer.style.cssText = "position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap";
|
|
38
|
+
document.body.append(announcer);
|
|
39
|
+
const announce = (message) => { announcer.textContent = message; };
|
|
32
40
|
|
|
33
41
|
const allItems = () => Array.from(element.querySelectorAll(itemSelector));
|
|
34
42
|
const visibleItems = () => allItems().filter((item) => item.getClientRects().length > 0 && item.getAttribute("aria-disabled") !== "true");
|
|
35
43
|
const rowFor = (item) => item.querySelector(":scope > .row");
|
|
44
|
+
const selectionMode = () => String(host.state.selection || "none");
|
|
36
45
|
// Only a branch has aria-expanded.
|
|
37
46
|
const acceptsChildren = (item) => item.hasAttribute("aria-expanded") && item.getAttribute("aria-disabled") !== "true";
|
|
38
47
|
const metadata = (item) => ({
|
|
@@ -91,6 +100,8 @@ export default function controller(host) {
|
|
|
91
100
|
cancelHover();
|
|
92
101
|
};
|
|
93
102
|
const finish = () => {
|
|
103
|
+
moveMode = false;
|
|
104
|
+
element.removeAttribute("data-move-mode");
|
|
94
105
|
source?.removeAttribute("data-dragging");
|
|
95
106
|
source = null;
|
|
96
107
|
clearTarget();
|
|
@@ -100,15 +111,12 @@ export default function controller(host) {
|
|
|
100
111
|
};
|
|
101
112
|
const itemFromEvent = (event) => event.composedPath().find((node) => node instanceof HTMLElement && node.matches?.(itemSelector)) ?? null;
|
|
102
113
|
const itemAtPoint = (x, y) => document.elementFromPoint(x, y)?.closest?.(itemSelector) ?? null;
|
|
103
|
-
const
|
|
114
|
+
const chooseTarget = (nextTarget, nextPosition, transfer) => {
|
|
104
115
|
if (!source || !nextTarget || nextTarget === source) {
|
|
105
116
|
clearTarget();
|
|
106
117
|
rejection = rejectedTarget = rejectedPosition = null;
|
|
107
118
|
return false;
|
|
108
119
|
}
|
|
109
|
-
const row = rowFor(nextTarget);
|
|
110
|
-
if (!row) return false;
|
|
111
|
-
const nextPosition = classify(row.getBoundingClientRect(), y, acceptsChildren(nextTarget));
|
|
112
120
|
const nextRejection = rejected(source, nextTarget, nextPosition);
|
|
113
121
|
if (nextRejection) {
|
|
114
122
|
if (transfer) transfer.dropEffect = "none";
|
|
@@ -132,21 +140,126 @@ export default function controller(host) {
|
|
|
132
140
|
else cancelHover();
|
|
133
141
|
return true;
|
|
134
142
|
};
|
|
135
|
-
const
|
|
143
|
+
const updateTarget = (nextTarget, y, transfer) => {
|
|
144
|
+
const row = nextTarget && rowFor(nextTarget);
|
|
145
|
+
return row ? chooseTarget(nextTarget, classify(row.getBoundingClientRect(), y, acceptsChildren(nextTarget)), transfer) : false;
|
|
146
|
+
};
|
|
147
|
+
const dispatchReorder = (from, to, nextPosition, how = "pointer") => {
|
|
136
148
|
const sourceId = itemId(from);
|
|
137
149
|
const targetId = itemId(to);
|
|
138
150
|
if (!sourceId || !targetId) return;
|
|
139
151
|
if (nextPosition === "inside") expandTarget(targetId);
|
|
140
152
|
const fromMeta = metadata(from);
|
|
141
153
|
const toMeta = metadata(to);
|
|
142
|
-
host.dispatch("reorder", { sourceId, targetId, position: nextPosition, sourceType: fromMeta.type, targetType: toMeta.type, sourceScope: fromMeta.scope, targetScope: toMeta.scope, trigger:
|
|
154
|
+
host.dispatch("reorder", { sourceId, targetId, position: nextPosition, sourceType: fromMeta.type, targetType: toMeta.type, sourceScope: fromMeta.scope, targetScope: toMeta.scope, trigger: how });
|
|
143
155
|
};
|
|
144
|
-
const dispatchRejected = (from, to, nextPosition, detail) => {
|
|
156
|
+
const dispatchRejected = (from, to, nextPosition, detail, how = "pointer") => {
|
|
145
157
|
const sourceId = itemId(from);
|
|
146
158
|
const targetId = itemId(to);
|
|
147
|
-
if (sourceId && targetId) host.dispatch("reorder-rejected", { sourceId, targetId, position: nextPosition, reason: "max-depth", maxDepth: detail.maxDepth, resultingDepth: detail.resultingDepth, trigger:
|
|
159
|
+
if (sourceId && targetId) host.dispatch("reorder-rejected", { sourceId, targetId, position: nextPosition, reason: "max-depth", maxDepth: detail.maxDepth, resultingDepth: detail.resultingDepth, trigger: how });
|
|
160
|
+
};
|
|
161
|
+
const nameOf = (item) => item.getAttribute("aria-label") || itemId(item) || "item";
|
|
162
|
+
const beginMove = (item) => {
|
|
163
|
+
if (!itemId(item) || item.getAttribute("aria-disabled") === "true") return;
|
|
164
|
+
finish();
|
|
165
|
+
moveMode = true;
|
|
166
|
+
source = item;
|
|
167
|
+
source.setAttribute("data-dragging", "true");
|
|
168
|
+
element.setAttribute("data-move-mode", "");
|
|
169
|
+
announce(`Moving ${nameOf(item)}. Choose a destination by click or the arrow keys. Press Enter to place or Escape to cancel.`);
|
|
170
|
+
};
|
|
171
|
+
const commitMove = (how) => {
|
|
172
|
+
if (!source) return;
|
|
173
|
+
if (target && position) {
|
|
174
|
+
const message = `Move requested: ${nameOf(source)} ${position} ${nameOf(target)}.`;
|
|
175
|
+
dispatchReorder(source, target, position, how);
|
|
176
|
+
finish();
|
|
177
|
+
announce(message);
|
|
178
|
+
} else if (rejection && rejectedTarget && rejectedPosition) {
|
|
179
|
+
dispatchRejected(source, rejectedTarget, rejectedPosition, rejection, how);
|
|
180
|
+
finish();
|
|
181
|
+
announce(`Cannot move ${nameOf(source)} there: maximum depth exceeded.`);
|
|
182
|
+
} else announce("Choose another destination row.");
|
|
183
|
+
};
|
|
184
|
+
const onMoveClick = (event) => {
|
|
185
|
+
const handle = event.composedPath().find((node) => node instanceof HTMLElement && node.classList.contains("drag-handle"));
|
|
186
|
+
if (handle) {
|
|
187
|
+
event.preventDefault();
|
|
188
|
+
event.stopPropagation();
|
|
189
|
+
const item = itemFromEvent(event);
|
|
190
|
+
if (item) beginMove(item);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (!moveMode) {
|
|
194
|
+
if (selectionMode() === "none") return;
|
|
195
|
+
const item = itemFromEvent(event);
|
|
196
|
+
if (!item || item.getAttribute("aria-disabled") === "true") return;
|
|
197
|
+
const path = event.composedPath();
|
|
198
|
+
const checkbox = path.some((node) => node instanceof HTMLElement && node.classList.contains("selection-checkbox"));
|
|
199
|
+
const control = path.some((node) => node instanceof HTMLElement && node !== item && node.matches?.('a, button, input, select, textarea, [role="button"], [role="link"]'));
|
|
200
|
+
if (control && !checkbox) return;
|
|
201
|
+
event.preventDefault();
|
|
202
|
+
event.stopPropagation();
|
|
203
|
+
selectItem(item, "pointer");
|
|
204
|
+
focusItem(item);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const item = itemFromEvent(event);
|
|
208
|
+
if (!item) return;
|
|
209
|
+
event.preventDefault();
|
|
210
|
+
event.stopPropagation();
|
|
211
|
+
if (updateTarget(item, event.clientY)) commitMove("pointer");
|
|
212
|
+
else if (rejection) commitMove("pointer");
|
|
213
|
+
else announce("Choose another destination row.");
|
|
214
|
+
};
|
|
215
|
+
const onMovePointer = (event) => {
|
|
216
|
+
if (!moveMode) return;
|
|
217
|
+
const item = itemFromEvent(event);
|
|
218
|
+
if (item && item !== source) updateTarget(item, event.clientY);
|
|
219
|
+
};
|
|
220
|
+
const onMoveKeydown = (event) => {
|
|
221
|
+
if (!moveMode) return false;
|
|
222
|
+
if (event.key === "Escape") {
|
|
223
|
+
event.preventDefault();
|
|
224
|
+
finish();
|
|
225
|
+
announce("Move cancelled.");
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
229
|
+
event.preventDefault();
|
|
230
|
+
commitMove("keyboard");
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
if (event.key === "ArrowRight" && target) {
|
|
234
|
+
event.preventDefault();
|
|
235
|
+
if (chooseTarget(target, "inside")) announce(`Move ${nameOf(source)} inside ${nameOf(target)}.`);
|
|
236
|
+
else announce("That item cannot contain this one.");
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
if (event.key === "ArrowLeft" && target) {
|
|
240
|
+
event.preventDefault();
|
|
241
|
+
const side = allItems().indexOf(target) < allItems().indexOf(source) ? "before" : "after";
|
|
242
|
+
if (chooseTarget(target, side)) announce(`Move ${nameOf(source)} ${side} ${nameOf(target)}.`);
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return false;
|
|
246
|
+
event.preventDefault();
|
|
247
|
+
const items = visibleItems();
|
|
248
|
+
const step = event.key === "ArrowDown" ? 1 : -1;
|
|
249
|
+
let index = items.indexOf(target ?? source);
|
|
250
|
+
while (index + step >= 0 && index + step < items.length) {
|
|
251
|
+
index += step;
|
|
252
|
+
const candidate = items[index];
|
|
253
|
+
const side = step < 0 ? "before" : "after";
|
|
254
|
+
if (candidate !== source && chooseTarget(candidate, side)) {
|
|
255
|
+
announce(`Move ${nameOf(source)} ${side} ${nameOf(candidate)}. Press Enter to place.`);
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return true;
|
|
148
260
|
};
|
|
149
261
|
const onDragStart = (event) => {
|
|
262
|
+
if (moveMode) finish();
|
|
150
263
|
const item = itemFromEvent(event);
|
|
151
264
|
// An item renders its drag handle only while it is sortable and enabled.
|
|
152
265
|
const fromHandle = event.composedPath().some((node) => node instanceof HTMLElement && node.classList.contains("drag-handle"));
|
|
@@ -204,9 +317,52 @@ export default function controller(host) {
|
|
|
204
317
|
tabStop = next;
|
|
205
318
|
for (const item of items) item.dispatchEvent(new CustomEvent("ui-tree-roving-tab-stop", { detail: { active: item === next } }));
|
|
206
319
|
};
|
|
320
|
+
const syncSelection = () => {
|
|
321
|
+
const mode = selectionMode();
|
|
322
|
+
if (mode === "multiple") element.setAttribute("aria-multiselectable", "true");
|
|
323
|
+
else element.removeAttribute("aria-multiselectable");
|
|
324
|
+
for (const item of allItems()) {
|
|
325
|
+
if (mode === "multiple") item.setAttribute("data-selection-mode", "multiple");
|
|
326
|
+
else item.removeAttribute("data-selection-mode");
|
|
327
|
+
const checkbox = rowFor(item)?.querySelector(".selection-checkbox");
|
|
328
|
+
if (checkbox) {
|
|
329
|
+
const descendants = Array.from(item.querySelectorAll(itemSelector));
|
|
330
|
+
checkbox.indeterminate = mode === "multiple" && descendants.some((child) => child.getAttribute("aria-selected") === "true")
|
|
331
|
+
&& (item.getAttribute("aria-selected") !== "true" || descendants.some((child) => child.getAttribute("aria-selected") !== "true"));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
const selectItem = (item, how) => {
|
|
336
|
+
const mode = selectionMode();
|
|
337
|
+
const id = itemId(item);
|
|
338
|
+
if (mode === "none" || !id) return;
|
|
339
|
+
if (mode === "single") {
|
|
340
|
+
if (item.getAttribute("aria-selected") !== "true") host.dispatch("select", { ids: [id], trigger: how });
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const items = allItems();
|
|
344
|
+
const selected = new Set(items.filter((candidate) => candidate.getAttribute("aria-selected") === "true").map(itemId).filter(Boolean));
|
|
345
|
+
const subtree = [item, ...item.querySelectorAll(itemSelector)].filter((candidate) => candidate.getAttribute("aria-disabled") !== "true");
|
|
346
|
+
const adding = !selected.has(id);
|
|
347
|
+
for (const candidate of subtree) {
|
|
348
|
+
const candidateId = itemId(candidate);
|
|
349
|
+
if (!candidateId) continue;
|
|
350
|
+
if (adding) selected.add(candidateId);
|
|
351
|
+
else selected.delete(candidateId);
|
|
352
|
+
}
|
|
353
|
+
let ancestor = parentItem(item, element);
|
|
354
|
+
while (ancestor) {
|
|
355
|
+
const children = items.filter((candidate) => parentItem(candidate, element) === ancestor);
|
|
356
|
+
if (children.length && children.every((child) => selected.has(itemId(child)))) selected.add(itemId(ancestor));
|
|
357
|
+
else selected.delete(itemId(ancestor));
|
|
358
|
+
ancestor = parentItem(ancestor, element);
|
|
359
|
+
}
|
|
360
|
+
host.dispatch("select", { ids: items.map(itemId).filter((candidate) => candidate && selected.has(candidate)), trigger: how });
|
|
361
|
+
};
|
|
207
362
|
const syncStructure = () => {
|
|
208
363
|
for (const item of allItems()) item.dispatchEvent(new CustomEvent("ui-tree-structure-sync"));
|
|
209
364
|
syncTabStop();
|
|
365
|
+
syncSelection();
|
|
210
366
|
};
|
|
211
367
|
const interactive = (event) => {
|
|
212
368
|
for (const node of event.composedPath()) {
|
|
@@ -219,9 +375,15 @@ export default function controller(host) {
|
|
|
219
375
|
const onFocusin = (event) => { if (!interactive(event)) { const item = itemFromEvent(event); if (item) syncTabStop(item); } };
|
|
220
376
|
const onExpansion = () => requestAnimationFrame(() => syncTabStop());
|
|
221
377
|
const onKeydown = (event) => {
|
|
378
|
+
if (onMoveKeydown(event)) return;
|
|
222
379
|
if (interactive(event)) return;
|
|
223
380
|
const current = itemFromEvent(event);
|
|
224
381
|
if (!current) return;
|
|
382
|
+
if (event.key === " " && selectionMode() !== "none") {
|
|
383
|
+
event.preventDefault();
|
|
384
|
+
selectItem(current, "keyboard");
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
225
387
|
const items = visibleItems();
|
|
226
388
|
const index = items.indexOf(current);
|
|
227
389
|
if (index < 0) return;
|
|
@@ -234,17 +396,34 @@ export default function controller(host) {
|
|
|
234
396
|
if (current.getAttribute("aria-expanded") === "false") { event.preventDefault(); current.dispatchEvent(new CustomEvent("ui-tree-request-expanded", { detail: { expanded: true, trigger: "keyboard" } })); }
|
|
235
397
|
else if (current.getAttribute("aria-expanded") === "true") { const child = items.find((item) => parentItem(item, element) === current); if (child) { event.preventDefault(); focusItem(child); } }
|
|
236
398
|
}
|
|
399
|
+
if (event.key.length === 1 && /^[\p{L}\p{N}]$/u.test(event.key) && !event.altKey && !event.ctrlKey && !event.metaKey) {
|
|
400
|
+
const now = Date.now();
|
|
401
|
+
typed = `${now - lastTyped < 700 ? typed : ""}${event.key.toLocaleLowerCase()}`;
|
|
402
|
+
lastTyped = now;
|
|
403
|
+
const candidates = [...items.slice(index + 1), ...items.slice(0, index + 1)];
|
|
404
|
+
const match = candidates.find((item) => (item.getAttribute("aria-label") || item.textContent || "").trim().toLocaleLowerCase().startsWith(typed));
|
|
405
|
+
if (match) { event.preventDefault(); focusItem(match); }
|
|
406
|
+
}
|
|
237
407
|
};
|
|
238
|
-
const listeners = { dragstart: onDragStart, drag: onDrag, dragenter: onDragOver, dragover: onDragOver, dragleave: onDragLeave, drop: onDrop, dragend: onDragEnd, keydown: onKeydown, focusin: onFocusin, "ui-tree-expansion-change": onExpansion };
|
|
408
|
+
const listeners = { dragstart: onDragStart, drag: onDrag, dragenter: onDragOver, dragover: onDragOver, dragleave: onDragLeave, drop: onDrop, dragend: onDragEnd, keydown: onKeydown, focusin: onFocusin, pointermove: onMovePointer, "ui-tree-expansion-change": onExpansion };
|
|
239
409
|
for (const [name, listener] of Object.entries(listeners)) element.addEventListener(name, listener);
|
|
240
|
-
|
|
241
|
-
observer
|
|
242
|
-
|
|
410
|
+
element.addEventListener("click", onMoveClick, true);
|
|
411
|
+
const observer = new MutationObserver((records) => {
|
|
412
|
+
if (records.some((record) => record.type === "childList")) syncStructure();
|
|
413
|
+
else syncSelection();
|
|
414
|
+
});
|
|
415
|
+
observer.observe(element, { childList: true, subtree: true, attributes: true, attributeFilter: ["aria-selected"] });
|
|
416
|
+
const stop = host.effect(() => {
|
|
417
|
+
element.setAttribute("aria-label", String(host.state.label || "Tree"));
|
|
418
|
+
syncSelection();
|
|
419
|
+
});
|
|
243
420
|
syncStructure();
|
|
244
421
|
return () => {
|
|
245
422
|
stop();
|
|
246
423
|
observer.disconnect();
|
|
247
424
|
cancelHover();
|
|
425
|
+
announcer.remove();
|
|
248
426
|
for (const [name, listener] of Object.entries(listeners)) element.removeEventListener(name, listener);
|
|
427
|
+
element.removeEventListener("click", onMoveClick, true);
|
|
249
428
|
};
|
|
250
429
|
}
|
|
@@ -13,9 +13,12 @@
|
|
|
13
13
|
<prop name="container" type="boolean" default="false"
|
|
14
14
|
>Makes the item a branch even before it has children: it gets the expand button and aria-expanded, and accepts drops inside it. An item with nested items is
|
|
15
15
|
a branch without it.</prop>
|
|
16
|
+
<prop name="lazy" type="boolean" default="false"
|
|
17
|
+
>Keeps an empty item expandable while its children are supplied later. Expanding emits expand; the item is aria-busy until child Tree Items are appended.
|
|
18
|
+
Clear lazy if loading finishes with no children.</prop>
|
|
16
19
|
<prop name="sortable" type="boolean" default="false"
|
|
17
|
-
>Gives the item a
|
|
18
|
-
|
|
20
|
+
>Gives the item a move handle. Drag it, or activate it and choose a target by a second click or the keyboard. The tree reports reorder and leaves moving the
|
|
21
|
+
item to you. Needs itemId; disabled items show no handle.</prop>
|
|
19
22
|
<prop name="dragType" type="string" default="item"
|
|
20
23
|
>The item's kind, for drag rules: it can be dropped before or after only items of the same type, and inside a branch only if that branch's accepts allows
|
|
21
24
|
it. Reported as sourceType and targetType.</prop>
|
|
@@ -29,8 +32,8 @@
|
|
|
29
32
|
>Whether the branch shows its children, initially or when set externally. The expand button, a click on the row, and the arrow keys toggle it from there,
|
|
30
33
|
each reported as an expand event. Only meaningful for a branch.</prop>
|
|
31
34
|
<prop name="selected" type="boolean" default="false"
|
|
32
|
-
>Marks the item selected: it sets aria-selected and
|
|
33
|
-
|
|
35
|
+
>Marks the item selected: it sets aria-selected and highlights the row. This is controlled state; respond to the parent Tree's select request by updating
|
|
36
|
+
it.</prop>
|
|
34
37
|
<prop name="marquee" type="boolean" default="false"
|
|
35
38
|
>Scrolls a name too long for its row while the row is hovered or focused, then puts it back. Off by default: a tree of short names should not move, and a
|
|
36
39
|
product decides whether reading the whole name matters more than a still list.</prop>
|
|
@@ -85,6 +88,14 @@
|
|
|
85
88
|
<button class="disclosure" $ref="disclosure" type="button" :disabled="disabled" :hidden="not isContainer">
|
|
86
89
|
<span class="disclosure-icon" aria-hidden="true"></span>
|
|
87
90
|
</button>
|
|
91
|
+
<label class="selection-hit"><input
|
|
92
|
+
class="selection-checkbox"
|
|
93
|
+
type="checkbox"
|
|
94
|
+
tabindex="-1"
|
|
95
|
+
:checked="selected"
|
|
96
|
+
:disabled="disabled"
|
|
97
|
+
:aria-label="format('Select %s', label)"
|
|
98
|
+
></label>
|
|
88
99
|
<span class="leading" $ref="leading"><slot name="leading"></slot></span>
|
|
89
100
|
<span class="label" $ref="label"><span class="label-text" $ref="labelText"><slot name="label"><template $value="label"></template></slot></span></span>
|
|
90
101
|
<span class="actions" $ref="actions"><slot name="actions"></slot></span>
|
|
@@ -204,6 +215,35 @@
|
|
|
204
215
|
display: none;
|
|
205
216
|
}
|
|
206
217
|
|
|
218
|
+
.selection-hit {
|
|
219
|
+
display: none;
|
|
220
|
+
grid-column: 2;
|
|
221
|
+
grid-row: 1;
|
|
222
|
+
place-items: center;
|
|
223
|
+
inline-size: 1.25rem;
|
|
224
|
+
block-size: var(--_ui-tree-item-min-block-size, var(--_tree-row-min-height));
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
}
|
|
227
|
+
.selection-checkbox {
|
|
228
|
+
inline-size: 1rem;
|
|
229
|
+
block-size: 1rem;
|
|
230
|
+
margin: 0;
|
|
231
|
+
accent-color: var(--ui-accent-solid);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
:host[data-selection-mode="multiple"] > .row {
|
|
235
|
+
grid-template-columns: var(--_tree-disclosure-size) 1.25rem auto minmax(0, 1fr);
|
|
236
|
+
}
|
|
237
|
+
:host[data-selection-mode="multiple"] > .row > .selection-hit {
|
|
238
|
+
display: grid;
|
|
239
|
+
}
|
|
240
|
+
:host[data-selection-mode="multiple"] > .row > .leading {
|
|
241
|
+
grid-column: 3;
|
|
242
|
+
}
|
|
243
|
+
:host[data-selection-mode="multiple"] > .row > .label {
|
|
244
|
+
grid-column: 4;
|
|
245
|
+
}
|
|
246
|
+
|
|
207
247
|
.disclosure:hover {
|
|
208
248
|
color: var(--ui-text-primary);
|
|
209
249
|
background: var(--ui-surface-elevated);
|
|
@@ -472,7 +512,7 @@
|
|
|
472
512
|
inset-inline: 1px;
|
|
473
513
|
display: none;
|
|
474
514
|
block-size: 2px;
|
|
475
|
-
border-radius:
|
|
515
|
+
border-radius: var(--ui-radius-round);
|
|
476
516
|
background: var(--_ui-tree-drop-color, var(--ui-accent-solid));
|
|
477
517
|
pointer-events: none;
|
|
478
518
|
}
|
|
@@ -485,7 +525,7 @@
|
|
|
485
525
|
inline-size: 7px;
|
|
486
526
|
block-size: 7px;
|
|
487
527
|
border: 2px solid var(--_ui-tree-drop-color, var(--ui-accent-solid));
|
|
488
|
-
border-radius:
|
|
528
|
+
border-radius: var(--ui-radius-round);
|
|
489
529
|
background: var(--ui-surface-elevated);
|
|
490
530
|
transform: translateY(-50%);
|
|
491
531
|
}
|
|
@@ -515,8 +555,47 @@
|
|
|
515
555
|
--_tree-row-min-height: 44px;
|
|
516
556
|
}
|
|
517
557
|
|
|
518
|
-
html[data-ui-input-modality="touch"] :host .
|
|
519
|
-
|
|
558
|
+
html[data-ui-input-modality="touch"] :host .row {
|
|
559
|
+
grid-template-columns: 44px var(--_tree-disclosure-size) auto minmax(0, 1fr);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
html[data-ui-input-modality="touch"] :host .drag-handle,
|
|
563
|
+
html[data-ui-input-modality="touch"] :host-state([isContainer]) > .row > .drag-handle {
|
|
564
|
+
position: relative;
|
|
565
|
+
grid-column: 1;
|
|
566
|
+
grid-row: 1;
|
|
567
|
+
inset: auto;
|
|
568
|
+
inline-size: 44px;
|
|
569
|
+
block-size: 44px;
|
|
570
|
+
padding: 14px;
|
|
571
|
+
opacity: 1;
|
|
572
|
+
transform: none;
|
|
573
|
+
cursor: pointer;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
html[data-ui-input-modality="touch"] :host .disclosure {
|
|
577
|
+
grid-column: 2;
|
|
578
|
+
}
|
|
579
|
+
html[data-ui-input-modality="touch"] :host .leading {
|
|
580
|
+
grid-column: 3;
|
|
581
|
+
}
|
|
582
|
+
html[data-ui-input-modality="touch"] :host .label {
|
|
583
|
+
grid-column: 4;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
html[data-ui-input-modality="touch"] :host[data-selection-mode="multiple"] > .row {
|
|
587
|
+
grid-template-columns: 44px var(--_tree-disclosure-size) 44px auto minmax(0, 1fr);
|
|
588
|
+
}
|
|
589
|
+
html[data-ui-input-modality="touch"] :host[data-selection-mode="multiple"] > .row > .selection-hit {
|
|
590
|
+
grid-column: 3;
|
|
591
|
+
inline-size: 44px;
|
|
592
|
+
block-size: 44px;
|
|
593
|
+
}
|
|
594
|
+
html[data-ui-input-modality="touch"] :host[data-selection-mode="multiple"] > .row > .leading {
|
|
595
|
+
grid-column: 4;
|
|
596
|
+
}
|
|
597
|
+
html[data-ui-input-modality="touch"] :host[data-selection-mode="multiple"] > .row > .label {
|
|
598
|
+
grid-column: 5;
|
|
520
599
|
}
|
|
521
600
|
|
|
522
601
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -27,7 +27,7 @@ export default function controller(host) {
|
|
|
27
27
|
let lastExternalExpanded = Boolean(host.state.expanded);
|
|
28
28
|
host.state.internalExpanded = lastExternalExpanded;
|
|
29
29
|
|
|
30
|
-
const isContainer = () => Boolean(host.state.container) || childItems().length > 0;
|
|
30
|
+
const isContainer = () => Boolean(host.state.container) || Boolean(host.state.lazy) || childItems().length > 0;
|
|
31
31
|
const updateLevel = () => {
|
|
32
32
|
const tree = element.closest('[role="tree"]');
|
|
33
33
|
let ancestor = parentItem(element);
|
|
@@ -52,6 +52,8 @@ export default function controller(host) {
|
|
|
52
52
|
// A leaf has no aria-expanded at all; "false" would announce it as a collapsed branch.
|
|
53
53
|
if (container) element.setAttribute("aria-expanded", String(expanded));
|
|
54
54
|
else element.removeAttribute("aria-expanded");
|
|
55
|
+
if (host.state.lazy && expanded && childItems().length === 0) element.setAttribute("aria-busy", "true");
|
|
56
|
+
else element.removeAttribute("aria-busy");
|
|
55
57
|
element.tabIndex = host.state.disabled || !host.state.tabStop ? -1 : 0;
|
|
56
58
|
element.style.setProperty("--ui-tree-item-depth", String(Number(host.state.structuralLevel ?? 1) - 1));
|
|
57
59
|
disclosure.setAttribute("aria-expanded", String(expanded));
|