luxen-ui 0.9.1 → 0.9.3
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/cdn/custom-elements.json +27 -2
- package/cdn/elements/dropdown-item/dropdown-item.js +1 -1
- package/cdn/elements/dropdown-item/dropdown-item.js.map +1 -1
- package/cdn/elements/tree/tree.d.ts +11 -1
- package/cdn/elements/tree/tree.d.ts.map +1 -1
- package/cdn/elements/tree/tree.js +1 -3
- package/cdn/elements/tree/tree.js.map +1 -1
- package/cdn/elements/tree-item/tree-item.d.ts +17 -1
- package/cdn/elements/tree-item/tree-item.d.ts.map +1 -1
- package/cdn/elements/tree-item/tree-item.js +2 -1
- package/cdn/elements/tree-item/tree-item.js.map +1 -1
- package/cdn/standalone.js +65 -17
- package/cdn/standalone.js.map +1 -1
- package/dist/custom-elements.json +27 -2
- package/dist/elements/dropdown-item/dropdown-item.css +1 -0
- package/dist/elements/tree/tree.d.ts +11 -1
- package/dist/elements/tree/tree.d.ts.map +1 -1
- package/dist/elements/tree/tree.js +37 -11
- package/dist/elements/tree-item/tree-item.css +7 -1
- package/dist/elements/tree-item/tree-item.d.ts +17 -1
- package/dist/elements/tree-item/tree-item.d.ts.map +1 -1
- package/dist/elements/tree-item/tree-item.js +51 -10
- package/dist/metadata/index.json +22 -3
- package/dist/metadata/tree-item.json +20 -1
- package/dist/metadata/tree.json +1 -1
- package/dist/templates/elements/tree.md +18 -0
- package/package.json +4 -2
package/cdn/standalone.js
CHANGED
|
@@ -5081,7 +5081,7 @@ __decorate([n$1({ attribute: "min-width" })], Dropdown.prototype, "minWidth", nu
|
|
|
5081
5081
|
define("dropdown", Dropdown);
|
|
5082
5082
|
//#endregion
|
|
5083
5083
|
//#region src/html/elements/dropdown-item/dropdown-item.ts
|
|
5084
|
-
var styles$10 = r$6(":host {\n display: block;\n}\n\n:host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0.375rem 0.5rem;\n cursor: pointer;\n outline: none;\n border-radius: 4px;\n font-size: 0.875rem;\n line-height: 1.5;\n color: var(--l-color-text-primary, CanvasText);\n white-space: nowrap;\n}\n\n.item:focus-visible {\n background: var(--l-color-bg-state-hover);\n}\n\n@media (hover: hover) {\n .item:hover {\n background: var(--l-color-bg-state-hover);\n }\n}\n\n.check {\n display: flex;\n width: 16px;\n flex-shrink: 0;\n}\n\n:host(:not([checked])) .check svg {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n display: flex;\n flex-shrink: 0;\n}\n\n.label {\n flex: 1;\n}\n");
|
|
5084
|
+
var styles$10 = r$6(":host {\n display: block;\n}\n\n:host([disabled]) {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 0.375rem 0.5rem;\n cursor: pointer;\n outline: none;\n border-radius: 4px;\n font-size: 0.875rem;\n line-height: 1.5;\n color: var(--l-color-text-primary, CanvasText);\n white-space: nowrap;\n text-align: start;\n}\n\n.item:focus-visible {\n background: var(--l-color-bg-state-hover);\n}\n\n@media (hover: hover) {\n .item:hover {\n background: var(--l-color-bg-state-hover);\n }\n}\n\n.check {\n display: flex;\n width: 16px;\n flex-shrink: 0;\n}\n\n:host(:not([checked])) .check svg {\n visibility: hidden;\n}\n\n::slotted([slot='prefix']),\n::slotted([slot='suffix']) {\n display: flex;\n flex-shrink: 0;\n}\n\n.label {\n flex: 1;\n}\n");
|
|
5085
5085
|
/**
|
|
5086
5086
|
* A menu item for use inside `<l-dropdown>`.
|
|
5087
5087
|
*
|
|
@@ -34538,6 +34538,9 @@ var styles$1 = r$6(":host {\n --indent-size: 1rem;\n --indent-guide-width: 1px
|
|
|
34538
34538
|
/**
|
|
34539
34539
|
* A hierarchical tree view composed of `<l-tree-item>` children.
|
|
34540
34540
|
*
|
|
34541
|
+
* The host carries `role="tree"`, so give it an accessible name with
|
|
34542
|
+
* `aria-label` or `aria-labelledby` (e.g. `<l-tree aria-label="Files">`).
|
|
34543
|
+
*
|
|
34541
34544
|
* @slot - One or more `l-tree-item` elements.
|
|
34542
34545
|
*
|
|
34543
34546
|
* @csspart base - The root tree container.
|
|
@@ -34558,6 +34561,7 @@ var styles$1 = r$6(":host {\n --indent-size: 1rem;\n --indent-guide-width: 1px
|
|
|
34558
34561
|
var Tree = class extends LuxenElement {
|
|
34559
34562
|
constructor(..._args) {
|
|
34560
34563
|
super(..._args);
|
|
34564
|
+
this._internals = this.attachInternals();
|
|
34561
34565
|
this._lastFocusedItem = null;
|
|
34562
34566
|
this.#_selection_accessor_storage = "single";
|
|
34563
34567
|
this.#_independent_accessor_storage = false;
|
|
@@ -34698,6 +34702,8 @@ var Tree = class extends LuxenElement {
|
|
|
34698
34702
|
}
|
|
34699
34703
|
connectedCallback() {
|
|
34700
34704
|
super.connectedCallback();
|
|
34705
|
+
this._internals.role = "tree";
|
|
34706
|
+
if (!this.hasAttribute("role")) this.setAttribute("role", "tree");
|
|
34701
34707
|
this._mutationObserver = new MutationObserver(() => this._syncAll());
|
|
34702
34708
|
this._mutationObserver.observe(this, {
|
|
34703
34709
|
childList: true,
|
|
@@ -34712,6 +34718,11 @@ var Tree = class extends LuxenElement {
|
|
|
34712
34718
|
this.removeEventListener("l-tree-item-toggle", this._onItemToggle);
|
|
34713
34719
|
}
|
|
34714
34720
|
updated(changed) {
|
|
34721
|
+
if (changed.has("selection")) {
|
|
34722
|
+
const multiselectable = this.selection === "multiple" ? "true" : "false";
|
|
34723
|
+
this._internals.ariaMultiSelectable = multiselectable;
|
|
34724
|
+
this.setAttribute("aria-multiselectable", multiselectable);
|
|
34725
|
+
}
|
|
34715
34726
|
if (changed.has("selection") || changed.has("independent")) this._syncAll();
|
|
34716
34727
|
}
|
|
34717
34728
|
/** Returns all items in document (flat) order, including nested ones. */
|
|
@@ -34740,14 +34751,24 @@ var Tree = class extends LuxenElement {
|
|
|
34740
34751
|
return;
|
|
34741
34752
|
}
|
|
34742
34753
|
const showCheckbox = this.selection === "multiple";
|
|
34743
|
-
|
|
34754
|
+
this._syncLevel(roots, 0, showCheckbox);
|
|
34744
34755
|
this._updateBranchStates();
|
|
34745
34756
|
this._ensureTabStop();
|
|
34746
34757
|
}
|
|
34747
|
-
|
|
34748
|
-
|
|
34749
|
-
|
|
34750
|
-
|
|
34758
|
+
/**
|
|
34759
|
+
* Sync depth, checkbox visibility and ARIA position for a sibling group, then
|
|
34760
|
+
* recurse. `aria-level`/`aria-setsize`/`aria-posinset` let screen readers
|
|
34761
|
+
* announce "level N, M of K" — valuable here because `lazy` items mean the
|
|
34762
|
+
* full set isn't always in the DOM (see WAI-ARIA Tree View pattern).
|
|
34763
|
+
*/
|
|
34764
|
+
_syncLevel(items, depth, showCheckbox) {
|
|
34765
|
+
const setSize = items.length;
|
|
34766
|
+
items.forEach((item, index) => {
|
|
34767
|
+
item.depth = depth;
|
|
34768
|
+
item.showCheckbox = showCheckbox && this._canShowCheckboxOn(item);
|
|
34769
|
+
item.setPosition(depth + 1, index + 1, setSize);
|
|
34770
|
+
this._syncLevel(item.getChildrenItems(), depth + 1, showCheckbox);
|
|
34771
|
+
});
|
|
34751
34772
|
}
|
|
34752
34773
|
_canShowCheckboxOn(_item) {
|
|
34753
34774
|
if (this.selection !== "multiple") return false;
|
|
@@ -34782,6 +34803,7 @@ var Tree = class extends LuxenElement {
|
|
|
34782
34803
|
switch (this.selection) {
|
|
34783
34804
|
case "single":
|
|
34784
34805
|
this._setSingleSelection(item);
|
|
34806
|
+
if (!item.isLeaf()) item.toggle();
|
|
34785
34807
|
break;
|
|
34786
34808
|
case "leaf":
|
|
34787
34809
|
if (item.isLeaf()) this._setSingleSelection(item);
|
|
@@ -34865,8 +34887,6 @@ var Tree = class extends LuxenElement {
|
|
|
34865
34887
|
<div
|
|
34866
34888
|
class="tree"
|
|
34867
34889
|
part="base"
|
|
34868
|
-
role="tree"
|
|
34869
|
-
aria-multiselectable=${this.selection === "multiple" ? "true" : "false"}
|
|
34870
34890
|
@click=${this._onClick}
|
|
34871
34891
|
@keydown=${this._onKeyDown}
|
|
34872
34892
|
@focusin=${this._onFocusIn}
|
|
@@ -34895,7 +34915,7 @@ define("tree", Tree);
|
|
|
34895
34915
|
var checkbox_appearance_styles_default = r$6("/* Shared checkbox appearance — the visual skin behind `.l-checkbox`.\n\n Colocated with its `checkbox-appearance.styles.ts` wrapper so Shadow-DOM\n elements that render their own native checkbox (e.g. `<l-tree-item>` in\n `selection=\"multiple\"`) can pull in the exact same look via `static styles`.\n The global light-DOM `checkbox.css` primitive `@import`s this file too, so\n both surfaces stay in sync. The global `.l-checkbox` class cannot pierce a\n shadow boundary, but the `--l-form-control-*` tokens this rule relies on DO\n inherit across shadow roots.\n\n The checkmark / indeterminate dash are drawn with a `background-image` SVG on\n the input itself — `::before`/`::after` do not paint on replaced elements\n like `<input>`. `background-image` can't read the host's `currentColor`, so\n the glyph color is baked white. This stays legible because the accent\n (`--l-form-control-activated-color`) is a stable color that does not invert\n between light and dark. Override `--checkmark` to swap the icon. */\n\n@layer components {\n .l-checkbox,\n :where(l-form-field:not([unstyled])) > input[type='checkbox']:not([role='switch']) {\n /* Public knobs */\n --size: var(--l-form-control-toggle-size);\n --accent: var(--l-form-control-activated-color);\n --checkmark: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>');\n --_dash: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2.5\" stroke-linecap=\"round\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/></svg>');\n\n box-sizing: border-box;\n flex: 0 0 auto;\n inline-size: var(--size);\n block-size: var(--size);\n margin: 0;\n padding: 0;\n appearance: none;\n border: var(--l-form-control-border-width) solid var(--l-form-control-border-color);\n border-radius: calc(var(--size) * 0.2);\n background-color: var(--l-form-control-background-color);\n background-repeat: no-repeat;\n background-position: center;\n background-size: 75%;\n vertical-align: middle;\n cursor: pointer;\n transition-property: background-color, border-color;\n transition-duration: 150ms;\n\n &:checked,\n &:indeterminate {\n border-color: var(--accent);\n background-color: var(--accent);\n }\n\n &:checked {\n background-image: var(--checkmark);\n }\n\n &:indeterminate {\n background-image: var(--_dash);\n }\n\n @media (hover: hover) {\n &:hover:not(:disabled) {\n border-color: var(--l-form-control-border-color-hover);\n }\n }\n\n &:focus-visible {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 2px;\n }\n\n /* Invalid: only after interaction (`:user-invalid`), or forced via\n `aria-invalid` (set by `l-form-field` / server-side validation).\n Overriding `--accent` makes a checked invalid box fill with the error\n color too (not just the border). */\n &:user-invalid,\n &[aria-invalid='true'] {\n --accent: var(--l-form-control-border-color-invalid);\n border-color: var(--l-form-control-border-color-invalid);\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .l-checkbox,\n :where(l-form-field:not([unstyled])) > input[type='checkbox']:not([role='switch']) {\n transition-duration: 0ms;\n }\n }\n}\n");
|
|
34896
34916
|
//#endregion
|
|
34897
34917
|
//#region src/html/elements/tree-item/tree-item.ts
|
|
34898
|
-
var styles = r$6(":host {\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-size: 0.875rem;\n line-height: 1.5;\n /* The host is the roving-tabindex focus target, but the visible ring is drawn\n on the inner `.item` row. Suppress the host's UA outline so it doesn't paint\n a second ring around the whole subtree (row + children). */\n outline: none;\n}\n\n:host([disabled]) {\n opacity: 0.4;\n}\n\n:host([disabled]) .item {\n cursor: not-allowed;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--item-gap);\n min-block-size: var(--row-height);\n padding-inline: var(--row-padding-inline);\n padding-inline-start: calc(var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline));\n border-radius: 0.375rem;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n transition:\n background-color 120ms ease,\n color 120ms ease;\n position: relative;\n}\n\n.item:focus-visible,\n:host(:focus-visible) .item {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 1px;\n}\n\n@media (hover: hover) {\n :host(:not([disabled])) .item:hover {\n background-color: var(--l-color-bg-state-hover);\n }\n}\n\n:host([selected]:not([disabled])) .item {\n background-color: var(--l-color-bg-state-selected);\n}\n\n.expand {\n inline-size: var(--chevron-size);\n block-size: var(--chevron-size);\n display: grid;\n place-items: center;\n flex: none;\n color: var(--l-color-text-secondary, CanvasText);\n border-radius: 3px;\n cursor: pointer;\n}\n\n/* Hide the DEFAULT fallback chevron SVG on a leaf — slotted content\n (user-provided icon, avatar, etc.) remains visible because it lives outside\n the slot in the DOM tree. The `.expand` span keeps its fixed --chevron-size\n so leaf rows stay aligned with branches. */\n\n:host(:not(:state(has-children)):not([lazy])) .expand > slot > svg {\n display: none;\n}\n\n.expand svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* The checkbox appearance comes from the shared `.l-checkbox` skin imported\n above; this rule only governs visibility. */\n\n:host(:not(:state(checkbox))) .checkbox {\n display: none;\n}\n\n.label {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n overflow:
|
|
34918
|
+
var styles = r$6(":host {\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-size: 0.875rem;\n line-height: 1.5;\n /* The host is the roving-tabindex focus target, but the visible ring is drawn\n on the inner `.item` row. Suppress the host's UA outline so it doesn't paint\n a second ring around the whole subtree (row + children). */\n outline: none;\n}\n\n:host([disabled]) {\n opacity: 0.4;\n}\n\n:host([disabled]) .item {\n cursor: not-allowed;\n}\n\n.item {\n display: flex;\n align-items: center;\n gap: var(--item-gap);\n min-block-size: var(--row-height);\n padding-inline: var(--row-padding-inline);\n padding-inline-start: calc(var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline));\n border-radius: 0.375rem;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n transition:\n background-color 120ms ease,\n color 120ms ease;\n position: relative;\n}\n\n.item:focus-visible,\n:host(:focus-visible) .item {\n outline: 2px solid var(--l-focus-ring);\n outline-offset: 1px;\n}\n\n@media (hover: hover) {\n :host(:not([disabled])) .item:hover {\n background-color: var(--l-color-bg-state-hover);\n }\n}\n\n:host([selected]:not([disabled])) .item {\n background-color: var(--l-color-bg-state-selected);\n}\n\n.expand {\n inline-size: var(--chevron-size);\n block-size: var(--chevron-size);\n display: grid;\n place-items: center;\n flex: none;\n color: var(--l-color-text-secondary, CanvasText);\n border-radius: 3px;\n cursor: pointer;\n}\n\n/* Hide the DEFAULT fallback chevron SVG on a leaf — slotted content\n (user-provided icon, avatar, etc.) remains visible because it lives outside\n the slot in the DOM tree. The `.expand` span keeps its fixed --chevron-size\n so leaf rows stay aligned with branches. */\n\n:host(:not(:state(has-children)):not([lazy])) .expand > slot > svg {\n display: none;\n}\n\n.expand svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* The checkbox appearance comes from the shared `.l-checkbox` skin imported\n above; this rule only governs visibility. */\n\n:host(:not(:state(checkbox))) .checkbox {\n display: none;\n}\n\n.label {\n flex: 1;\n min-inline-size: 0;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n /* `clip` (not `hidden`) so the label still truncates long text to an ellipsis\n while `overflow-clip-margin` lets a slotted interactive control's hover/focus\n decoration (a row-action button, an `<l-dropdown>` trigger) bleed past the\n row-height label box instead of being cut on its top/bottom/left edges. The\n margin is kept small so the bleed stays imperceptible for text. */\n overflow: clip;\n overflow-clip-margin: 0.375rem;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.label ::slotted(*) {\n min-inline-size: 0;\n}\n\n/* Wrapper around the content slot + children — anchor for the indent guide. */\n\n.branch {\n position: relative;\n}\n\n/* Content slot — block area between the row and the children.\n Aligned under the label text: same left offset as the row's label\n (depth indent + row padding + chevron + gap). Visible for leaves (no\n children) and for expanded branches; hidden when a branch is collapsed\n (mirrors the children visibility). */\n\n.content {\n display: block;\n padding-inline-start: calc(\n var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline) + var(--chevron-size) +\n var(--item-gap)\n );\n padding-inline-end: var(--row-padding-inline);\n}\n\n:host(:state(has-children):not([expanded])) .content {\n display: none;\n}\n\n.children {\n display: none;\n}\n\n:host([expanded]) .children {\n display: block;\n}\n\n/* Vertical indent guide — spans the content + children block, starting\n right below the row so it never overlaps the chevron/avatar.\n The guide's visual centre sits exactly on the parent chevron's centre. */\n\n.branch::before {\n content: '';\n position: absolute;\n inset-block: 0;\n inset-inline-start: calc(\n var(--indent-size) * var(--_depth, 0) + var(--row-padding-inline) + (var(--chevron-size) / 2) -\n (var(--indent-guide-width) / 2)\n );\n inline-size: 0;\n border-inline-start: var(--indent-guide-width) var(--indent-guide-style) var(--indent-guide-color);\n pointer-events: none;\n}\n\n/* Only render the guide for open branches that have children. */\n\n:host(:not([expanded])) .branch::before,\n:host(:not(:state(has-children))) .branch::before {\n display: none;\n}\n\n.spinner {\n inline-size: 0.875rem;\n block-size: 0.875rem;\n border-radius: 50%;\n border: 2px solid var(--l-color-border, currentColor);\n border-block-start-color: transparent;\n animation: spin 700ms linear infinite;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .spinner {\n animation: none;\n }\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n");
|
|
34899
34919
|
/**
|
|
34900
34920
|
* A node inside `<l-tree>`. Nested `<l-tree-item>` children become sub-nodes.
|
|
34901
34921
|
*
|
|
@@ -35015,6 +35035,17 @@ var TreeItem = class extends LuxenElement {
|
|
|
35015
35035
|
get depth() {
|
|
35016
35036
|
return this._depth;
|
|
35017
35037
|
}
|
|
35038
|
+
/**
|
|
35039
|
+
* Set by `<l-tree>`: ARIA position within the tree. `level` is 1-based depth,
|
|
35040
|
+
* `posInSet`/`setSize` describe the item's rank among its siblings. These let
|
|
35041
|
+
* screen readers announce "level 2, 3 of 5" even when `lazy` children keep the
|
|
35042
|
+
* full set out of the DOM.
|
|
35043
|
+
*/
|
|
35044
|
+
setPosition(level, posInSet, setSize) {
|
|
35045
|
+
this._aria("ariaLevel", "aria-level", String(level));
|
|
35046
|
+
this._aria("ariaPosInSet", "aria-posinset", String(posInSet));
|
|
35047
|
+
this._aria("ariaSetSize", "aria-setsize", String(setSize));
|
|
35048
|
+
}
|
|
35018
35049
|
/** Whether this item has nested tree-item children. */
|
|
35019
35050
|
get hasChildren() {
|
|
35020
35051
|
return this._hasChildren;
|
|
@@ -35037,6 +35068,7 @@ var TreeItem = class extends LuxenElement {
|
|
|
35037
35068
|
connectedCallback() {
|
|
35038
35069
|
super.connectedCallback();
|
|
35039
35070
|
this._internals.role = "treeitem";
|
|
35071
|
+
if (!this.hasAttribute("role")) this.setAttribute("role", "treeitem");
|
|
35040
35072
|
this._childObserver = new MutationObserver(() => this._syncChildren());
|
|
35041
35073
|
this._childObserver.observe(this, { childList: true });
|
|
35042
35074
|
this._syncChildren();
|
|
@@ -35047,11 +35079,28 @@ var TreeItem = class extends LuxenElement {
|
|
|
35047
35079
|
}
|
|
35048
35080
|
updated(changed) {
|
|
35049
35081
|
if (changed.has("expanded")) {
|
|
35050
|
-
this.
|
|
35082
|
+
this._reflectExpanded();
|
|
35083
|
+
if (this.expanded && this.lazy) this.emit("lazy-load");
|
|
35051
35084
|
this.emit(this.expanded ? "expand" : "collapse");
|
|
35052
35085
|
}
|
|
35053
|
-
if (changed.has("selected")) this.
|
|
35054
|
-
if (changed.has("disabled")) this.
|
|
35086
|
+
if (changed.has("selected")) this._aria("ariaSelected", "aria-selected", String(this.selected));
|
|
35087
|
+
if (changed.has("disabled")) this._aria("ariaDisabled", "aria-disabled", this.disabled ? "true" : null);
|
|
35088
|
+
if (changed.has("loading")) this._aria("ariaBusy", "aria-busy", this.loading ? "true" : null);
|
|
35089
|
+
}
|
|
35090
|
+
/** Leaf items omit `aria-expanded` entirely; branches reflect their state. */
|
|
35091
|
+
_reflectExpanded() {
|
|
35092
|
+
this._aria("ariaExpanded", "aria-expanded", this.isLeaf() ? null : String(this.expanded));
|
|
35093
|
+
}
|
|
35094
|
+
/**
|
|
35095
|
+
* Write an ARIA state to BOTH ElementInternals (the semantic source, in the
|
|
35096
|
+
* accessibility tree) and a content attribute (so `[aria-*]` CSS / query / test
|
|
35097
|
+
* selectors keep matching — same belt-and-suspenders as the mirrored `role`).
|
|
35098
|
+
* A `null` value clears both.
|
|
35099
|
+
*/
|
|
35100
|
+
_aria(key, attr, value) {
|
|
35101
|
+
this._internals[key] = value;
|
|
35102
|
+
if (value === null) this.removeAttribute(attr);
|
|
35103
|
+
else this.setAttribute(attr, value);
|
|
35055
35104
|
}
|
|
35056
35105
|
_setState(name, on) {
|
|
35057
35106
|
if (!this._internals.states) return;
|
|
@@ -35068,14 +35117,12 @@ var TreeItem = class extends LuxenElement {
|
|
|
35068
35117
|
this._hasChildren = count > 0;
|
|
35069
35118
|
this._setState("has-children", this._hasChildren);
|
|
35070
35119
|
if (!this._hasChildren && !this.lazy && this.expanded) this.expanded = false;
|
|
35071
|
-
this.
|
|
35120
|
+
this._reflectExpanded();
|
|
35072
35121
|
}
|
|
35073
|
-
/** Toggle expand state.
|
|
35122
|
+
/** Toggle expand state. Opening a `lazy` item emits `lazy-load` (via `updated`). */
|
|
35074
35123
|
toggle() {
|
|
35075
35124
|
if (this.isLeaf() && !this.lazy) return;
|
|
35076
|
-
|
|
35077
|
-
if (next && this.lazy) this.emit("lazy-load");
|
|
35078
|
-
this.expanded = next;
|
|
35125
|
+
this.expanded = !this.expanded;
|
|
35079
35126
|
}
|
|
35080
35127
|
render() {
|
|
35081
35128
|
return b`
|
|
@@ -35125,6 +35172,7 @@ var TreeItem = class extends LuxenElement {
|
|
|
35125
35172
|
part="checkbox"
|
|
35126
35173
|
type="checkbox"
|
|
35127
35174
|
tabindex="-1"
|
|
35175
|
+
aria-hidden="true"
|
|
35128
35176
|
.checked=${this.selected}
|
|
35129
35177
|
.indeterminate=${this.indeterminate}
|
|
35130
35178
|
?disabled=${this.disabled}
|