@crisp-ui-kit/crisp 0.33.1 → 0.33.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/datatable/datatable.js +14 -2
- package/dist/cjs/components/datatable/datatable.recipe.js +5 -0
- package/dist/datatable.css +3 -1
- package/dist/datatable.layered.css +3 -1
- package/dist/esm/components/datatable/datatable.js +14 -2
- package/dist/esm/components/datatable/datatable.recipe.js +5 -0
- package/dist/styles.css +3 -1
- package/dist/styles.layered.css +3 -1
- package/dist/types/components/datatable/datatable.d.ts +10 -1
- package/package.json +1 -1
|
@@ -155,7 +155,7 @@ function renderTyped(col, value, avatarTone, display) {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
const CHECK_W = 40;
|
|
158
|
-
function DataTable({ columns: columnsProp, data, selectable = false, selectedIds, onSelectionChange, selectAllLabel = "Select all rows", selectRowLabel = (row) => `Select row ${row.id}`, columnMenu = false, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable = false, searchPlaceholder = "Search…", searchLabel = "Search table", onEdit, stickyFirst = true, avatarTone = "brand", surface, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", empty = "No results.", showCount = true, countLabel = (shown, total) => shown === total
|
|
158
|
+
function DataTable({ columns: columnsProp, data, selectable = false, selectedIds, onSelectionChange, selectAllLabel = "Select all rows", selectRowLabel = (row) => `Select row ${row.id}`, selectionAnnouncement = (count) => count === 0 ? "Selection cleared" : `${count} selected`, columnMenu = false, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable = false, searchPlaceholder = "Search…", searchLabel = "Search table", onEdit, stickyFirst = true, avatarTone = "brand", surface, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", empty = "No results.", showCount = true, countLabel = (shown, total) => shown === total
|
|
159
159
|
? `${total} ${total === 1 ? "row" : "rows"}`
|
|
160
160
|
: `${shown} of ${total}`, toolbar, className, reorderRowLabel = "Reorder row", ...rest }) {
|
|
161
161
|
const [query, setQuery] = React.useState("");
|
|
@@ -234,6 +234,18 @@ function DataTable({ columns: columnsProp, data, selectable = false, selectedIds
|
|
|
234
234
|
if (!selectedIds)
|
|
235
235
|
setInternalSel(next);
|
|
236
236
|
}, [onSelectionChange, selectedIds]);
|
|
237
|
+
// The selection is announced from a region that is part of the table and
|
|
238
|
+
// outlives every selection, because a consumer's own bulk bar (mounted only
|
|
239
|
+
// once something is picked) cannot announce its own arrival (#234).
|
|
240
|
+
// Derived by adjusting state during render rather than in an effect: it
|
|
241
|
+
// must not fire on mount — nobody has selected anything yet — and it has to
|
|
242
|
+
// cover a `selectedIds` change the consumer makes as well as a click here.
|
|
243
|
+
const prevSelectedCount = React.useRef(selected.size);
|
|
244
|
+
const [selectionText, setSelectionText] = React.useState("");
|
|
245
|
+
if (prevSelectedCount.current !== selected.size) {
|
|
246
|
+
prevSelectedCount.current = selected.size;
|
|
247
|
+
setSelectionText(selectionAnnouncement(selected.size));
|
|
248
|
+
}
|
|
237
249
|
const [editing, setEditing] = React.useState(null);
|
|
238
250
|
const [scrolledX, setScrolledX] = React.useState(false);
|
|
239
251
|
// column widths (drag-to-resize) + fixed-layout sizing
|
|
@@ -464,7 +476,7 @@ function DataTable({ columns: columnsProp, data, selectable = false, selectedIds
|
|
|
464
476
|
return dir === "asc" ? ((0, jsx_runtime_1.jsx)(lucide_react_1.ArrowUp, { className: "crisp-datatable-chevron", size: 13, strokeWidth: 2 })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "crisp-datatable-chevron", size: 13, strokeWidth: 2 }));
|
|
465
477
|
return ((0, jsx_runtime_1.jsx)(lucide_react_1.ChevronsUpDown, { className: "crisp-datatable-chevron", size: 13, strokeWidth: 2 }));
|
|
466
478
|
}
|
|
467
|
-
return ((0, jsx_runtime_1.jsxs)("div", { ref: gridRef, className: (0, datatable_recipe_1.datatableRecipe)({ className }), tabIndex: -1, onKeyDown: onGridKeyDown, ...rest, children: [(filterable || showCount || toolbar || columnMenu) && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-datatable-toolbar", children: [columnMenu && ((0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "start", trigger: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-datatable-viewsettings", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.SlidersHorizontal, { size: 14, strokeWidth: 1.75 }), "View settings"] }), children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-datatable-group-label", children: "Columns" }), allColumns.map((c) => ((0, jsx_runtime_1.jsxs)(menu_1.MenuItem, { onSelect: () => c.hidden ? showColumn(c.key) : hideColumn(c.key), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 14, strokeWidth: 2, style: { opacity: c.hidden ? 0 : 1 } }), typeof c.header === "string" ? c.header : c.key] }, c.key)))] })), filterable && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-datatable-search", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)("input", { type: "search", placeholder: searchPlaceholder, value: query, onChange: (e) => setQuery(e.target.value), "aria-label": searchLabel })] })), showCount && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-datatable-count", children: countLabel(rows.length, data.length) })), toolbar] })), (0, jsx_runtime_1.jsxs)(table_1.Table, { interactive: interactive, surface: surface, style: { minWidth }, scrollProps: {
|
|
479
|
+
return ((0, jsx_runtime_1.jsxs)("div", { ref: gridRef, className: (0, datatable_recipe_1.datatableRecipe)({ className }), tabIndex: -1, onKeyDown: onGridKeyDown, ...rest, children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-datatable-live", role: "status", "aria-live": "polite", children: selectionText }), (filterable || showCount || toolbar || columnMenu) && ((0, jsx_runtime_1.jsxs)("div", { className: "crisp-datatable-toolbar", children: [columnMenu && ((0, jsx_runtime_1.jsxs)(menu_1.Menu, { align: "start", trigger: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "crisp-datatable-viewsettings", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.SlidersHorizontal, { size: 14, strokeWidth: 1.75 }), "View settings"] }), children: [(0, jsx_runtime_1.jsx)("div", { className: "crisp-datatable-group-label", children: "Columns" }), allColumns.map((c) => ((0, jsx_runtime_1.jsxs)(menu_1.MenuItem, { onSelect: () => c.hidden ? showColumn(c.key) : hideColumn(c.key), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: 14, strokeWidth: 2, style: { opacity: c.hidden ? 0 : 1 } }), typeof c.header === "string" ? c.header : c.key] }, c.key)))] })), filterable && ((0, jsx_runtime_1.jsxs)("span", { className: "crisp-datatable-search", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Search, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)("input", { type: "search", placeholder: searchPlaceholder, value: query, onChange: (e) => setQuery(e.target.value), "aria-label": searchLabel })] })), showCount && ((0, jsx_runtime_1.jsx)("span", { className: "crisp-datatable-count", children: countLabel(rows.length, data.length) })), toolbar] })), (0, jsx_runtime_1.jsxs)(table_1.Table, { interactive: interactive, surface: surface, style: { minWidth }, scrollProps: {
|
|
468
480
|
onScroll: (e) => setScrolledX(e.currentTarget.scrollLeft > 0),
|
|
469
481
|
...(scrolledX ? { "data-scrolled-x": "" } : {}),
|
|
470
482
|
}, children: [(0, jsx_runtime_1.jsxs)("colgroup", { children: [showGrip && (0, jsx_runtime_1.jsx)("col", { style: { width: GRIP_W } }), selectable && (0, jsx_runtime_1.jsx)("col", { style: { width: CHECK_W } }), columns.map((col) => ((0, jsx_runtime_1.jsx)("col", { style: { width: colWidth(col) } }, col.key)))] }), (0, jsx_runtime_1.jsx)(table_1.TableHeader, { children: (0, jsx_runtime_1.jsxs)(table_1.TableRow, { children: [showGrip && ((0, jsx_runtime_1.jsx)(table_1.TableHead, { className: "crisp-datatable-col-grip", ...stickyCol(-2) })), selectable && ((0, jsx_runtime_1.jsx)(table_1.TableHead, { className: "crisp-datatable-col-check", ...stickyCol(-1), children: (0, jsx_runtime_1.jsx)("span", { className: "crisp-datatable-check", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { "aria-label": selectAllLabel, checked: allSelected, indeterminate: someSelected, onChange: toggleAll }) }) })), columns.map((col, i) => {
|
|
@@ -18,6 +18,11 @@ const config = (0, core_1.defineRecipe)({
|
|
|
18
18
|
& .crisp-datatable-search input:focus { box-shadow: inset 0 0 0 1px ${tokens_1.contract.bgBrandSolid}; }
|
|
19
19
|
& .crisp-datatable-count { margin-inline-start: auto; font-size: ${tokens_1.contract.text.md}; color: ${tokens_1.contract.fgMuted}; }
|
|
20
20
|
/* The header cell has no padding of its own -- the button owns the
|
|
21
|
+
/* announced, never drawn */
|
|
22
|
+
& .crisp-datatable-live {
|
|
23
|
+
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
24
|
+
overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
|
|
25
|
+
}
|
|
21
26
|
full cell so the whole header is clickable (its own inset is 12px).
|
|
22
27
|
Mirrors the summary-row fix. */
|
|
23
28
|
& th { padding: 0; }
|
package/dist/datatable.css
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
& .crisp-datatable-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
8
8
|
& .crisp-datatable-search input:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
9
9
|
& .crisp-datatable-count { margin-inline-start: auto; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
10
|
-
/* The header cell has no padding of its own -- the button owns the
|
|
10
|
+
/* The header cell has no padding of its own -- the button owns the /* announced, never drawn */
|
|
11
|
+
& .crisp-datatable-live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
12
|
+
full cell so the whole header is clickable (its own inset is 12px). Mirrors the summary-row fix. */
|
|
11
13
|
& th { padding: 0; }
|
|
12
14
|
/* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger):
|
|
13
15
|
Menu wraps its trigger in a flex div that sizes to its content, so a
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
& .crisp-datatable-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
9
9
|
& .crisp-datatable-search input:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
10
10
|
& .crisp-datatable-count { margin-inline-start: auto; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
11
|
-
/* The header cell has no padding of its own -- the button owns the
|
|
11
|
+
/* The header cell has no padding of its own -- the button owns the /* announced, never drawn */
|
|
12
|
+
& .crisp-datatable-live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
13
|
+
full cell so the whole header is clickable (its own inset is 12px). Mirrors the summary-row fix. */
|
|
12
14
|
& th { padding: 0; }
|
|
13
15
|
/* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger):
|
|
14
16
|
Menu wraps its trigger in a flex div that sizes to its content, so a
|
|
@@ -119,7 +119,7 @@ function renderTyped(col, value, avatarTone, display) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
const CHECK_W = 40;
|
|
122
|
-
export function DataTable({ columns: columnsProp, data, selectable = false, selectedIds, onSelectionChange, selectAllLabel = "Select all rows", selectRowLabel = (row) => `Select row ${row.id}`, columnMenu = false, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable = false, searchPlaceholder = "Search…", searchLabel = "Search table", onEdit, stickyFirst = true, avatarTone = "brand", surface, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", empty = "No results.", showCount = true, countLabel = (shown, total) => shown === total
|
|
122
|
+
export function DataTable({ columns: columnsProp, data, selectable = false, selectedIds, onSelectionChange, selectAllLabel = "Select all rows", selectRowLabel = (row) => `Select row ${row.id}`, selectionAnnouncement = (count) => count === 0 ? "Selection cleared" : `${count} selected`, columnMenu = false, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable = false, searchPlaceholder = "Search…", searchLabel = "Search table", onEdit, stickyFirst = true, avatarTone = "brand", surface, interactive = false, onRowClick, onAddRow, addRowLabel = "New record", empty = "No results.", showCount = true, countLabel = (shown, total) => shown === total
|
|
123
123
|
? `${total} ${total === 1 ? "row" : "rows"}`
|
|
124
124
|
: `${shown} of ${total}`, toolbar, className, reorderRowLabel = "Reorder row", ...rest }) {
|
|
125
125
|
const [query, setQuery] = React.useState("");
|
|
@@ -198,6 +198,18 @@ export function DataTable({ columns: columnsProp, data, selectable = false, sele
|
|
|
198
198
|
if (!selectedIds)
|
|
199
199
|
setInternalSel(next);
|
|
200
200
|
}, [onSelectionChange, selectedIds]);
|
|
201
|
+
// The selection is announced from a region that is part of the table and
|
|
202
|
+
// outlives every selection, because a consumer's own bulk bar (mounted only
|
|
203
|
+
// once something is picked) cannot announce its own arrival (#234).
|
|
204
|
+
// Derived by adjusting state during render rather than in an effect: it
|
|
205
|
+
// must not fire on mount — nobody has selected anything yet — and it has to
|
|
206
|
+
// cover a `selectedIds` change the consumer makes as well as a click here.
|
|
207
|
+
const prevSelectedCount = React.useRef(selected.size);
|
|
208
|
+
const [selectionText, setSelectionText] = React.useState("");
|
|
209
|
+
if (prevSelectedCount.current !== selected.size) {
|
|
210
|
+
prevSelectedCount.current = selected.size;
|
|
211
|
+
setSelectionText(selectionAnnouncement(selected.size));
|
|
212
|
+
}
|
|
201
213
|
const [editing, setEditing] = React.useState(null);
|
|
202
214
|
const [scrolledX, setScrolledX] = React.useState(false);
|
|
203
215
|
// column widths (drag-to-resize) + fixed-layout sizing
|
|
@@ -428,7 +440,7 @@ export function DataTable({ columns: columnsProp, data, selectable = false, sele
|
|
|
428
440
|
return dir === "asc" ? (_jsx(ArrowUp, { className: "crisp-datatable-chevron", size: 13, strokeWidth: 2 })) : (_jsx(ArrowDown, { className: "crisp-datatable-chevron", size: 13, strokeWidth: 2 }));
|
|
429
441
|
return (_jsx(ChevronsUpDown, { className: "crisp-datatable-chevron", size: 13, strokeWidth: 2 }));
|
|
430
442
|
}
|
|
431
|
-
return (_jsxs("div", { ref: gridRef, className: datatableRecipe({ className }), tabIndex: -1, onKeyDown: onGridKeyDown, ...rest, children: [(filterable || showCount || toolbar || columnMenu) && (_jsxs("div", { className: "crisp-datatable-toolbar", children: [columnMenu && (_jsxs(Menu, { align: "start", trigger: _jsxs("button", { type: "button", className: "crisp-datatable-viewsettings", children: [_jsx(SlidersHorizontal, { size: 14, strokeWidth: 1.75 }), "View settings"] }), children: [_jsx("div", { className: "crisp-datatable-group-label", children: "Columns" }), allColumns.map((c) => (_jsxs(MenuItem, { onSelect: () => c.hidden ? showColumn(c.key) : hideColumn(c.key), children: [_jsx(Check, { size: 14, strokeWidth: 2, style: { opacity: c.hidden ? 0 : 1 } }), typeof c.header === "string" ? c.header : c.key] }, c.key)))] })), filterable && (_jsxs("span", { className: "crisp-datatable-search", children: [_jsx(Search, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), _jsx("input", { type: "search", placeholder: searchPlaceholder, value: query, onChange: (e) => setQuery(e.target.value), "aria-label": searchLabel })] })), showCount && (_jsx("span", { className: "crisp-datatable-count", children: countLabel(rows.length, data.length) })), toolbar] })), _jsxs(Table, { interactive: interactive, surface: surface, style: { minWidth }, scrollProps: {
|
|
443
|
+
return (_jsxs("div", { ref: gridRef, className: datatableRecipe({ className }), tabIndex: -1, onKeyDown: onGridKeyDown, ...rest, children: [_jsx("div", { className: "crisp-datatable-live", role: "status", "aria-live": "polite", children: selectionText }), (filterable || showCount || toolbar || columnMenu) && (_jsxs("div", { className: "crisp-datatable-toolbar", children: [columnMenu && (_jsxs(Menu, { align: "start", trigger: _jsxs("button", { type: "button", className: "crisp-datatable-viewsettings", children: [_jsx(SlidersHorizontal, { size: 14, strokeWidth: 1.75 }), "View settings"] }), children: [_jsx("div", { className: "crisp-datatable-group-label", children: "Columns" }), allColumns.map((c) => (_jsxs(MenuItem, { onSelect: () => c.hidden ? showColumn(c.key) : hideColumn(c.key), children: [_jsx(Check, { size: 14, strokeWidth: 2, style: { opacity: c.hidden ? 0 : 1 } }), typeof c.header === "string" ? c.header : c.key] }, c.key)))] })), filterable && (_jsxs("span", { className: "crisp-datatable-search", children: [_jsx(Search, { size: 15, strokeWidth: 1.75, "aria-hidden": "true" }), _jsx("input", { type: "search", placeholder: searchPlaceholder, value: query, onChange: (e) => setQuery(e.target.value), "aria-label": searchLabel })] })), showCount && (_jsx("span", { className: "crisp-datatable-count", children: countLabel(rows.length, data.length) })), toolbar] })), _jsxs(Table, { interactive: interactive, surface: surface, style: { minWidth }, scrollProps: {
|
|
432
444
|
onScroll: (e) => setScrolledX(e.currentTarget.scrollLeft > 0),
|
|
433
445
|
...(scrolledX ? { "data-scrolled-x": "" } : {}),
|
|
434
446
|
}, children: [_jsxs("colgroup", { children: [showGrip && _jsx("col", { style: { width: GRIP_W } }), selectable && _jsx("col", { style: { width: CHECK_W } }), columns.map((col) => (_jsx("col", { style: { width: colWidth(col) } }, col.key)))] }), _jsx(TableHeader, { children: _jsxs(TableRow, { children: [showGrip && (_jsx(TableHead, { className: "crisp-datatable-col-grip", ...stickyCol(-2) })), selectable && (_jsx(TableHead, { className: "crisp-datatable-col-check", ...stickyCol(-1), children: _jsx("span", { className: "crisp-datatable-check", children: _jsx(Checkbox, { "aria-label": selectAllLabel, checked: allSelected, indeterminate: someSelected, onChange: toggleAll }) }) })), columns.map((col, i) => {
|
|
@@ -15,6 +15,11 @@ const config = defineRecipe({
|
|
|
15
15
|
& .crisp-datatable-search input:focus { box-shadow: inset 0 0 0 1px ${c.bgBrandSolid}; }
|
|
16
16
|
& .crisp-datatable-count { margin-inline-start: auto; font-size: ${c.text.md}; color: ${c.fgMuted}; }
|
|
17
17
|
/* The header cell has no padding of its own -- the button owns the
|
|
18
|
+
/* announced, never drawn */
|
|
19
|
+
& .crisp-datatable-live {
|
|
20
|
+
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
21
|
+
overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
|
|
22
|
+
}
|
|
18
23
|
full cell so the whole header is clickable (its own inset is 12px).
|
|
19
24
|
Mirrors the summary-row fix. */
|
|
20
25
|
& th { padding: 0; }
|
package/dist/styles.css
CHANGED
|
@@ -559,7 +559,9 @@
|
|
|
559
559
|
& .crisp-datatable-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
560
560
|
& .crisp-datatable-search input:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
561
561
|
& .crisp-datatable-count { margin-inline-start: auto; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
562
|
-
/* The header cell has no padding of its own -- the button owns the
|
|
562
|
+
/* The header cell has no padding of its own -- the button owns the /* announced, never drawn */
|
|
563
|
+
& .crisp-datatable-live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
564
|
+
full cell so the whole header is clickable (its own inset is 12px). Mirrors the summary-row fix. */
|
|
563
565
|
& th { padding: 0; }
|
|
564
566
|
/* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger):
|
|
565
567
|
Menu wraps its trigger in a flex div that sizes to its content, so a
|
package/dist/styles.layered.css
CHANGED
|
@@ -560,7 +560,9 @@
|
|
|
560
560
|
& .crisp-datatable-search input::placeholder { color: var(--crisp-fg-muted); }
|
|
561
561
|
& .crisp-datatable-search input:focus { box-shadow: inset 0 0 0 1px var(--crisp-bg-brand-solid); }
|
|
562
562
|
& .crisp-datatable-count { margin-inline-start: auto; font-size: var(--crisp-text-md); color: var(--crisp-fg-muted); }
|
|
563
|
-
/* The header cell has no padding of its own -- the button owns the
|
|
563
|
+
/* The header cell has no padding of its own -- the button owns the /* announced, never drawn */
|
|
564
|
+
& .crisp-datatable-live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
565
|
+
full cell so the whole header is clickable (its own inset is 12px). Mirrors the summary-row fix. */
|
|
564
566
|
& th { padding: 0; }
|
|
565
567
|
/* Same wrapper trap as AUTHORING.md Lesson 40 (ColumnCalc's summary trigger):
|
|
566
568
|
Menu wraps its trigger in a flex div that sizes to its content, so a
|
|
@@ -74,6 +74,15 @@ export type DataTableProps<T extends {
|
|
|
74
74
|
* Takes the row so the label can read back a human identifier (a name,
|
|
75
75
|
* a code) instead of the raw id. */
|
|
76
76
|
selectRowLabel?: (row: T) => string;
|
|
77
|
+
/**
|
|
78
|
+
* Announced when the selection changes. A formatter, not a string: the
|
|
79
|
+
* count moves within the sentence between languages. Return "" to say
|
|
80
|
+
* nothing. A consumer's own `<BulkBar>` — mounted only once something is
|
|
81
|
+
* selected — cannot carry this itself: its live region would be created by
|
|
82
|
+
* the very change it should announce (#234). This table's region is
|
|
83
|
+
* mounted unconditionally instead, so it outlives every selection.
|
|
84
|
+
*/
|
|
85
|
+
selectionAnnouncement?: (count: number) => string;
|
|
77
86
|
/** Controlled sort (omit for self-managed; seed with `defaultSort`). */
|
|
78
87
|
/**
|
|
79
88
|
* Active sort. Accepts a single sort or an ordered list — a table can sort by
|
|
@@ -148,7 +157,7 @@ export type DataTableProps<T extends {
|
|
|
148
157
|
};
|
|
149
158
|
export declare function DataTable<T extends {
|
|
150
159
|
id: string;
|
|
151
|
-
}>({ columns: columnsProp, data, selectable, selectedIds, onSelectionChange, selectAllLabel, selectRowLabel, columnMenu, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable, searchPlaceholder, searchLabel, onEdit, stickyFirst, avatarTone, surface, interactive, onRowClick, onAddRow, addRowLabel, empty, showCount, countLabel, toolbar, className, reorderRowLabel, ...rest }: DataTableProps<T>): React.JSX.Element;
|
|
160
|
+
}>({ columns: columnsProp, data, selectable, selectedIds, onSelectionChange, selectAllLabel, selectRowLabel, selectionAnnouncement, columnMenu, onColumnsChange, groupBy, onRowsReorder, error, sort: sortProp, defaultSort, onSortChange, filterable, searchPlaceholder, searchLabel, onEdit, stickyFirst, avatarTone, surface, interactive, onRowClick, onAddRow, addRowLabel, empty, showCount, countLabel, toolbar, className, reorderRowLabel, ...rest }: DataTableProps<T>): React.JSX.Element;
|
|
152
161
|
export declare namespace DataTable {
|
|
153
162
|
var displayName: string;
|
|
154
163
|
}
|