Skip to content

Commit

Permalink
fix(tree, tree-item): fix rendering tied to named-slot content (#10462)
Browse files Browse the repository at this point in the history
**Related Issue:** #6059

## Summary

- remove use of `getSlotted` utility
- replace with `slotchange` event and `@State` variables to update the
display of elements.
- existing tests should suffice
  • Loading branch information
driskull authored Oct 1, 2024
1 parent cc75101 commit d2f9fb6
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 29 deletions.
6 changes: 6 additions & 0 deletions packages/calcite-components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
/**
Expand Down Expand Up @@ -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;
/**
Expand Down Expand Up @@ -5785,6 +5787,7 @@ export namespace Components {
* When `true`, displays indentation guide lines.
*/
"lines": boolean;
"parentExpanded": boolean;
/**
* Specifies the size of the component.
*/
Expand Down Expand Up @@ -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;
/**
Expand Down Expand Up @@ -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;
/**
Expand Down Expand Up @@ -14016,6 +14021,7 @@ declare namespace LocalJSX {
* Fires when the user selects/deselects `calcite-tree-items`.
*/
"onCalciteTreeSelect"?: (event: CalciteTreeCustomEvent<void>) => void;
"parentExpanded"?: boolean;
/**
* Specifies the size of the component.
*/
Expand Down
54 changes: 27 additions & 27 deletions packages/calcite-components/src/components/tree-item/tree-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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"`). */
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -337,7 +323,7 @@ export class TreeItem implements ConditionalSlotComponent, InteractiveComponent
onClick={this.childrenClickHandler}
role={this.hasChildren ? "group" : undefined}
>
<slot name={SLOTS.children} />
<slot name={SLOTS.children} onSlotchange={this.handleChildrenSlotChange} />
</div>
</div>
</InteractiveContainer>
Expand Down Expand Up @@ -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<HTMLCalciteTreeItemElement>(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
Expand Down
35 changes: 33 additions & 2 deletions packages/calcite-components/src/components/tree/tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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";

Expand Down Expand Up @@ -96,7 +112,7 @@ export class Tree {
role={!this.child ? "tree" : undefined}
tabIndex={this.getRootTabIndex()}
>
<slot />
<slot onSlotchange={this.handleDefaultSlotChange} />
</Host>
);
}
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit d2f9fb6

Please sign in to comment.