Skip to content

Commit

Permalink
feat(tree): add none selection mode (#5128)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcfranco authored Aug 16, 2022
1 parent 2e2b694 commit e96bfbe
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 28 deletions.
3 changes: 2 additions & 1 deletion src/components/tree-item/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ export const SLOTS = {
export const ICONS = {
bulletPoint: "bullet-point",
checkmark: "check",
chevronRight: "chevron-right"
chevronRight: "chevron-right",
blank: "blank"
};
8 changes: 7 additions & 1 deletion src/components/tree-item/tree-item.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
cursor-pointer;
}

:host([selection-mode="none"]:not([has-children])) {
.node-container {
margin-inline: theme("margin.3");
}
}

@include calciteHydratedHidden();

:host([scale="s"]) {
Expand Down Expand Up @@ -177,7 +183,7 @@
}

// dropdown expanded and not selected
:host([has-children][expanded]:not([selected])) > .node-container {
:host([has-children][expanded]:not([selected]):not([selection-mode="none"])) > .node-container {
::slotted(*) {
@apply text-color-1 font-medium;
}
Expand Down
6 changes: 3 additions & 3 deletions src/components/tree-item/tree-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export class TreeItem implements ConditionalSlotComponent {
/**
* @internal
*/
@Prop({ mutable: true }) selectionMode: TreeSelectionMode;
@Prop({ mutable: true, reflect: true }) selectionMode: TreeSelectionMode;

@Watch("selectionMode")
getselectionMode(): void {
Expand Down Expand Up @@ -213,7 +213,7 @@ export class TreeItem implements ConditionalSlotComponent {
: showCheckmark
? ICONS.checkmark
: null;
const bulletOrCheckIcon = selectedIcon ? (
const itemIndicator = selectedIcon ? (
<calcite-icon
class={{
[CSS.bulletPointIcon]: selectedIcon === ICONS.bulletPoint,
Expand Down Expand Up @@ -245,7 +245,7 @@ export class TreeItem implements ConditionalSlotComponent {
ref={(el) => (this.defaultSlotWrapper = el as HTMLElement)}
>
{chevron}
{bulletOrCheckIcon}
{itemIndicator}
{checkbox ? checkbox : defaultSlotNode}
</div>
<div
Expand Down
1 change: 1 addition & 0 deletions src/components/tree/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface TreeSelectDetail {
export enum TreeSelectionMode {
Single = "single",
Multi = "multi",
None = "none",
Children = "children",
MultiChildren = "multi-children",
Ancestors = "ancestors"
Expand Down
38 changes: 38 additions & 0 deletions src/components/tree/tree.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,44 @@ describe("calcite-tree", () => {
expect(checkbox).not.toBeNull();
});
});

describe(`when tree-item selection-mode is ${TreeSelectionMode.None}`, () => {
it("allows selecting items without a selection", async () => {
const page = await newE2EPage();
await page.setContent(html`
<calcite-tree selection-mode=${TreeSelectionMode.None}>
<calcite-tree-item id="1">1</calcite-tree-item>
<calcite-tree-item id="2">2</calcite-tree-item>
</calcite-tree>
`);

type TestWindow = GlobalTestProps<{
selectedIds: string[];
}>;

await page.evaluateHandle(() =>
document.addEventListener("calciteTreeSelect", ({ detail }: CustomEvent) => {
(window as TestWindow).selectedIds = detail.selected.map((item) => item.id);
})
);

const getSelectedIds = async (): Promise<any> => page.evaluate(() => (window as TestWindow).selectedIds);

const tree = await page.find(`calcite-tree`);
const selectEventSpy = await tree.spyOnEvent("calciteTreeSelect");
const [item1, item2] = await page.findAll(`calcite-tree-item`);

await item1.click();
expect(selectEventSpy).toHaveReceivedEventTimes(1);
expect(await getSelectedIds()).toEqual(["1"]);
expect(await page.findAll("calcite-tree-item[selected]")).toHaveLength(0);

await item2.click();
expect(selectEventSpy).toHaveReceivedEventTimes(2);
expect(await getSelectedIds()).toEqual(["2"]);
expect(await page.findAll("calcite-tree-item[selected]")).toHaveLength(0);
});
});
});

describe("keyboard support", () => {
Expand Down
20 changes: 5 additions & 15 deletions src/components/tree/tree.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,12 @@ export default {
}
};

const selectionModes = ["single", "multi", "children", "multi-children", "ancestors", "none"];

export const Simple = (): string => html`
<calcite-tree
${boolean("lines", false)}
selection-mode="${select(
"selection-mode",
["single", "multi", "children", "multi-children", "ancestors"],
"single"
)}"
selection-mode="${select("selection-mode", selectionModes, "single")}"
scale="${select("scale", ["s", "m", "l"], "m")}"
>
${treeItems}
Expand All @@ -67,11 +65,7 @@ export const RTL = (): string => html`
<calcite-tree
dir="rtl"
${boolean("lines", false)}
selection-mode="${select(
"selection-mode",
["single", "multi", "children", "multi-children", "ancestors"],
"single"
)}"
selection-mode="${select("selection-mode", selectionModes, "single")}"
scale="${select("scale", ["s", "m", "l"], "m")}"
>
${treeItems}
Expand All @@ -82,11 +76,7 @@ export const DarkMode = (): string => html`
<calcite-tree
class="calcite-theme-dark"
${boolean("lines", false)}
selection-mode="${select(
"selection-mode",
["single", "multi", "children", "multi-children", "ancestors"],
"single"
)}"
selection-mode="${select("selection-mode", selectionModes, "single")}"
scale="${select("scale", ["s", "m", "l"], "m")}"
>
${treeItems}
Expand Down
19 changes: 11 additions & 8 deletions src/components/tree/tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ export class Tree {
return;
}

const isNoneSelectionMode = this.selectionMode === TreeSelectionMode.None;

const shouldSelect =
this.selectionMode !== null &&
(!target.hasChildren ||
Expand All @@ -160,6 +162,7 @@ export class Tree {
this.selectionMode === TreeSelectionMode.MultiChildren)));

const shouldModifyToCurrentSelection =
!isNoneSelectionMode &&
event.detail.modifyCurrentSelection &&
(this.selectionMode === TreeSelectionMode.Multi ||
this.selectionMode === TreeSelectionMode.MultiChildren);
Expand Down Expand Up @@ -220,20 +223,20 @@ export class Tree {
targetItems.forEach((treeItem) => {
treeItem.selected = false;
});
} else {
} else if (!isNoneSelectionMode) {
targetItems.forEach((treeItem) => {
treeItem.selected = true;
});
}
}

this.calciteTreeSelect.emit({
selected: (
nodeListToArray(
this.el.querySelectorAll("calcite-tree-item")
) as HTMLCalciteTreeItemElement[]
).filter((i) => i.selected)
});
const selected = isNoneSelectionMode
? [target]
: (nodeListToArray(this.el.querySelectorAll("calcite-tree-item")).filter(
(i) => i.selected
) as HTMLCalciteTreeItemElement[]);

this.calciteTreeSelect.emit({ selected });

event.stopPropagation();
}
Expand Down
89 changes: 89 additions & 0 deletions src/demos/tree.html
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,95 @@ <h1 style="margin: 0 auto; text-align: center">Tree</h1>
</div>
</div>

<!-- none selection mode -->
<div class="parent">
<div class="child right-aligned-text">none selection mode</div>

<div class="child">
<calcite-tree selection-mode="none" scale="s">
<calcite-tree-item>
<span>Child 1</span>
</calcite-tree-item>

<calcite-tree-item>
<span>Child 2</span>

<calcite-tree slot="children">
<calcite-tree-item>
<span>Grandchild 1</span>
<calcite-tree slot="children">
<calcite-tree-item>
<span>Great Grandchild 1</span>
</calcite-tree-item>
<calcite-tree-item>
<span>Great Grandchild 2</span>
</calcite-tree-item>
<calcite-tree-item>
<span>Great Grandchild 3</span>
</calcite-tree-item>
</calcite-tree>
</calcite-tree-item>
<calcite-tree-item>
<span>Grandchild 2</span>
</calcite-tree-item>
<calcite-tree-item>
<span>Grandchild 3</span>
</calcite-tree-item>
</calcite-tree>
</calcite-tree-item>

<calcite-tree-item>
<span>Child 3</span>
</calcite-tree-item>
<calcite-tree-item>
<span>Child 4</span>
</calcite-tree-item>
</calcite-tree>
</div>

<div class="child">
<calcite-tree selection-mode="none" scale="m">
<calcite-tree-item>
<span>Child 1</span>
</calcite-tree-item>

<calcite-tree-item>
<span>Child 2</span>

<calcite-tree slot="children">
<calcite-tree-item>
<span>Grandchild 1</span>
<calcite-tree slot="children">
<calcite-tree-item>
<span>Great Grandchild 1</span>
</calcite-tree-item>
<calcite-tree-item>
<span>Great Grandchild 2</span>
</calcite-tree-item>
<calcite-tree-item>
<span>Great Grandchild 3</span>
</calcite-tree-item>
</calcite-tree>
</calcite-tree-item>
<calcite-tree-item>
<span>Grandchild 2</span>
</calcite-tree-item>
<calcite-tree-item>
<span>Grandchild 3</span>
</calcite-tree-item>
</calcite-tree>
</calcite-tree-item>

<calcite-tree-item>
<span>Child 3</span>
</calcite-tree-item>
<calcite-tree-item>
<span>Child 4</span>
</calcite-tree-item>
</calcite-tree>
</div>
</div>

<!-- events to test -->
<div class="parent">
<div class="child right-aligned-text">events</div>
Expand Down

0 comments on commit e96bfbe

Please sign in to comment.