mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-14 18:01:06 +00:00
Merge branch 'master' into new-tree-flatarray-prop
This commit is contained in:
commit
d1c00813fd
11 changed files with 182 additions and 30 deletions
3
.github/workflows/checks.yml
vendored
3
.github/workflows/checks.yml
vendored
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Component Index
|
||||
|
||||
> 165 components exported from carbon-components-svelte@0.86.1.
|
||||
> 165 components exported from carbon-components-svelte@0.86.2.
|
||||
|
||||
## Components
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
@ -18078,4 +18075,4 @@
|
|||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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}
|
||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "carbon-components-svelte",
|
||||
"version": "0.86.1",
|
||||
"version": "0.86.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "carbon-components-svelte",
|
||||
"version": "0.86.1",
|
||||
"version": "0.86.2",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -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 }));
|
||||
|
@ -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));
|
||||
|
|
124
tests/MultiSelect/MultiSelect.test.ts
Normal file
124
tests/MultiSelect/MultiSelect.test.ts
Normal file
|
@ -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,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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue