Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/src/COMPONENT_API.json
Original file line number Diff line number Diff line change
Expand Up @@ -18479,6 +18479,12 @@
"type": "(visible: boolean) => void",
"description": "",
"optional": false
},
{
"name": "batchActionsActive",
"type": "import(\"svelte/store\").Writable<boolean>",
"description": "",
"optional": false
}
]
}
Expand Down
64 changes: 64 additions & 0 deletions docs/src/pages/components/DataTable.svx
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,70 @@ Use `size="short"` to create a more compact table with a small toolbar.
</Toolbar>
</DataTable>

## With toolbar and selectable rows

Set `selectable` to `true` to enable selectable rows. Here, the toolbar is used standalone. For batch actions for selected rows, see the [batch selection with toolbar](#batch-selection-with-batch-actions-toolbar) example.

<DataTable selectable size="short" title="Load balancers" description="Your organization's active load balancers."
headers="{[
{ key: "name", value: "Name" },
{ key: "protocol", value: "Protocol" },
{ key: "port", value: "Port" },
{ key: "rule", value: "Rule" }
]}"
rows="{[
{
id: "a",
name: "Load Balancer 3",
protocol: "HTTP",
port: 3000,
rule: "Round robin"
},
{
id: "b",
name: "Load Balancer 1",
protocol: "HTTP",
port: 443,
rule: "Round robin"
},
{
id: "c",
name: "Load Balancer 2",
protocol: "HTTP",
port: 80,
rule: "DNS delegation"
},
{
id: "d",
name: "Load Balancer 6",
protocol: "HTTP",
port: 3000,
rule: "Round robin"
},
{
id: "e",
name: "Load Balancer 4",
protocol: "HTTP",
port: 443,
rule: "Round robin"
},
{
id: "f",
name: "Load Balancer 5",
protocol: "HTTP",
port: 80,
rule: "DNS delegation"
},
]}"
>
<Toolbar size="sm">
<ToolbarContent>
<ToolbarSearch persistent />
<Button>Action</Button>
</ToolbarContent>
</Toolbar>
</DataTable>

## Filterable

Set `shouldFilterRows` to `true` to enable client-side filtering. The default filter performs string comparisons on cell values.
Expand Down
6 changes: 6 additions & 0 deletions src/DataTable/Toolbar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
*/
const overflowVisible = writable(false);

/**
* @type {import("svelte/store").Writable<boolean>}
*/
const batchActionsActive = writable(false);

/**
* @type {(visible: boolean) => void}
*/
Expand All @@ -26,6 +31,7 @@
setContext("Toolbar", {
overflowVisible,
setOverflowVisible,
batchActionsActive,
});
</script>

Expand Down
4 changes: 4 additions & 0 deletions src/DataTable/ToolbarBatchActions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@
});
}

$: if (ctxToolbar?.batchActionsActive) {
ctxToolbar.batchActionsActive.set(showActions);
}

onMount(() => {
return () => {
unsubscribe?.();
Expand Down
13 changes: 6 additions & 7 deletions src/DataTable/ToolbarContent.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
<script>
import { getContext } from "svelte";

const ctx = getContext("DataTable") ?? {};
const ctx = getContext("Toolbar") ?? {};

let batchSelectedIds = [];
let batchActionsActive = false;

if (ctx?.batchSelectedIds) {
ctx.batchSelectedIds.subscribe((value) => {
batchSelectedIds = value;
if (ctx?.batchActionsActive) {
ctx.batchActionsActive.subscribe((value) => {
batchActionsActive = value;
});
}

$: hasBatchSelection = batchSelectedIds.length > 0;
$: inertProps = hasBatchSelection ? { inert: true } : {};
$: inertProps = batchActionsActive ? { inert: true } : {};
</script>

<div class:bx--toolbar-content={true} {...inertProps}>
Expand Down
32 changes: 32 additions & 0 deletions tests/DataTable/DataTableToolbarNoBatch.test.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import {
Button,
DataTable,
Toolbar,
ToolbarContent,
ToolbarSearch,
} from "carbon-components-svelte";

const headers = [
{ key: "name", value: "Name" },
{ key: "port", value: "Port" },
{ key: "rule", value: "Rule" },
] as const;

const rows = [
{ id: "a", name: "Load Balancer 3", port: 3000, rule: "Round robin" },
{ id: "b", name: "Load Balancer 1", port: 443, rule: "Round robin" },
{ id: "c", name: "Load Balancer 2", port: 80, rule: "DNS delegation" },
];

export let selectedRowIds: string[] = [];
</script>

<DataTable selectable {headers} {rows} bind:selectedRowIds>
<Toolbar>
<ToolbarContent>
<ToolbarSearch persistent />
<Button>Action</Button>
</ToolbarContent>
</Toolbar>
</DataTable>
45 changes: 45 additions & 0 deletions tests/DataTable/DataTableToolbarNoBatch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { render, screen } from "@testing-library/svelte";
import { user } from "../setup-tests";
import DataTableToolbarNoBatch from "./DataTableToolbarNoBatch.test.svelte";

// Regression test for https://github.com/carbon-design-system/carbon-components-svelte/issues/2404
describe("DataTable toolbar without batch actions", () => {
it("toolbar content should not be inert when rows are selected without batch actions", () => {
const { container } = render(DataTableToolbarNoBatch, {
props: {
selectedRowIds: ["a"],
},
});

const toolbarContent = container.querySelector(".bx--toolbar-content");
expect(toolbarContent).not.toHaveAttribute("inert");
});

it("toolbar button should be clickable when rows are selected without batch actions", async () => {
const clickHandler = vi.fn();
render(DataTableToolbarNoBatch, {
props: {
selectedRowIds: ["a"],
},
});

const button = screen.getByText("Action");
button.addEventListener("click", clickHandler);
await user.click(button);

expect(clickHandler).toHaveBeenCalled();
});

it("toolbar search should be focusable when rows are selected without batch actions", async () => {
render(DataTableToolbarNoBatch, {
props: {
selectedRowIds: ["a"],
},
});

const searchInput = screen.getByRole("searchbox");
await user.click(searchInput);

expect(searchInput).toHaveFocus();
});
});
1 change: 1 addition & 0 deletions types/DataTable/Toolbar.svelte.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { SvelteHTMLElements } from "svelte/elements";
export type ToolbarContext = {
overflowVisible: import("svelte/store").Writable<boolean>;
setOverflowVisible: (visible: boolean) => void;
batchActionsActive: import("svelte/store").Writable<boolean>;
};

type $RestProps = SvelteHTMLElements["section"];
Expand Down