Skip to content

Commit

Permalink
feat(list-item): Add calciteListItemToggle event. (#8433)
Browse files Browse the repository at this point in the history
**Related Issue:** #8434

## Summary

- Adds `calciteListItemToggle ` event for when a list item open is
toggled via user interaction.
- Adds test
  • Loading branch information
driskull authored Dec 16, 2023
1 parent 9e5c59b commit 1d2fa04
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 24 deletions.
5 changes: 5 additions & 0 deletions packages/calcite-components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6286,6 +6286,7 @@ declare global {
interface HTMLCalciteListItemElementEventMap {
"calciteListItemSelect": void;
"calciteListItemClose": void;
"calciteListItemToggle": void;
"calciteInternalListItemSelect": void;
"calciteInternalListItemSelectMultiple": {
selectMultiple: boolean;
Expand Down Expand Up @@ -10083,6 +10084,10 @@ declare namespace LocalJSX {
* Emits when the item's content is selected.
*/
"onCalciteListItemSelect"?: (event: CalciteListItemCustomEvent<void>) => void;
/**
* Fires when the open button is clicked.
*/
"onCalciteListItemToggle"?: (event: CalciteListItemCustomEvent<void>) => void;
/**
* When `true`, the item is open to show child components.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,27 @@ describe("calcite-list-item", () => {

expect(calciteListItemClose).toHaveReceivedEventTimes(1);
});

it("should fire calciteListItemToggle event when opened and closed", async () => {
const page = await newE2EPage({
html: html`<calcite-list-item
><calcite-list><calcite-list-item></calcite-list-item></calcite-list
></calcite-list-item>`,
});

const listItem = await page.find("calcite-list-item");
const calciteListItemToggle = await page.spyOnEvent("calciteListItemToggle", "window");

expect(await listItem.getProperty("open")).toBe(false);

const openButton = await page.find(`calcite-list-item >>> .${CSS.openContainer}`);

await openButton.click();
expect(await listItem.getProperty("open")).toBe(true);
expect(calciteListItemToggle).toHaveReceivedEventTimes(1);

await openButton.click();
expect(await listItem.getProperty("open")).toBe(false);
expect(calciteListItemToggle).toHaveReceivedEventTimes(2);
});
});
58 changes: 34 additions & 24 deletions packages/calcite-components/src/components/list-item/list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ export class ListItem
*/
@Event({ cancelable: false }) calciteListItemClose: EventEmitter<void>;

/**
* Fires when the open button is clicked.
*/
@Event({ cancelable: false }) calciteListItemToggle: EventEmitter<void>;

/**
*
* @internal
Expand Down Expand Up @@ -397,7 +402,7 @@ export class ListItem
}

return (
<td class={CSS.selectionContainer} key="selection-container" onClick={this.itemClicked}>
<td class={CSS.selectionContainer} key="selection-container" onClick={this.handleItemClick}>
<calcite-icon
icon={
selected
Expand Down Expand Up @@ -446,7 +451,7 @@ export class ListItem
: ICONS.closedLTR
: ICONS.blank;

const clickHandler = openable ? this.toggleOpen : this.itemClicked;
const clickHandler = openable ? this.handleToggleClick : this.handleItemClick;

return openable || parentListEl?.openable ? (
<td class={CSS.openContainer} key="open-container" onClick={clickHandler}>
Expand Down Expand Up @@ -491,7 +496,7 @@ export class ListItem
icon={ICONS.close}
key="close-action"
label={messages.close}
onClick={this.closeClickHandler}
onClick={this.handleCloseClick}
text={messages.close}
/>
) : null}
Expand Down Expand Up @@ -593,7 +598,7 @@ export class ListItem
[CSS.contentContainerHasCenterContent]: hasCenterContent,
}}
key="content-container"
onClick={this.itemClicked}
onClick={this.handleItemClick}
role="gridcell"
// eslint-disable-next-line react/jsx-sort-props -- ref should be last so node attrs/props are in sync (see https://github.com/Esri/calcite-design-system/pull/6530)
ref={(el) => (this.contentEl = el)}
Expand Down Expand Up @@ -669,36 +674,36 @@ export class ListItem
this.calciteInternalListItemChange.emit();
}

closeClickHandler = (): void => {
private handleCloseClick = (): void => {
this.closed = true;
this.calciteListItemClose.emit();
};

handleContentSlotChange = (event: Event): void => {
private handleContentSlotChange = (event: Event): void => {
this.hasCustomContent = slotChangeHasAssignedElement(event);
};

handleActionsStartSlotChange = (event: Event): void => {
private handleActionsStartSlotChange = (event: Event): void => {
this.hasActionsStart = slotChangeHasAssignedElement(event);
};

handleActionsEndSlotChange = (event: Event): void => {
private handleActionsEndSlotChange = (event: Event): void => {
this.hasActionsEnd = slotChangeHasAssignedElement(event);
};

handleContentStartSlotChange = (event: Event): void => {
private handleContentStartSlotChange = (event: Event): void => {
this.hasContentStart = slotChangeHasAssignedElement(event);
};

handleContentEndSlotChange = (event: Event): void => {
private handleContentEndSlotChange = (event: Event): void => {
this.hasContentEnd = slotChangeHasAssignedElement(event);
};

handleContentBottomSlotChange = (event: Event): void => {
private handleContentBottomSlotChange = (event: Event): void => {
this.hasContentBottom = slotChangeHasAssignedElement(event);
};

setSelectionDefaults(): void {
private setSelectionDefaults(): void {
const { parentListEl, selectionMode, selectionAppearance } = this;

if (!parentListEl) {
Expand All @@ -714,7 +719,7 @@ export class ListItem
}
}

handleOpenableChange(slotEl: HTMLSlotElement): void {
private handleOpenableChange(slotEl: HTMLSlotElement): void {
if (!slotEl) {
return;
}
Expand All @@ -736,15 +741,20 @@ export class ListItem
}
}

handleDefaultSlotChange = (event: Event): void => {
private handleDefaultSlotChange = (event: Event): void => {
this.handleOpenableChange(event.target as HTMLSlotElement);
};

toggleOpen = (): void => {
this.open = !this.open;
private handleToggleClick = (): void => {
this.toggle();
};

private toggle = (value = !this.open): void => {
this.open = value;
this.calciteListItemToggle.emit();
};

itemClicked = (event: PointerEvent): void => {
private handleItemClick = (event: PointerEvent): void => {
if (event.defaultPrevented) {
return;
}
Expand All @@ -753,7 +763,7 @@ export class ListItem
this.calciteInternalListItemActive.emit();
};

toggleSelected = (shiftKey: boolean): void => {
private toggleSelected = (shiftKey: boolean): void => {
const { selectionMode, selected } = this;

if (this.disabled) {
Expand All @@ -772,13 +782,13 @@ export class ListItem
this.calciteListItemSelect.emit();
};

getGridCells(): HTMLTableCellElement[] {
private getGridCells(): HTMLTableCellElement[] {
return [this.handleGridEl, this.actionsStartEl, this.contentEl, this.actionsEndEl].filter(
(el) => el && !el.hidden
);
}

handleItemKeyDown = (event: KeyboardEvent): void => {
private handleItemKeyDown = (event: KeyboardEvent): void => {
if (event.defaultPrevented) {
return;
}
Expand All @@ -802,7 +812,7 @@ export class ListItem
const nextIndex = currentIndex + 1;
if (currentIndex === -1) {
if (!open && openable) {
this.open = true;
this.toggle(true);
this.focusCell(null);
} else if (cells[0]) {
this.focusCell(cells[0]);
Expand All @@ -816,7 +826,7 @@ export class ListItem
if (currentIndex === -1) {
this.focusCell(null);
if (open && openable) {
this.open = false;
this.toggle(false);
} else {
this.calciteInternalFocusPreviousItem.emit();
}
Expand All @@ -829,11 +839,11 @@ export class ListItem
}
};

focusCellNull = (): void => {
private focusCellNull = (): void => {
this.focusCell(null);
};

focusCell = (focusEl: HTMLTableCellElement, saveFocusIndex = true): void => {
private focusCell = (focusEl: HTMLTableCellElement, saveFocusIndex = true): void => {
const { parentListEl } = this;

if (saveFocusIndex) {
Expand Down

0 comments on commit 1d2fa04

Please sign in to comment.