Skip to content

Commit

Permalink
feat(list)!: Support moving between different lists via keyboard (#10480
Browse files Browse the repository at this point in the history
)

**Related Issue:** #7537

## Summary

- depends on #10241
- updates `action` to allow cursor to be overriden
- lists should set the `label` property for the "Move to" sorting menu
to have a name for the list.
- adds `calcite-sort-handle` component to handle sorting and moving
between lists for non mouse users
  - internal component 
  - adds stories
  - adds tests 
- list-item
  - deprecates `dragSelected` property: no longer needed.
- deprecates `calciteListItemDragHandleChange` event. no longer needed.
- removed setting `aria-posinset` and `aria-setsize`. These are only
needed when only part of the items are availalbe in the DOM. So we can
safely remove these.
-
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-setsize
-
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-posinset
- replaces `calcite-handle` with `calcite-sort-handle` in the `list`
component.
- updates tests
- adds tests
- adds demo pages

BREAKING CHANGE: Modifies the component's keyboard sorting experience by
using a dropdown menu to move list items. The ListItem `dragSelected`
property and `calciteListItemDragHandleChange` event have been removed
due to no longer being relevant.
  • Loading branch information
driskull authored Oct 31, 2024
1 parent c150492 commit 1005109
Show file tree
Hide file tree
Showing 22 changed files with 1,344 additions and 283 deletions.
240 changes: 223 additions & 17 deletions packages/calcite-components/src/components.d.ts

Large diffs are not rendered by default.

13 changes: 8 additions & 5 deletions packages/calcite-components/src/components/action/action.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

:host {
@extend %component-host;
@apply flex bg-transparent;
@apply flex bg-transparent cursor-pointer;
}

