Skip to content

Commit

Permalink
Merge branch 'master' into new-tree-flatarray-prop
Browse files Browse the repository at this point in the history
  • Loading branch information
bhavers committed Dec 2, 2024
2 parents 048c10a + c7f4b16 commit d1c0081
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 30 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ jobs:
- name: Install dependencies
run: npm install

- name: Run lint
run: npm run lint

- name: Unit tests
run: npm run test

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [0.86.2](https://github.com/carbon-design-system/carbon-components-svelte/compare/v0.86.1...v0.86.2) (2024-11-30)

### Bug Fixes

- **multi-select:** fix sorting behavior ([c3a390f](https://github.com/carbon-design-system/carbon-components-svelte/commit/c3a390f3fef072c6b736e33a85a2ae772df12e52)), closes [#2066](https://github.com/carbon-design-system/carbon-components-svelte/issues/2066)

## [0.86.1](https://github.com/carbon-design-system/carbon-components-svelte/compare/v0.86.0...v0.86.1) (2024-11-22)

### Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion COMPONENT_INDEX.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Component Index

> 165 components exported from [email protected].1.
> 165 components exported from [email protected].2.
## Components

Expand Down
7 changes: 2 additions & 5 deletions docs/src/COMPONENT_API.json
Original file line number Diff line number Diff line change
Expand Up @@ -3235,10 +3235,7 @@
"ts": "interface DataTableCell<\n Row = DataTableRow,\n> {\n key:\n | DataTableKey<Row>\n | (string & {});\n value: DataTableValue;\n display?: (\n item: DataTableValue,\n row: DataTableRow,\n ) => DataTableValue;\n}\n"
}
],
"generics": [
"Row",
"Row extends DataTableRow = DataTableRow"
],
"generics": ["Row", "Row extends DataTableRow = DataTableRow"],
"rest_props": {
"type": "Element",
"name": "div"
Expand Down Expand Up @@ -18078,4 +18075,4 @@
}
}
]
}
}
30 changes: 18 additions & 12 deletions docs/src/components/ComponentApi.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
$: source = `https://github.com/carbon-design-system/carbon-components-svelte/tree/master/${component.filePath}`;
$: forwarded_events = component.events.filter(
(event) => event.type === "forwarded"
(event) => event.type === "forwarded",
);
$: dispatched_events = component.events.filter(
(event) => event.type === "dispatched"
(event) => event.type === "dispatched",
);
</script>

Expand Down Expand Up @@ -116,20 +116,20 @@
>
<svelte:component
this={AsyncPreviewTypeScript}
type="inline"
code={typeMap[type]}
/>
</div>
type="inline"
code={typeMap[type]}
/>
</div>
{:else}
<div
style="display: inline-flex; max-width: 220px; word-break: break-word;"
>
<svelte:component
this={AsyncPreviewTypeScript}
type="inline"
code={type}
/>
</div>
type="inline"
code={type}
/>
</div>
{/if}
</div>
{/each}
Expand All @@ -145,10 +145,16 @@
</div>
{/each}
{/if}
<div style:margin-top="var(--cds-layout-02)" style:margin-bottom="var(--cds-spacing-03)">
<div
style:margin-top="var(--cds-layout-02)"
style:margin-bottom="var(--cds-spacing-03)"
>
<strong>Default value</strong>
</div>
<div style:margin-bottom="var(--cds-layout-01)" style:max-width="85%">
<div
style:margin-bottom="var(--cds-layout-01)"
style:max-width="85%"
>
{#if prop.value === undefined}
<em>undefined</em>
{:else}
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "carbon-components-svelte",
"version": "0.86.1",
"version": "0.86.2",
"license": "Apache-2.0",
"description": "Svelte implementation of the Carbon Design System",
"type": "module",
Expand Down
6 changes: 3 additions & 3 deletions scripts/format-component-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { format } from "prettier";
import plugin from "prettier/plugins/typescript";

const formatTypeScript = async (value) => {
return await format(value, {
parser: "typescript",
return await format(value, {
parser: "typescript",
plugins: [plugin],
printWidth: 40, // Force breaking onto new lines
bracketSameLine: false
bracketSameLine: false,
});
};

Expand Down
25 changes: 19 additions & 6 deletions src/MultiSelect/MultiSelect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,11 @@
}
});
$: menuId = `menu-${id}`;
$: inline = type === "inline";
$: ariaLabel = $$props["aria-label"] || "Choose an item";
$: sortedItems = (() => {
if (selectionFeedback === "top" && selectedIds.length > 0) {
function sort() {
if (
selectionFeedback === "top" ||
selectionFeedback === "top-after-reopen"
) {
const checkedItems = items
.filter((item) => selectedIds.includes(item.id))
.map((item) => ({ ...item, checked: true }));
Expand All @@ -269,7 +269,20 @@
checked: selectedIds.includes(item.id),
}))
.sort(sortItem);
})();
}
let sortedItems = sort();
$: menuId = `menu-${id}`;
$: inline = type === "inline";
$: ariaLabel = $$props["aria-label"] || "Choose an item";
$: if (
selectedIds &&
(selectionFeedback === "top" ||
(selectionFeedback === "top-after-reopen" && open === false))
) {
sortedItems = sort();
}
$: checked = sortedItems.filter(({ checked }) => checked);
$: unchecked = sortedItems.filter(({ checked }) => !checked);
$: filteredItems = sortedItems.filter((item) => filterItem(item, value));
Expand Down
124 changes: 124 additions & 0 deletions tests/MultiSelect/MultiSelect.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { render, screen } from "@testing-library/svelte";
import { MultiSelect } from "carbon-components-svelte";
import { user } from "../setup-tests";

