Skip to content

Commit

Permalink
fix(combobox): fix navigating initially when multiple items are selec…
Browse files Browse the repository at this point in the history
…ted (#9613)

**Related Issue:** #6776

## Summary

- When a chip is focused, the activeChipIndex is updated
- Only allow tabindex on one chip or the input.
- Adds tests
  • Loading branch information
driskull committed Jun 17, 2024
1 parent 6f466aa commit 5d9509b
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 2 deletions.
4 changes: 2 additions & 2 deletions packages/calcite-components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1819,7 +1819,7 @@ export namespace Components {
*/
"items": object[];
/**
* Specifies the fields to match against when filtering.
* Specifies the fields to match against when filtering. This will only apply when `value` is an object. If not set, all fields will be matched.
*/
"matchFields": string[];
/**
Expand Down Expand Up @@ -9648,7 +9648,7 @@ declare namespace LocalJSX {
*/
"items"?: object[];
/**
* Specifies the fields to match against when filtering.
* Specifies the fields to match against when filtering. This will only apply when `value` is an object. If not set, all fields will be matched.
*/
"matchFields"?: string[];
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,77 @@ describe("calcite-combobox", () => {
}
});

describe("keyboard navigation with chips", () => {
let page: E2EPage;
beforeEach(async () => {
page = await newE2EPage();
await page.setContent(html`
<calcite-combobox id="myCombobox" placeholder="Select a field">
<calcite-combobox-item value="Natural Resources" text-label="Natural Resources"></calcite-combobox-item>
<calcite-combobox-item value="Agriculture" text-label="Agriculture"></calcite-combobox-item>
<calcite-combobox-item value="Forestry" text-label="Forestry"></calcite-combobox-item>
<calcite-combobox-item selected value="Mining" text-label="Mining"></calcite-combobox-item>
<calcite-combobox-item value="Business" text-label="Business"></calcite-combobox-item>
<calcite-combobox-item selected value="Education" text-label="Education"></calcite-combobox-item>
<calcite-combobox-item selected value="Utilities" text-label="Utilities"></calcite-combobox-item>
<calcite-combobox-item value="Transportation" text-label="Transportation"></calcite-combobox-item>
</calcite-combobox>
`);
});

it("should navigate chips with arrow keys", async () => {
const comboboxId = "myCombobox";
const inputId = "input";
const chipId = "chip";

const getActiveElementId = () => page.evaluate(() => document.activeElement.id);

const getDataTestId = () =>
page.$eval(`#${comboboxId}`, (myCombobox) => myCombobox.shadowRoot.activeElement.getAttribute("data-test-id"));

await page.keyboard.press("Tab");
await page.waitForChanges();

expect(await getActiveElementId()).toBe(comboboxId);
expect(await getDataTestId()).toBe(inputId);

await page.keyboard.press("ArrowRight");
await page.waitForChanges();
expect(await getActiveElementId()).toBe(comboboxId);
expect(await getDataTestId()).toBe(inputId);

await page.keyboard.press("ArrowLeft");
await page.waitForChanges();
expect(await getActiveElementId()).toBe(comboboxId);
expect(await getDataTestId()).toBe(`${chipId}-2`);

await page.keyboard.press("ArrowLeft");
await page.waitForChanges();
expect(await getActiveElementId()).toBe(comboboxId);
expect(await getDataTestId()).toBe(`${chipId}-1`);

await page.keyboard.press("ArrowLeft");
await page.waitForChanges();
expect(await getActiveElementId()).toBe(comboboxId);
expect(await getDataTestId()).toBe(`${chipId}-0`);

await page.keyboard.press("ArrowLeft");
await page.waitForChanges();
expect(await getActiveElementId()).toBe(comboboxId);
expect(await getDataTestId()).toBe(`${chipId}-0`);

await page.keyboard.press("ArrowRight");
await page.waitForChanges();
expect(await getActiveElementId()).toBe(comboboxId);
expect(await getDataTestId()).toBe(`${chipId}-1`);

await page.keyboard.press("ArrowRight");
await page.waitForChanges();
expect(await getActiveElementId()).toBe(comboboxId);
expect(await getDataTestId()).toBe(`${chipId}-2`);
});
});

describe("keyboard navigation in all selection-display mode", () => {
let page: E2EPage;
const scrollablePageSizeInPx = 2400;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1387,14 +1387,17 @@ export class Combobox
appearance={readOnly ? "outline" : "solid"}
class={chipClasses}
closable={!readOnly}
data-test-id={`chip-${i}`}
icon={item.icon}
iconFlipRtl={item.iconFlipRtl}
id={item.guid ? `${chipUidPrefix}${item.guid}` : null}
key={item.textLabel}
messageOverrides={{ dismissLabel: messages.removeTag }}
onCalciteChipClose={() => this.calciteChipCloseHandler(item)}
onFocusin={() => (this.activeChipIndex = i)}
scale={scale}
selected={item.selected}
tabindex={activeChipIndex === i ? 0 : -1}
title={label}
value={item.value}
>
Expand Down Expand Up @@ -1597,6 +1600,7 @@ export class Combobox
"input--hidden": showLabel,
"input--icon": this.showingInlineIcon && !!this.placeholderIcon,
}}
data-test-id="input"
disabled={disabled}
id={`${inputUidPrefix}${guid}`}
key="input"
Expand All @@ -1606,6 +1610,7 @@ export class Combobox
readOnly={this.readOnly}
ref={(el) => (this.textInput = el as HTMLInputElement)}
role="combobox"
tabindex={this.activeChipIndex === -1 ? 0 : -1}
type="text"
/>
</span>
Expand Down

0 comments on commit 5d9509b

Please sign in to comment.