:host,
Expand Down Expand Up @@ -62,7 +62,6 @@ button {
m-0
flex
w-auto
cursor-pointer
items-center
justify-start
border-none
Expand All @@ -73,6 +72,7 @@ button {
color: var(--calcite-action-text-color, var(--calcite-color-text-3));
text-align: unset;
flex: 1 0 auto;
cursor: inherit;

&:hover,
&:focus {
Expand Down Expand Up @@ -173,7 +173,8 @@ button {

:host([scale="s"]) {
.button {
@apply text-n2h px-2 font-normal;
@apply text-n2h font-normal;
padding-inline: var(--calcite-internal-action-padding-inline, theme("spacing.2"));
padding-block: var(--calcite-internal-action-padding-block, var(--calcite-size-xxs));
}
.button--text-visible .icon-container {
Expand All @@ -183,7 +184,8 @@ button {

:host([scale="m"]) {
.button {
@apply text-n1h px-4 font-normal;
@apply text-n1h font-normal;
padding-inline: var(--calcite-internal-action-padding-inline, theme("spacing.4"));
padding-block: var(--calcite-internal-action-padding-block, var(--calcite-size-md));
}
.button--text-visible .icon-container {
Expand All @@ -193,7 +195,8 @@ button {

:host([scale="l"]) {
.button {
@apply text-0h px-5 font-normal;
@apply text-0h font-normal;
padding-inline: var(--calcite-internal-action-padding-inline, theme("spacing.5"));
padding-block: var(--calcite-internal-action-padding-block, var(--calcite-size-xl));
}
.button--text-visible .icon-container {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ export class Dropdown
this.toggleDropdown();
event.preventDefault();
} else if (key === "ArrowDown" || key === "ArrowUp") {
event.preventDefault();
this.focusLastDropdownItem = key === "ArrowUp";
this.open = true;
this.el.addEventListener("calciteDropdownOpen", this.onOpenEnd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ describe("calcite-list-item", () => {
propertyName: "dragHandle",
defaultValue: false,
},
{
propertyName: "dragSelected",
defaultValue: false,
},
{
propertyName: "filterHidden",
defaultValue: false,
Expand Down Expand Up @@ -139,15 +135,15 @@ describe("calcite-list-item", () => {
await page.setContent(`<calcite-list-item></calcite-list-item>`);
await page.waitForChanges();

let handleNode = await page.find("calcite-list-item >>> calcite-handle");
let handleNode = await page.find("calcite-list-item >>> calcite-sort-handle");

expect(handleNode).toBeNull();

const item = await page.find("calcite-list-item");
item.setProperty("dragHandle", true);
await page.waitForChanges();

handleNode = await page.find("calcite-list-item >>> calcite-handle");
handleNode = await page.find("calcite-list-item >>> calcite-sort-handle");

expect(handleNode).not.toBeNull();
});
Expand Down Expand Up @@ -375,29 +371,4 @@ describe("calcite-list-item", () => {
expect(await listItem.getProperty("open")).toBe(false);
expect(calciteListItemToggle).toHaveReceivedEventTimes(2);
});

it("should fire calciteListItemDragHandleChange event when drag handle is clicked", async () => {
const page = await newE2EPage({
html: html`<calcite-list-item drag-handle></calcite-list-item>`,
});

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

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

const dragHandle = await page.find(`calcite-list-item >>> calcite-handle`);
await dragHandle.callMethod("setFocus");
await page.waitForChanges();

await dragHandle.press("Space");
await page.waitForChanges();
expect(await listItem.getProperty("dragSelected")).toBe(true);
expect(calciteListItemDragHandleChange).toHaveReceivedEventTimes(1);

await dragHandle.press("Space");
await page.waitForChanges();
expect(await listItem.getProperty("dragSelected")).toBe(false);
expect(calciteListItemDragHandleChange).toHaveReceivedEventTimes(2);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@
@apply flex items-center;

calcite-action,
calcite-handle {
calcite-sort-handle {
@apply self-stretch;
}
}
Expand All @@ -208,7 +208,7 @@
@apply p-0 relative;
::slotted(calcite-action),
::slotted(calcite-action-menu),
::slotted(calcite-handle),
::slotted(calcite-sort-handle),
::slotted(calcite-dropdown) {
@apply self-stretch;

Expand All @@ -223,7 +223,7 @@
.close,
::slotted(calcite-action),
::slotted(calcite-action-menu),
::slotted(calcite-handle),
::slotted(calcite-sort-handle),
::slotted(calcite-dropdown) {
block-size: calc(100% - theme("spacing[1]"));
}
Expand Down
106 changes: 73 additions & 33 deletions packages/calcite-components/src/components/list-item/list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,9 @@ import {
setUpLoadableComponent,
} from "../../utils/loadable";
import { SortableComponentItem } from "../../utils/sortableComponent";
import { MoveTo } from "../sort-handle/interfaces";
import { ListItemMessages } from "./assets/list-item/t9n";
import {
getDepth,
getListItemChildren,
getListItemChildLists,
updateListItemChildren,
} from "./utils";
import { getDepth, hasListItemChildren } from "./utils";
import { CSS, activeCellTestAttribute, ICONS, SLOTS } from "./resources";

const focusMap = new Map<HTMLCalciteListElement, number>();
Expand Down Expand Up @@ -140,11 +136,6 @@ export class ListItem
*/
@Prop() dragHandle = false;

/**
* When `true`, the component's drag handle is selected.
*/
@Prop({ mutable: true, reflect: true }) dragSelected = false;

/**
* Hides the component when filtered.
*
Expand All @@ -162,6 +153,13 @@ export class ListItem
*/
@Prop() metadata: Record<string, unknown>;

/**
* Sets the item to display a border.
*
* @internal
*/
@Prop() moveToItems: MoveTo[] = [];

/**
* When `true`, the item is open to show child components.
*/
Expand All @@ -173,14 +171,14 @@ export class ListItem
}

/**
* Used to specify the aria-setsize attribute to define the number of items in the current set of list for accessibility.
* Used to determine what menu options are available in the sort-handle
*
* @internal
*/
@Prop() setSize: number = null;

/**
* Used to specify the aria-posinset attribute to define the number or position in the current set of list items for accessibility.
* Used to determine what menu options are available in the sort-handle
*
* @internal
*/
Expand Down Expand Up @@ -229,6 +227,21 @@ export class ListItem
*/
@Prop({ mutable: true }) selectionAppearance: SelectionAppearance = null;

/**
* When `true`, displays and positions the sort handle.
*/
@Prop({ mutable: true }) sortHandleOpen = false;

@Watch("sortHandleOpen")
sortHandleOpenHandler(): void {
if (!this.sortHandleEl) {
return;
}

// we set the property instead of the attribute to ensure open/close events are emitted properly
this.sortHandleEl.open = this.sortHandleOpen;
}

/**
* Use this property to override individual strings used by the component.
*/
Expand Down Expand Up @@ -264,10 +277,17 @@ export class ListItem
*/
@Event({ cancelable: false }) calciteListItemClose: EventEmitter<void>;

/**
* Fires when the drag handle is selected.
*/
@Event({ cancelable: false }) calciteListItemDragHandleChange: EventEmitter<void>;
/** Fires when the sort handle is requested to be closed and before the closing transition begins. */
@Event({ cancelable: false }) calciteListItemSortHandleBeforeClose: EventEmitter<void>;

/** Fires when the sort handle is closed and animation is complete. */
@Event({ cancelable: false }) calciteListItemSortHandleClose: EventEmitter<void>;

/** Fires when the sort handle is added to the DOM but not rendered, and before the opening transition begins. */
@Event({ cancelable: false }) calciteListItemSortHandleBeforeOpen: EventEmitter<void>;

/** Fires when the sort handle is open and animation is complete. */
@Event({ cancelable: false }) calciteListItemSortHandleOpen: EventEmitter<void>;

/**
* Fires when the open button is clicked.
Expand Down Expand Up @@ -367,6 +387,8 @@ export class ListItem

defaultSlotEl: HTMLSlotElement;

private sortHandleEl: HTMLCalciteSortHandleElement;

// --------------------------------------------------------------------------
//
// Lifecycle
Expand Down Expand Up @@ -466,7 +488,7 @@ export class ListItem
}

renderDragHandle(): VNode {
const { label, dragHandle, dragSelected, dragDisabled, setPosition, setSize } = this;
const { label, dragHandle, dragDisabled, setPosition, setSize, moveToItems } = this;

return dragHandle ? (
<div
Expand All @@ -477,11 +499,16 @@ export class ListItem
ref={(el) => (this.handleGridEl = el)}
role="gridcell"
>
<calcite-handle
<calcite-sort-handle
disabled={dragDisabled}
label={label}
onCalciteHandleChange={this.dragHandleSelectedChangeHandler}
selected={dragSelected}
moveToItems={moveToItems}
onCalciteSortHandleBeforeClose={this.handleSortHandleBeforeClose}
onCalciteSortHandleBeforeOpen={this.handleSortHandleBeforeOpen}
onCalciteSortHandleClose={this.handleSortHandleClose}
onCalciteSortHandleOpen={this.handleSortHandleOpen}
overlayPositioning="fixed"
ref={this.setSortHandleEl}
setPosition={setPosition}
setSize={setSize}
/>
Expand Down Expand Up @@ -659,8 +686,6 @@ export class ListItem
openable,
open,
level,
setPosition,
setSize,
active,
label,
selected,
Expand Down Expand Up @@ -691,9 +716,7 @@ export class ListItem
aria-expanded={openable ? toAriaBoolean(open) : null}
aria-label={label}
aria-level={level}
aria-posinset={setPosition}
aria-selected={toAriaBoolean(selected)}
aria-setsize={setSize}
class={{
[CSS.row]: true,
[CSS.container]: true,
Expand Down Expand Up @@ -731,10 +754,31 @@ export class ListItem
//
// --------------------------------------------------------------------------

private dragHandleSelectedChangeHandler = (event: CustomEvent<void>): void => {
this.dragSelected = (event.target as HTMLCalciteHandleElement).selected;
this.calciteListItemDragHandleChange.emit();
private setSortHandleEl = (el: HTMLCalciteSortHandleElement): void => {
this.sortHandleEl = el;
this.sortHandleOpenHandler();
};

private handleSortHandleBeforeOpen = (event: CustomEvent<void>): void => {
event.stopPropagation();
this.calciteListItemSortHandleBeforeOpen.emit();
};

private handleSortHandleBeforeClose = (event: CustomEvent<void>): void => {
event.stopPropagation();
this.calciteListItemSortHandleBeforeClose.emit();
};

private handleSortHandleClose = (event: CustomEvent<void>): void => {
event.stopPropagation();
this.sortHandleOpen = false;
this.calciteListItemSortHandleClose.emit();
};

private handleSortHandleOpen = (event: CustomEvent<void>): void => {
event.stopPropagation();
this.sortHandleOpen = true;
this.calciteListItemSortHandleOpen.emit();
};

private emitInternalListItemActive = (): void => {
Expand Down Expand Up @@ -815,11 +859,7 @@ export class ListItem
return;
}

const listItemChildren = getListItemChildren(slotEl);
const listItemChildLists = getListItemChildLists(slotEl);
updateListItemChildren(listItemChildren);

this.openable = !!listItemChildren.length || !!listItemChildLists.length;
this.openable = hasListItemChildren(slotEl);
}

private handleDefaultSlotChange = (event: Event): void => {
Expand Down
Loading

0 comments on commit 1005109

Please sign in to comment.