describe("MultiSelect sorts items correctly", () => {
/** Opens the dropdown. */
const openMenu = async () =>
await user.click(
await screen.findByLabelText("Open menu", {
selector: `[role="button"]`,
}),
);

/** Closes the dropdown. */
const closeMenu = async () =>
await user.click(
await screen.findByLabelText("Close menu", {
selector: `[role="button"]`,
}),
);

/** Toggles an option, identifying it by its `text` value. */
const toggleOption = async (optionText: string) =>
await user.click(
await screen.findByText((text) => text.trim() === optionText),
);

/** Fetches the `text` value of the nth option in the MultiSelect component. */
const nthRenderedOptionText = (index: number) =>
screen.queryAllByRole("option").at(index)?.textContent?.trim();

it("initially sorts items alphabetically", async () => {
render(MultiSelect, {
items: [
{ id: "1", text: "C" },
{ id: "3", text: "A" },
{ id: "2", text: "B" },
],
});

await openMenu();
expect(nthRenderedOptionText(0)).toBe("A");
expect(nthRenderedOptionText(1)).toBe("B");
expect(nthRenderedOptionText(2)).toBe("C");
});

it("immediately moves selected items to the top (with selectionFeedback: top)", async () => {
render(MultiSelect, {
items: [
{ id: "3", text: "C" },
{ id: "1", text: "A" },
{ id: "2", text: "B" },
],
selectionFeedback: "top",
});

await openMenu();
expect(nthRenderedOptionText(0)).toBe("A");

await toggleOption("C");
expect(nthRenderedOptionText(0)).toBe("C");

await toggleOption("C");
expect(nthRenderedOptionText(0)).toBe("A");
});

it("sorts newly-toggled items only after the dropdown is reoponed (with selectionFeedback: top-after-reopen)", async () => {
render(MultiSelect, {
items: [
{ id: "3", text: "C" },
{ id: "1", text: "A" },
{ id: "2", text: "B" },
],
});

// Initially, items should be sorted alphabetically.
await openMenu();
expect(nthRenderedOptionText(0)).toBe("A");

// While the menu is still open, a newly-selected item should not move.
await toggleOption("C");
expect(nthRenderedOptionText(0)).toBe("A");

// The newly-selected item should move after the menu is closed and
// re-opened.
await closeMenu();
await openMenu();
expect(nthRenderedOptionText(0)).toBe("C");

// A deselected item should not move while the dropdown is still open.
await toggleOption("C");
expect(nthRenderedOptionText(0)).toBe("C");

// The deselected item should move after closing and re-opening the dropdown.
await closeMenu();
await openMenu();
expect(nthRenderedOptionText(0)).toBe("A");
});

it("never moves selected items to the top (with selectionFeedback: fixed)", async () => {
render(MultiSelect, {
items: [
{ id: "3", text: "C" },
{ id: "1", text: "A" },
{ id: "2", text: "B" },
],
selectionFeedback: "fixed",
});

// Items should be sorted alphabetically.
await openMenu();
expect(nthRenderedOptionText(0)).toBe("A");

// A newly-selected item should not move after the selection is made.
await toggleOption("C");
expect(nthRenderedOptionText(0)).toBe("A");

// The newly-selected item also shouldn’t move after the dropdown is closed
// and reopened.
await closeMenu();
await openMenu();
expect(nthRenderedOptionText(0)).toBe("A");
});
});
3 changes: 3 additions & 0 deletions tests/setup-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ import "@testing-library/jest-dom/vitest";
import { userEvent } from "@testing-library/user-event";
import "../css/all.css";

// Mock scrollIntoView since it's not implemented in JSDOM
Element.prototype.scrollIntoView = vi.fn();

export const user = userEvent.setup();

0 comments on commit d1c0081

Please sign in to comment.