diff --git a/packages/calcite-components/src/components.d.ts b/packages/calcite-components/src/components.d.ts index feacafafdb1..bfa5b3f2fc8 100644 --- a/packages/calcite-components/src/components.d.ts +++ b/packages/calcite-components/src/components.d.ts @@ -982,6 +982,7 @@ export namespace Components { "form": string; /** * The `id` attribute of the component. When omitted, a globally unique identifier is used. + * @deprecated No longer necessary. */ "guid": string; /** @@ -4199,6 +4200,7 @@ export namespace Components { "form": string; /** * The `id` of the component. When omitted, a globally unique identifier is used. + * @deprecated No longer necessary. */ "guid": string; /** @@ -5785,6 +5787,7 @@ export namespace Components { * When `true`, displays indentation guide lines. */ "lines": boolean; + "parentExpanded": boolean; /** * Specifies the size of the component. */ @@ -8967,6 +8970,7 @@ declare namespace LocalJSX { "form"?: string; /** * The `id` attribute of the component. When omitted, a globally unique identifier is used. + * @deprecated No longer necessary. */ "guid"?: string; /** @@ -12368,6 +12372,7 @@ declare namespace LocalJSX { "form"?: string; /** * The `id` of the component. When omitted, a globally unique identifier is used. + * @deprecated No longer necessary. */ "guid"?: string; /** @@ -14016,6 +14021,7 @@ declare namespace LocalJSX { * Fires when the user selects/deselects `calcite-tree-items`. */ "onCalciteTreeSelect"?: (event: CalciteTreeCustomEvent) => void; + "parentExpanded"?: boolean; /** * Specifies the size of the component. */ diff --git a/packages/calcite-components/src/components/tree-item/tree-item.tsx b/packages/calcite-components/src/components/tree-item/tree-item.tsx index c3f0655c75b..07c4b7998fe 100644 --- a/packages/calcite-components/src/components/tree-item/tree-item.tsx +++ b/packages/calcite-components/src/components/tree-item/tree-item.tsx @@ -14,15 +14,10 @@ import { import { filterDirectChildren, getElementDir, - getSlotted, + slotChangeGetAssignedElements, slotChangeHasAssignedElement, toAriaBoolean, } from "../../utils/dom"; -import { - ConditionalSlotComponent, - connectConditionalSlotComponent, - disconnectConditionalSlotComponent, -} from "../../utils/conditionalSlot"; import { InteractiveComponent, InteractiveContainer, @@ -45,7 +40,7 @@ import { CSS, ICONS, SLOTS } from "./resources"; styleUrl: "tree-item.scss", shadow: true, }) -export class TreeItem implements ConditionalSlotComponent, InteractiveComponent { +export class TreeItem implements InteractiveComponent { //-------------------------------------------------------------------------- // // Properties @@ -64,8 +59,8 @@ export class TreeItem implements ConditionalSlotComponent, InteractiveComponent @Prop({ mutable: true, reflect: true }) expanded = false; @Watch("expanded") - expandedHandler(newValue: boolean): void { - this.updateParentIsExpanded(this.el, newValue); + expandedHandler(): void { + this.updateChildTree(); } /** When `true`, the icon will be flipped when the element direction is right-to-left (`"rtl"`). */ @@ -142,15 +137,6 @@ export class TreeItem implements ConditionalSlotComponent, InteractiveComponent connectedCallback(): void { this.parentTreeItem = this.el.parentElement?.closest("calcite-tree-item"); - if (this.parentTreeItem) { - const { expanded } = this.parentTreeItem; - this.updateParentIsExpanded(this.parentTreeItem, expanded); - } - connectConditionalSlotComponent(this); - } - - disconnectedCallback(): void { - disconnectConditionalSlotComponent(this); } componentWillRender(): void { @@ -337,7 +323,7 @@ export class TreeItem implements ConditionalSlotComponent, InteractiveComponent onClick={this.childrenClickHandler} role={this.hasChildren ? "group" : undefined} > - + @@ -454,25 +440,39 @@ export class TreeItem implements ConditionalSlotComponent, InteractiveComponent private userChangedValue = false; + private childTree: HTMLCalciteTreeElement; + //-------------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------------- + private updateChildTree(): void { + const { childTree } = this; + + if (!childTree) { + return; + } + + childTree.parentExpanded = this.expanded; + } + + private handleChildrenSlotChange = (event: Event): void => { + const childTree = slotChangeGetAssignedElements(event).filter( + (el): el is HTMLCalciteTreeElement => el.matches("calcite-tree"), + )[0]; + + this.childTree = childTree; + + this.updateChildTree(); + }; + private isActionEndEvent(event: Event): boolean { const composedPath = event.composedPath(); return composedPath.includes(this.actionSlotWrapper); } - private updateParentIsExpanded = (el: HTMLCalciteTreeItemElement, expanded: boolean): void => { - const items = getSlotted(el, SLOTS.children, { - all: true, - selector: "calcite-tree-item", - }); - items.forEach((item) => (item.parentExpanded = expanded)); - }; - /** * This is meant to be called in `componentDidLoad` in order to take advantage of the hierarchical component lifecycle * and help check for item selection as items are initialized diff --git a/packages/calcite-components/src/components/tree/tree.tsx b/packages/calcite-components/src/components/tree/tree.tsx index 6f07c8e5d91..03577a4ad9b 100644 --- a/packages/calcite-components/src/components/tree/tree.tsx +++ b/packages/calcite-components/src/components/tree/tree.tsx @@ -8,8 +8,14 @@ import { Listen, Prop, VNode, + Watch, } from "@stencil/core"; -import { focusElement, nodeListToArray, toAriaBoolean } from "../../utils/dom"; +import { + focusElement, + nodeListToArray, + slotChangeGetAssignedElements, + toAriaBoolean, +} from "../../utils/dom"; import { Scale, SelectionMode } from "../interfaces"; import { TreeItemSelectDetail } from "../tree-item/interfaces"; import { getTraversableItems, isTreeItem } from "./utils"; @@ -37,6 +43,16 @@ export class Tree { */ @Prop({ reflect: true, mutable: true }) child: boolean; + /** + * @internal + */ + @Prop() parentExpanded = false; + + @Watch("parentExpanded") + handleParentExpandedChange(): void { + this.updateItems(); + } + /** Specifies the size of the component. */ @Prop({ mutable: true, reflect: true }) scale: Scale = "m"; @@ -96,7 +112,7 @@ export class Tree { role={!this.child ? "tree" : undefined} tabIndex={this.getRootTabIndex()} > - + ); } @@ -435,12 +451,27 @@ export class Tree { @Element() el: HTMLCalciteTreeElement; + private items: HTMLCalciteTreeItemElement[] = []; + // -------------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------------- + private updateItems(): void { + this.items.forEach((item) => (item.parentExpanded = this.parentExpanded)); + } + + private handleDefaultSlotChange = (event: Event): void => { + const items = slotChangeGetAssignedElements(event).filter( + (el): el is HTMLCalciteTreeItemElement => el.matches("calcite-tree-item"), + ); + + this.items = items; + this.updateItems(); + }; + getRootTabIndex(): number { return !this.child ? 0 : -1; }