@multiplatform.one/table 7.28.1 → 7.29.1
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/CellContent.cjs +77 -0
- package/dist/cjs/components/DataTable/CellContent.native.js +88 -0
- package/dist/cjs/components/DataTable/CellContent.native.js.map +1 -0
- package/dist/cjs/components/DataTable/DataTableInfiniteTail.cjs +90 -0
- package/dist/cjs/components/DataTable/DataTableInfiniteTail.native.js +99 -0
- package/dist/cjs/components/DataTable/DataTableInfiniteTail.native.js.map +1 -0
- package/dist/cjs/components/DataTable/DataTableRoot.cjs +17 -47
- package/dist/cjs/components/DataTable/DataTableRoot.native.js +17 -56
- package/dist/cjs/components/DataTable/DataTableRoot.native.js.map +1 -1
- package/dist/cjs/components/DataTable/NativeInfiniteSentinel.cjs +62 -0
- package/dist/cjs/components/DataTable/NativeInfiniteSentinel.native.js +67 -0
- package/dist/cjs/components/DataTable/NativeInfiniteSentinel.native.js.map +1 -0
- package/dist/cjs/components/DataTable/index.native.js +75 -15
- package/dist/cjs/components/DataTable/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableBulkActions/index.cjs +70 -51
- package/dist/cjs/components/DataTableBulkActions/index.native.js +84 -63
- package/dist/cjs/components/DataTableBulkActions/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableCell/index.cjs +3 -1
- package/dist/cjs/components/DataTableCell/index.native.js +3 -1
- package/dist/cjs/components/DataTableCell/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableDateFilter/index.cjs +2 -1
- package/dist/cjs/components/DataTableDateFilter/index.native.js +2 -1
- package/dist/cjs/components/DataTableDateFilter/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableExport/index.cjs +2 -1
- package/dist/cjs/components/DataTableExport/index.native.js +2 -1
- package/dist/cjs/components/DataTableExport/index.native.js.map +1 -1
- package/dist/cjs/components/DataTableGrouping/index.cjs +2 -2
- package/dist/cjs/components/DataTableGrouping/index.native.js +2 -2
- package/dist/cjs/components/DataTableViewOptions/index.cjs +1 -1
- package/dist/cjs/components/DataTableViewOptions/index.native.js +1 -1
- package/dist/cjs/components/DataTableViewOptions/index.native.js.map +1 -1
- package/dist/cjs/components/KnobDialog.cjs +2 -1
- package/dist/cjs/components/KnobDialog.native.js +4 -2
- package/dist/cjs/components/KnobDialog.native.js.map +1 -1
- package/dist/cjs/components/TableInput/RowDetailEditor.cjs +79 -81
- package/dist/cjs/components/TableInput/index.cjs +20 -19
- package/dist/cjs/components/TableInput/index.native.js +1 -0
- package/dist/cjs/components/TableInput/index.native.js.map +1 -1
- package/dist/esm/components/DataTable/CellContent.mjs +52 -0
- package/dist/esm/components/DataTable/CellContent.mjs.map +1 -0
- package/dist/esm/components/DataTable/CellContent.native.js +60 -0
- package/dist/esm/components/DataTable/CellContent.native.js.map +1 -0
- package/dist/esm/components/DataTable/DataTableInfiniteTail.mjs +65 -0
- package/dist/esm/components/DataTable/DataTableInfiniteTail.mjs.map +1 -0
- package/dist/esm/components/DataTable/DataTableInfiniteTail.native.js +71 -0
- package/dist/esm/components/DataTable/DataTableInfiniteTail.native.js.map +1 -0
- package/dist/esm/components/DataTable/DataTableRoot.mjs +18 -48
- package/dist/esm/components/DataTable/DataTableRoot.mjs.map +1 -1
- package/dist/esm/components/DataTable/DataTableRoot.native.js +18 -57
- package/dist/esm/components/DataTable/DataTableRoot.native.js.map +1 -1
- package/dist/esm/components/DataTable/NativeInfiniteSentinel.mjs +36 -0
- package/dist/esm/components/DataTable/NativeInfiniteSentinel.mjs.map +1 -0
- package/dist/esm/components/DataTable/NativeInfiniteSentinel.native.js +38 -0
- package/dist/esm/components/DataTable/NativeInfiniteSentinel.native.js.map +1 -0
- package/dist/esm/components/DataTable/index.native.js +77 -17
- package/dist/esm/components/DataTable/index.native.js.map +1 -1
- package/dist/esm/components/DataTableBulkActions/index.mjs +71 -52
- package/dist/esm/components/DataTableBulkActions/index.mjs.map +1 -1
- package/dist/esm/components/DataTableBulkActions/index.native.js +85 -64
- package/dist/esm/components/DataTableBulkActions/index.native.js.map +1 -1
- package/dist/esm/components/DataTableCell/index.mjs +3 -1
- package/dist/esm/components/DataTableCell/index.mjs.map +1 -1
- package/dist/esm/components/DataTableCell/index.native.js +3 -1
- package/dist/esm/components/DataTableCell/index.native.js.map +1 -1
- package/dist/esm/components/DataTableDateFilter/index.mjs +2 -1
- package/dist/esm/components/DataTableDateFilter/index.mjs.map +1 -1
- package/dist/esm/components/DataTableDateFilter/index.native.js +2 -1
- package/dist/esm/components/DataTableDateFilter/index.native.js.map +1 -1
- package/dist/esm/components/DataTableExport/index.mjs +2 -1
- package/dist/esm/components/DataTableExport/index.mjs.map +1 -1
- package/dist/esm/components/DataTableExport/index.native.js +2 -1
- package/dist/esm/components/DataTableExport/index.native.js.map +1 -1
- package/dist/esm/components/DataTableGrouping/index.mjs +2 -2
- package/dist/esm/components/DataTableGrouping/index.native.js +2 -2
- package/dist/esm/components/DataTableViewOptions/index.mjs +2 -2
- package/dist/esm/components/DataTableViewOptions/index.mjs.map +1 -1
- package/dist/esm/components/DataTableViewOptions/index.native.js +2 -2
- package/dist/esm/components/DataTableViewOptions/index.native.js.map +1 -1
- package/dist/esm/components/KnobDialog.mjs +2 -1
- package/dist/esm/components/KnobDialog.mjs.map +1 -1
- package/dist/esm/components/KnobDialog.native.js +4 -2
- package/dist/esm/components/KnobDialog.native.js.map +1 -1
- package/dist/esm/components/TableInput/RowDetailEditor.mjs +81 -83
- package/dist/esm/components/TableInput/RowDetailEditor.mjs.map +1 -1
- package/dist/esm/components/TableInput/index.mjs +20 -19
- package/dist/esm/components/TableInput/index.mjs.map +1 -1
- package/dist/esm/components/TableInput/index.native.js +1 -0
- package/dist/esm/components/TableInput/index.native.js.map +1 -1
- package/dist/jsx/components/DataTable/CellContent.mjs +52 -0
- package/dist/jsx/components/DataTable/CellContent.mjs.map +1 -0
- package/dist/jsx/components/DataTable/CellContent.native.js +88 -0
- package/dist/jsx/components/DataTable/CellContent.native.js.map +1 -0
- package/dist/jsx/components/DataTable/DataTableInfiniteTail.mjs +65 -0
- package/dist/jsx/components/DataTable/DataTableInfiniteTail.mjs.map +1 -0
- package/dist/jsx/components/DataTable/DataTableInfiniteTail.native.js +99 -0
- package/dist/jsx/components/DataTable/DataTableInfiniteTail.native.js.map +1 -0
- package/dist/jsx/components/DataTable/DataTableRoot.mjs +18 -48
- package/dist/jsx/components/DataTable/DataTableRoot.mjs.map +1 -1
- package/dist/jsx/components/DataTable/DataTableRoot.native.js +17 -56
- package/dist/jsx/components/DataTable/DataTableRoot.native.js.map +1 -1
- package/dist/jsx/components/DataTable/NativeInfiniteSentinel.mjs +36 -0
- package/dist/jsx/components/DataTable/NativeInfiniteSentinel.mjs.map +1 -0
- package/dist/jsx/components/DataTable/NativeInfiniteSentinel.native.js +67 -0
- package/dist/jsx/components/DataTable/NativeInfiniteSentinel.native.js.map +1 -0
- package/dist/jsx/components/DataTable/index.native.js +75 -15
- package/dist/jsx/components/DataTable/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableBulkActions/index.mjs +71 -52
- package/dist/jsx/components/DataTableBulkActions/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableBulkActions/index.native.js +84 -63
- package/dist/jsx/components/DataTableBulkActions/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableCell/index.mjs +3 -1
- package/dist/jsx/components/DataTableCell/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableCell/index.native.js +3 -1
- package/dist/jsx/components/DataTableCell/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableDateFilter/index.mjs +2 -1
- package/dist/jsx/components/DataTableDateFilter/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableDateFilter/index.native.js +2 -1
- package/dist/jsx/components/DataTableDateFilter/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableExport/index.mjs +2 -1
- package/dist/jsx/components/DataTableExport/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableExport/index.native.js +2 -1
- package/dist/jsx/components/DataTableExport/index.native.js.map +1 -1
- package/dist/jsx/components/DataTableGrouping/index.mjs +2 -2
- package/dist/jsx/components/DataTableGrouping/index.native.js +2 -2
- package/dist/jsx/components/DataTableViewOptions/index.mjs +2 -2
- package/dist/jsx/components/DataTableViewOptions/index.mjs.map +1 -1
- package/dist/jsx/components/DataTableViewOptions/index.native.js +1 -1
- package/dist/jsx/components/DataTableViewOptions/index.native.js.map +1 -1
- package/dist/jsx/components/KnobDialog.mjs +2 -1
- package/dist/jsx/components/KnobDialog.mjs.map +1 -1
- package/dist/jsx/components/KnobDialog.native.js +4 -2
- package/dist/jsx/components/KnobDialog.native.js.map +1 -1
- package/dist/jsx/components/TableInput/RowDetailEditor.mjs +81 -83
- package/dist/jsx/components/TableInput/RowDetailEditor.mjs.map +1 -1
- package/dist/jsx/components/TableInput/index.mjs +20 -19
- package/dist/jsx/components/TableInput/index.mjs.map +1 -1
- package/dist/jsx/components/TableInput/index.native.js +1 -0
- package/dist/jsx/components/TableInput/index.native.js.map +1 -1
- package/package.json +12 -12
- package/src/components/ChildTable/childTable.rowDetail.spec.tsx +69 -0
- package/src/components/DataTable/CellContent.tsx +73 -0
- package/src/components/DataTable/DataTableInfiniteTail.tsx +94 -0
- package/src/components/DataTable/DataTableRoot.tsx +37 -81
- package/src/components/DataTable/NativeInfiniteSentinel.tsx +45 -0
- package/src/components/DataTable/cellWeight.native.spec.tsx +82 -0
- package/src/components/DataTable/cellWeight.spec.tsx +147 -0
- package/src/components/DataTable/index.native.tsx +108 -19
- package/src/components/DataTable/nativeRoot.spec.tsx +180 -0
- package/src/components/DataTableBulkActions/index.tsx +100 -71
- package/src/components/DataTableCell/index.tsx +3 -2
- package/src/components/DataTableDateFilter/index.tsx +2 -10
- package/src/components/DataTableExport/index.tsx +2 -1
- package/src/components/DataTableFilters/DataTableFilters.stories.tsx +7 -19
- package/src/components/DataTableGrouping/index.tsx +2 -2
- package/src/components/DataTablePagination/DataTablePagination.stories.tsx +12 -46
- package/src/components/DataTableViewOptions/index.tsx +2 -2
- package/src/components/KnobDialog.tsx +2 -0
- package/src/components/TableInput/RowDetailEditor.tsx +73 -72
- package/src/components/TableInput/index.native.tsx +1 -0
- package/src/components/TableInput/index.tsx +30 -21
- package/types/components/DataTable/CellContent.d.ts +19 -0
- package/types/components/DataTable/CellContent.d.ts.map +1 -0
- package/types/components/DataTable/DataTableInfiniteTail.d.ts +22 -0
- package/types/components/DataTable/DataTableInfiniteTail.d.ts.map +1 -0
- package/types/components/DataTable/DataTableRoot.d.ts.map +1 -1
- package/types/components/DataTable/NativeInfiniteSentinel.d.ts +17 -0
- package/types/components/DataTable/NativeInfiniteSentinel.d.ts.map +1 -0
- package/types/components/DataTable/index.native.d.ts +1 -1
- package/types/components/DataTable/index.native.d.ts.map +1 -1
- package/types/components/DataTableBulkActions/index.d.ts.map +1 -1
- package/types/components/DataTableCell/index.d.ts.map +1 -1
- package/types/components/DataTableDateFilter/index.d.ts.map +1 -1
- package/types/components/DataTableExport/index.d.ts.map +1 -1
- package/types/components/KnobDialog.d.ts.map +1 -1
- package/types/components/TableInput/RowDetailEditor.d.ts +4 -0
- package/types/components/TableInput/RowDetailEditor.d.ts.map +1 -1
- package/types/components/TableInput/index.d.ts.map +1 -1
- package/types/components/TableInput/index.native.d.ts.map +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native load-more trigger for DataTable's infinite mode.
|
|
3
|
+
*
|
|
4
|
+
* Web watches its sentinel with an IntersectionObserver. React Native has
|
|
5
|
+
* none, and the table never sees its host's scroll events: the backoffice
|
|
6
|
+
* list scrolls the whole screen in a ScrollView the table sits inside. So
|
|
7
|
+
* the sentinel asks where it is on screen, on a short interval while more
|
|
8
|
+
* pages exist, and fires once it comes within `leadPx` of the window's
|
|
9
|
+
* bottom edge, the same lead web gives its observer.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { type ComponentRef, useEffect, useRef } from "react";
|
|
13
|
+
import { Dimensions, View } from "react-native";
|
|
14
|
+
|
|
15
|
+
export const NATIVE_SENTINEL_POLL_MS = 250;
|
|
16
|
+
|
|
17
|
+
export interface NativeInfiniteSentinelProps {
|
|
18
|
+
onVisible: () => void;
|
|
19
|
+
leadPx: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function NativeInfiniteSentinel({ onVisible, leadPx }: NativeInfiniteSentinelProps) {
|
|
23
|
+
const ref = useRef<ComponentRef<typeof View>>(null);
|
|
24
|
+
const onVisibleRef = useRef(onVisible);
|
|
25
|
+
onVisibleRef.current = onVisible;
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
let active = true;
|
|
29
|
+
const timer = setInterval(() => {
|
|
30
|
+
ref.current?.measureInWindow((_x, y, width) => {
|
|
31
|
+
// An unmeasured view reports all zeros; width 0 means not laid out.
|
|
32
|
+
if (!active || width <= 0) return;
|
|
33
|
+
if (y <= Dimensions.get("window").height + leadPx) onVisibleRef.current();
|
|
34
|
+
});
|
|
35
|
+
}, NATIVE_SENTINEL_POLL_MS);
|
|
36
|
+
return () => {
|
|
37
|
+
active = false;
|
|
38
|
+
clearInterval(timer);
|
|
39
|
+
};
|
|
40
|
+
}, [leadPx]);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<View ref={ref} style={{ height: 1, width: "100%" }} aria-hidden testID="infinite-sentinel" />
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-446 table arm (native): the native root renders body cells through the
|
|
3
|
+
* same CellContent as web, so a primitive value rides house Text and takes
|
|
4
|
+
* the fontWeight and bodyFont knobs. index.native.tsx pulls in FlashList and
|
|
5
|
+
* the suite runs under happy-dom, so the root is read as source (the
|
|
6
|
+
* ./nativeCardParity.spec.tsx precedent) and CellContent renders under the
|
|
7
|
+
* native platform flags.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { resolve } from "node:path";
|
|
12
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
13
|
+
import { Preset } from "@multiplatform.one/theme";
|
|
14
|
+
import { cleanup, screen } from "@testing-library/react";
|
|
15
|
+
import { Text as RawText } from "tamagui";
|
|
16
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
17
|
+
import { CellContent } from "./CellContent";
|
|
18
|
+
|
|
19
|
+
vi.mock("@multiplatform.one/platform", async (importOriginal) => ({
|
|
20
|
+
...(await importOriginal<typeof import("@multiplatform.one/platform")>()),
|
|
21
|
+
isWeb: false,
|
|
22
|
+
isNative: true,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
afterEach(cleanup);
|
|
26
|
+
|
|
27
|
+
function classes(el: Element, prefix: string): string[] {
|
|
28
|
+
return String(el.className || "")
|
|
29
|
+
.split(" ")
|
|
30
|
+
.filter((c) => c.startsWith(prefix))
|
|
31
|
+
.sort();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function explicit(prefix: string, props: Record<string, string>): string[] {
|
|
35
|
+
renderWithProviders(<RawText {...props}>probe</RawText>);
|
|
36
|
+
const got = classes(screen.getByText("probe"), prefix);
|
|
37
|
+
cleanup();
|
|
38
|
+
return got;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe("DataTable custom cell values follow the text knobs (native, MPO-446)", () => {
|
|
42
|
+
it("really is running with the native platform flags", async () => {
|
|
43
|
+
const platform = await import("@multiplatform.one/platform");
|
|
44
|
+
expect(platform.isWeb).toBe(false);
|
|
45
|
+
expect(platform.isNative).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("the native root renders body cells through CellContent with the value voice size", () => {
|
|
49
|
+
const native = readFileSync(resolve(__dirname, "index.native.tsx"), "utf-8");
|
|
50
|
+
const start = native.indexOf("<CellContent");
|
|
51
|
+
expect(start).toBeGreaterThan(-1);
|
|
52
|
+
const site = native.slice(start, native.indexOf("/>", start));
|
|
53
|
+
expect(site).toMatch(/cellDef=\{columnDef\.cell\}/);
|
|
54
|
+
expect(site).toMatch(/fontSize=\{knobProps\.label\.fontSize/);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it.each([
|
|
58
|
+
["regular", "400"],
|
|
59
|
+
["bold", "700"],
|
|
60
|
+
] as const)("string and number values paint the knob weight at %s", (fontWeight, want) => {
|
|
61
|
+
const expected = explicit("_fow-", { fontWeight: want });
|
|
62
|
+
for (const value of ["Bulbasaur", 4461]) {
|
|
63
|
+
renderWithProviders(
|
|
64
|
+
<Preset overrides={{ fontWeight }}>
|
|
65
|
+
<CellContent cellDef={() => value} ctx={{}} fontSize="$3" />
|
|
66
|
+
</Preset>,
|
|
67
|
+
);
|
|
68
|
+
expect(classes(screen.getByText(String(value)), "_fow-"), String(value)).toEqual(expected);
|
|
69
|
+
cleanup();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("string values take the bodyFont family", () => {
|
|
74
|
+
const expected = explicit("_ff-", { fontFamily: "$mono" });
|
|
75
|
+
renderWithProviders(
|
|
76
|
+
<Preset overrides={{ bodyFont: "mono" }}>
|
|
77
|
+
<CellContent cellDef={() => "Bulbasaur"} ctx={{}} fontSize="$3" />
|
|
78
|
+
</Preset>,
|
|
79
|
+
);
|
|
80
|
+
expect(classes(screen.getByText("Bulbasaur"), "_ff-")).toEqual(expected);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-446 table arm (web): a DataTable custom cell's value takes the
|
|
3
|
+
* fontWeight and bodyFont knobs.
|
|
4
|
+
*
|
|
5
|
+
* `cell: (info) => info.getValue()` returns a primitive, and flexRender
|
|
6
|
+
* dropped it as a bare text node into the cell's alignment View: a div with
|
|
7
|
+
* no text voice, so the value painted the page's 400 under Weight bold. The
|
|
8
|
+
* value now rides house Text (./CellContent.tsx). ./cellWeight.native.spec.tsx
|
|
9
|
+
* is the native arm.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
13
|
+
import { Preset } from "@multiplatform.one/theme";
|
|
14
|
+
import { act, cleanup, screen } from "@testing-library/react";
|
|
15
|
+
import { useState, type ReactNode } from "react";
|
|
16
|
+
import { Text as RawText } from "tamagui";
|
|
17
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
18
|
+
import type { DataTableColumn } from "../../types";
|
|
19
|
+
import { CellContent } from "./CellContent";
|
|
20
|
+
import { DataTable } from "./index";
|
|
21
|
+
|
|
22
|
+
type Row = { id: number; name: string; status: string; amount: string };
|
|
23
|
+
|
|
24
|
+
const rows: Row[] = [{ id: 4461, name: "Bulbasaur", status: "sleeping", amount: "12.50" }];
|
|
25
|
+
|
|
26
|
+
const columns: DataTableColumn<Row>[] = [
|
|
27
|
+
{ id: "id", accessorKey: "id", header: "ID", cell: (info) => info.getValue() },
|
|
28
|
+
{ id: "name", accessorKey: "name", header: "Name", cell: (info) => info.getValue() },
|
|
29
|
+
{
|
|
30
|
+
id: "status",
|
|
31
|
+
accessorKey: "status",
|
|
32
|
+
header: "Status",
|
|
33
|
+
cell: (info) => <RawText fontWeight="300">{String(info.getValue())}</RawText>,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "amount",
|
|
37
|
+
accessorKey: "amount",
|
|
38
|
+
header: "Amount",
|
|
39
|
+
field: "money",
|
|
40
|
+
fieldProps: { currency: "USD", locale: "en-US" },
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const weights = [
|
|
45
|
+
["regular", "400"],
|
|
46
|
+
["bold", "700"],
|
|
47
|
+
] as const;
|
|
48
|
+
|
|
49
|
+
afterEach(cleanup);
|
|
50
|
+
|
|
51
|
+
function classes(el: Element, prefix: string): string[] {
|
|
52
|
+
return String(el.className || "")
|
|
53
|
+
.split(" ")
|
|
54
|
+
.filter((c) => c.startsWith(prefix))
|
|
55
|
+
.sort();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** The class a prop paints, read off a raw node so no house wiring is involved. */
|
|
59
|
+
function explicit(prefix: string, props: Record<string, string>): string[] {
|
|
60
|
+
renderWithProviders(<RawText {...props}>probe</RawText>);
|
|
61
|
+
const got = classes(screen.getByText("probe"), prefix);
|
|
62
|
+
cleanup();
|
|
63
|
+
return got;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function renderTable(overrides: Record<string, string>) {
|
|
67
|
+
return renderWithProviders(
|
|
68
|
+
<Preset overrides={overrides as never}>
|
|
69
|
+
<DataTable
|
|
70
|
+
data={rows}
|
|
71
|
+
columns={columns as DataTableColumn<Record<string, any>>[]}
|
|
72
|
+
layout="table"
|
|
73
|
+
enablePagination={false}
|
|
74
|
+
readOnly
|
|
75
|
+
/>
|
|
76
|
+
</Preset>,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
describe("DataTable custom cell values follow the text knobs (web, MPO-446)", () => {
|
|
81
|
+
it.each(weights)("string and number values paint the knob weight at %s", (fontWeight, want) => {
|
|
82
|
+
const expected = explicit("_fow-", { fontWeight: want });
|
|
83
|
+
renderTable({ fontWeight });
|
|
84
|
+
for (const text of ["Bulbasaur", "4461"]) {
|
|
85
|
+
const node = screen.getByText(text);
|
|
86
|
+
expect(node.closest("[data-cell-align]")).not.toBe(node);
|
|
87
|
+
expect(classes(node, "_fow-"), text).toEqual(expected);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("string values take the bodyFont family", () => {
|
|
92
|
+
const expected = explicit("_ff-", { fontFamily: "$mono" });
|
|
93
|
+
renderTable({ bodyFont: "mono" });
|
|
94
|
+
expect(classes(screen.getByText("Bulbasaur"), "_ff-")).toEqual(expected);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it.each(weights)("a money value paints the knob weight at %s", (fontWeight, want) => {
|
|
98
|
+
const expected = explicit("_fow-", { fontWeight: want });
|
|
99
|
+
renderTable({ fontWeight });
|
|
100
|
+
expect(classes(screen.getByText(/12\.50/), "_fow-")).toEqual(expected);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("a renderer that returns an element keeps its own weight", () => {
|
|
104
|
+
const expected = explicit("_fow-", { fontWeight: "300" });
|
|
105
|
+
renderTable({ fontWeight: "bold" });
|
|
106
|
+
expect(classes(screen.getByText("sleeping"), "_fow-")).toEqual(expected);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe("CellContent keeps flexRender's component identity per renderer", () => {
|
|
111
|
+
function Counter({ start }: { start: number }): ReactNode {
|
|
112
|
+
const [n, setN] = useState(start);
|
|
113
|
+
return (
|
|
114
|
+
<RawText onPress={() => setN((v) => v + 1)} data-testid="counter">
|
|
115
|
+
{n}
|
|
116
|
+
</RawText>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
it("a renderer's hook state survives a re-render with the same renderer", () => {
|
|
121
|
+
const render = (ctx: unknown) => <Counter start={(ctx as { start: number }).start} />;
|
|
122
|
+
const { rerender } = renderWithProviders(
|
|
123
|
+
<CellContent cellDef={render} ctx={{ start: 1 }} fontSize="$3" />,
|
|
124
|
+
);
|
|
125
|
+
act(() => screen.getByTestId("counter").click());
|
|
126
|
+
expect(screen.getByTestId("counter").textContent).toBe("2");
|
|
127
|
+
rerender(<CellContent cellDef={render} ctx={{ start: 1 }} fontSize="$3" />);
|
|
128
|
+
expect(screen.getByTestId("counter").textContent).toBe("2");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("a new renderer mounts its own hooks instead of reading the old renderer's slots", () => {
|
|
132
|
+
const first = () => {
|
|
133
|
+
const [label] = useState("first renderer");
|
|
134
|
+
return label;
|
|
135
|
+
};
|
|
136
|
+
const second = () => {
|
|
137
|
+
const [label] = useState("second renderer");
|
|
138
|
+
return label;
|
|
139
|
+
};
|
|
140
|
+
const { rerender } = renderWithProviders(
|
|
141
|
+
<CellContent cellDef={first} ctx={{}} fontSize="$3" />,
|
|
142
|
+
);
|
|
143
|
+
expect(screen.getByText("first renderer")).toBeInTheDocument();
|
|
144
|
+
rerender(<CellContent cellDef={second} ctx={{}} fontSize="$3" />);
|
|
145
|
+
expect(screen.getByText("second renderer")).toBeInTheDocument();
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -14,19 +14,21 @@ import {
|
|
|
14
14
|
TrashIcon,
|
|
15
15
|
} from "@phosphor-icons/react";
|
|
16
16
|
import { FlashList, type FlashListRef } from "@shopify/flash-list";
|
|
17
|
-
import { AsyncBoundary, EmptyState, useDirection } from "@multiplatform.one/components";
|
|
17
|
+
import { AsyncBoundary, EmptyState, useDirection, ScrollView } from "@multiplatform.one/components";
|
|
18
18
|
import { Button, Field, useFormField } from "@multiplatform.one/forms";
|
|
19
19
|
import { flexRender } from "@tanstack/react-table";
|
|
20
20
|
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
21
21
|
import React, { useRef, useMemo, useCallback } from "react";
|
|
22
|
-
import {
|
|
22
|
+
import type { FontSizeTokens } from "tamagui";
|
|
23
|
+
import { Text, View, useMedia, withStaticProperties } from "tamagui";
|
|
23
24
|
import { useTranslation } from "react-i18next";
|
|
24
25
|
import { useDataTable } from "../../hooks/useDataTable";
|
|
25
|
-
import type { DataTableColumn, DataTableField, SelectAllScope } from "../../types";
|
|
26
|
-
import { DEFAULT_PAGE_SIZE_OPTIONS } from "../../utils/paginationDefaults";
|
|
26
|
+
import type { BulkAction, DataTableColumn, DataTableField, SelectAllScope } from "../../types";
|
|
27
|
+
import { DEFAULT_PAGE_SIZE_OPTIONS, INFINITE_TRIGGER_ROWS } from "../../utils/paginationDefaults";
|
|
27
28
|
import { withInterp } from "../../utils/withInterp";
|
|
28
29
|
import { DataTableColumnPinning } from "../DataTableColumnPinning";
|
|
29
30
|
import { DataTablePagination } from "../DataTablePagination";
|
|
31
|
+
import { CellContent } from "./CellContent";
|
|
30
32
|
import { DataTableToolbar } from "../DataTableToolbar";
|
|
31
33
|
import { DataTableFilters } from "../DataTableFilters";
|
|
32
34
|
import { DataTableBulkActions } from "../DataTableBulkActions";
|
|
@@ -38,8 +40,10 @@ import { DataTableCell } from "../DataTableCell";
|
|
|
38
40
|
import { Table } from "@multiplatform.one/table-primitives";
|
|
39
41
|
import { DataTableContext } from "./DataTableContext";
|
|
40
42
|
import { DataTableDocumentList } from "./DataTableDocumentList";
|
|
43
|
+
import { DataTableInfiniteTail } from "./DataTableInfiniteTail";
|
|
41
44
|
import { DataTableMobileCards } from "./DataTableMobileCards";
|
|
42
45
|
import { dataTableChrome, resolveDataTableIntent, rowIntentProps } from "./dataTableChrome";
|
|
46
|
+
import { NativeInfiniteSentinel } from "./NativeInfiniteSentinel";
|
|
43
47
|
import { tableRowStateProps } from "./rowStateChrome";
|
|
44
48
|
import { DataTableStateContext } from "./DataTableStateContext";
|
|
45
49
|
import type { DataTableStateContextValue } from "./DataTableStateContext";
|
|
@@ -110,6 +114,7 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
110
114
|
data,
|
|
111
115
|
columns,
|
|
112
116
|
initialState,
|
|
117
|
+
controlledState,
|
|
113
118
|
onStateChange,
|
|
114
119
|
onRetry,
|
|
115
120
|
isLoading: isLoadingProp,
|
|
@@ -121,24 +126,32 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
121
126
|
manualPagination = false,
|
|
122
127
|
manualSorting = false,
|
|
123
128
|
enableFiltering = true,
|
|
129
|
+
filterableFields,
|
|
124
130
|
enableSorting = true,
|
|
125
131
|
enablePagination = true,
|
|
126
132
|
pageSizeOptions,
|
|
133
|
+
paginationMode = "pages",
|
|
134
|
+
loadPage,
|
|
135
|
+
rowAccumulator,
|
|
127
136
|
enableColumnVisibility = true,
|
|
128
137
|
enableColumnOrdering = false,
|
|
129
138
|
enableColumnResizing = false,
|
|
130
139
|
enableGlobalSearch = true,
|
|
131
140
|
enableViews = false,
|
|
141
|
+
columnLayout = "equal",
|
|
132
142
|
layout = "auto",
|
|
133
143
|
enableVirtualization = false,
|
|
134
144
|
virtualizationHeight,
|
|
135
145
|
virtualizationOverscan = 5,
|
|
136
146
|
enableRowExpansion = false,
|
|
137
147
|
renderSubComponent,
|
|
148
|
+
getSubRows,
|
|
138
149
|
enableRowSelection = false,
|
|
139
150
|
selectAllScope: selectAllScopeProp,
|
|
151
|
+
bulkActions,
|
|
140
152
|
enableColumnPinning = false,
|
|
141
153
|
maxPinnedColumns = 3,
|
|
154
|
+
enableGrouping = false,
|
|
142
155
|
enableKeyboardNavigation: _enableKeyboardNavigation = false,
|
|
143
156
|
onRowPress,
|
|
144
157
|
rowLabel,
|
|
@@ -184,6 +197,7 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
184
197
|
compact,
|
|
185
198
|
});
|
|
186
199
|
const chrome = dataTableChrome(String(knobProps.sizeToken));
|
|
200
|
+
const bulkBarPlacement = knobProps.bulkBarPlacement === "bottom" ? "bottom" : "top";
|
|
187
201
|
// House selectAllScope knob (DG-TBL-03): prop overrides knob; default page.
|
|
188
202
|
const selectAllScope: SelectAllScope =
|
|
189
203
|
selectAllScopeProp ?? (knobProps.selectAllScope === "filtered" ? "filtered" : "page");
|
|
@@ -202,6 +216,7 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
202
216
|
data,
|
|
203
217
|
columns,
|
|
204
218
|
initialState,
|
|
219
|
+
controlledState,
|
|
205
220
|
onStateChange,
|
|
206
221
|
syncWithUrl,
|
|
207
222
|
urlDebounceMs,
|
|
@@ -210,21 +225,28 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
210
225
|
manualPagination,
|
|
211
226
|
manualSorting,
|
|
212
227
|
enableFiltering,
|
|
228
|
+
filterableFields,
|
|
213
229
|
enableSorting,
|
|
214
230
|
enablePagination,
|
|
231
|
+
paginationMode,
|
|
232
|
+
loadPage,
|
|
233
|
+
rowAccumulator,
|
|
215
234
|
enableColumnVisibility,
|
|
216
235
|
enableColumnOrdering,
|
|
217
236
|
enableColumnResizing,
|
|
237
|
+
columnLayout,
|
|
218
238
|
enableGlobalSearch,
|
|
219
239
|
enableViews,
|
|
220
240
|
enableVirtualization,
|
|
221
241
|
virtualizationHeight,
|
|
222
242
|
virtualizationOverscan,
|
|
223
243
|
enableRowExpansion,
|
|
244
|
+
getSubRows,
|
|
224
245
|
renderSubComponent,
|
|
225
246
|
enableRowSelection,
|
|
226
247
|
enableColumnPinning,
|
|
227
248
|
maxPinnedColumns,
|
|
249
|
+
enableGrouping,
|
|
228
250
|
enableKeyboardNavigation: false,
|
|
229
251
|
rowCount,
|
|
230
252
|
pageCount,
|
|
@@ -232,6 +254,8 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
232
254
|
isFetching: isFetchingProp,
|
|
233
255
|
});
|
|
234
256
|
|
|
257
|
+
const resolvedBulkActions = (bulkActions ?? []) as BulkAction<TData>[];
|
|
258
|
+
|
|
235
259
|
const selectAllChecked =
|
|
236
260
|
enableRowSelection &&
|
|
237
261
|
(selectAllScope === "filtered"
|
|
@@ -257,12 +281,22 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
257
281
|
const cellHeight = resolvedSize === "sm" ? "$6" : resolvedSize === "lg" ? "$10" : "$8";
|
|
258
282
|
|
|
259
283
|
const headerGroups = table.getHeaderGroups();
|
|
260
|
-
const
|
|
284
|
+
const rowModelRows = table.getRowModel().rows;
|
|
285
|
+
// Infinite mode reveals accumulated pages only; loader mode's row model is
|
|
286
|
+
// already just the accumulated rows, so the slice is a no-op there.
|
|
287
|
+
const infinite = computed.infinite;
|
|
288
|
+
const tableRows = infinite ? rowModelRows.slice(0, infinite.visibleRowCount) : rowModelRows;
|
|
261
289
|
const heldRowsRef = useRef(tableRows);
|
|
262
290
|
if (tableRows.length > 0) {
|
|
263
291
|
heldRowsRef.current = tableRows;
|
|
264
292
|
}
|
|
265
|
-
const queryInFlight = Boolean(
|
|
293
|
+
const queryInFlight = Boolean(
|
|
294
|
+
state.isFetching ||
|
|
295
|
+
state.isPlaceholderData ||
|
|
296
|
+
infinite?.isAppending ||
|
|
297
|
+
state.isLoading ||
|
|
298
|
+
infinite?.isInitialLoading,
|
|
299
|
+
);
|
|
266
300
|
const displayRows =
|
|
267
301
|
tableRows.length > 0
|
|
268
302
|
? tableRows
|
|
@@ -307,6 +341,8 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
307
341
|
|
|
308
342
|
const isVirtualized =
|
|
309
343
|
enableVirtualization && virtualizationHeight != null && virtualizationHeight > 0;
|
|
344
|
+
// Only the grid virtualizes on native; list and cards render in flow.
|
|
345
|
+
const isVirtualGrid = isVirtualized && !showList && !showCards;
|
|
310
346
|
|
|
311
347
|
// DataTableColumnPinning is a hook-style helper (it calls useState/useMemo/
|
|
312
348
|
// useCallback internally), so it must run unconditionally at the top level —
|
|
@@ -369,16 +405,11 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
369
405
|
const value = cell.getValue();
|
|
370
406
|
|
|
371
407
|
if (columnDef.cell && !columnDef.field) {
|
|
372
|
-
// TanStack injects a default cell renderer that returns the raw value,
|
|
373
|
-
// and story/consumer columns commonly do `cell: (info) => info.getValue()`;
|
|
374
|
-
// raw strings/numbers outside <Text> are dropped on native. flexRender
|
|
375
|
-
// hides function-cell primitives inside an element, so NativeCellContent
|
|
376
|
-
// calls the renderer itself and wraps primitive output.
|
|
377
408
|
return (
|
|
378
|
-
<
|
|
409
|
+
<CellContent
|
|
379
410
|
cellDef={columnDef.cell}
|
|
380
411
|
ctx={cell.getContext()}
|
|
381
|
-
fontSize={knobProps.
|
|
412
|
+
fontSize={knobProps.label.fontSize as FontSizeTokens}
|
|
382
413
|
/>
|
|
383
414
|
);
|
|
384
415
|
}
|
|
@@ -398,7 +429,7 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
398
429
|
/>
|
|
399
430
|
);
|
|
400
431
|
},
|
|
401
|
-
[handleCellChange, readOnly, disabled, knobProps.
|
|
432
|
+
[handleCellChange, readOnly, disabled, knobProps.label.fontSize],
|
|
402
433
|
);
|
|
403
434
|
|
|
404
435
|
const renderRowContent = useCallback(
|
|
@@ -647,8 +678,8 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
647
678
|
};
|
|
648
679
|
|
|
649
680
|
const stateContextValue = useMemo<DataTableStateContextValue<TData>>(
|
|
650
|
-
() => ({ table, state, actions, computed }),
|
|
651
|
-
[table, state, actions, computed],
|
|
681
|
+
() => ({ table, state, actions, computed, selectAllScope }),
|
|
682
|
+
[table, state, actions, computed, selectAllScope],
|
|
652
683
|
);
|
|
653
684
|
|
|
654
685
|
const renderTableInner = useCallback(
|
|
@@ -676,7 +707,12 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
676
707
|
/>
|
|
677
708
|
);
|
|
678
709
|
}
|
|
679
|
-
if (
|
|
710
|
+
if (
|
|
711
|
+
(state.isLoading || infinite?.isInitialLoading) &&
|
|
712
|
+
displayRows.length === 0 &&
|
|
713
|
+
!state.isFetching &&
|
|
714
|
+
!state.isPlaceholderData
|
|
715
|
+
) {
|
|
680
716
|
return <AsyncBoundary loading layout="table" aria-label={ariaLabel || "Data table"} />;
|
|
681
717
|
}
|
|
682
718
|
|
|
@@ -711,6 +747,16 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
711
747
|
{renderToolbarComponent()}
|
|
712
748
|
</View>
|
|
713
749
|
)}
|
|
750
|
+
{enableRowSelection && bulkBarPlacement === "top" ? (
|
|
751
|
+
<View width="100%" {...(disabled ? disabledState.chromeKnobProps : {})}>
|
|
752
|
+
<DataTableBulkActions
|
|
753
|
+
actions={resolvedBulkActions}
|
|
754
|
+
maxVisibleActions={5}
|
|
755
|
+
showSelectionCount
|
|
756
|
+
placement="top"
|
|
757
|
+
/>
|
|
758
|
+
</View>
|
|
759
|
+
) : null}
|
|
714
760
|
{children}
|
|
715
761
|
{renderFilters?.({
|
|
716
762
|
filters: state.filters || [],
|
|
@@ -759,7 +805,7 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
759
805
|
queryInFlight={queryInFlight}
|
|
760
806
|
{...(rowPressActive ? { getRowPressProps } : {})}
|
|
761
807
|
/>
|
|
762
|
-
{enablePagination && (
|
|
808
|
+
{enablePagination && !infinite && (
|
|
763
809
|
<View width="100%" {...(disabled ? disabledState.chromeKnobProps : {})}>
|
|
764
810
|
{renderPaginationComponent()}
|
|
765
811
|
</View>
|
|
@@ -932,11 +978,19 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
932
978
|
) : isVirtualized ? (
|
|
933
979
|
<View style={{ height: virtualizationHeight }}>
|
|
934
980
|
<FlashList
|
|
981
|
+
keyboardShouldPersistTaps="handled"
|
|
935
982
|
ref={flashListRef}
|
|
936
983
|
data={displayRows}
|
|
937
984
|
drawDistance={rowHeightPx * virtualizationOverscan}
|
|
938
985
|
keyExtractor={(row) => row.id}
|
|
939
986
|
renderItem={({ item, index }) => renderRow(item, index)}
|
|
987
|
+
{...(infinite && !infinite.exhausted
|
|
988
|
+
? {
|
|
989
|
+
onEndReached: infinite.loadMore,
|
|
990
|
+
onEndReachedThreshold:
|
|
991
|
+
(INFINITE_TRIGGER_ROWS * rowHeightPx) / virtualizationHeight!,
|
|
992
|
+
}
|
|
993
|
+
: {})}
|
|
940
994
|
/>
|
|
941
995
|
</View>
|
|
942
996
|
) : (
|
|
@@ -993,6 +1047,36 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
993
1047
|
</ScrollView>
|
|
994
1048
|
)}
|
|
995
1049
|
|
|
1050
|
+
{infinite ? (
|
|
1051
|
+
<DataTableInfiniteTail
|
|
1052
|
+
infinite={infinite}
|
|
1053
|
+
visibleCount={tableRows.length}
|
|
1054
|
+
showAppendSkeleton={!isVirtualGrid}
|
|
1055
|
+
rowHeightPx={rowHeightPx}
|
|
1056
|
+
fontSize={knobProps.sizeToken}
|
|
1057
|
+
gapProps={knobProps.gap}
|
|
1058
|
+
sentinel={
|
|
1059
|
+
!isVirtualGrid && !infinite.exhausted ? (
|
|
1060
|
+
<NativeInfiniteSentinel
|
|
1061
|
+
onVisible={infinite.loadMore}
|
|
1062
|
+
leadPx={INFINITE_TRIGGER_ROWS * rowHeightPx}
|
|
1063
|
+
/>
|
|
1064
|
+
) : null
|
|
1065
|
+
}
|
|
1066
|
+
/>
|
|
1067
|
+
) : null}
|
|
1068
|
+
|
|
1069
|
+
{enableRowSelection && bulkBarPlacement === "bottom" ? (
|
|
1070
|
+
<View width="100%" {...(disabled ? disabledState.chromeKnobProps : {})}>
|
|
1071
|
+
<DataTableBulkActions
|
|
1072
|
+
actions={resolvedBulkActions}
|
|
1073
|
+
maxVisibleActions={5}
|
|
1074
|
+
showSelectionCount
|
|
1075
|
+
placement="bottom"
|
|
1076
|
+
/>
|
|
1077
|
+
</View>
|
|
1078
|
+
) : null}
|
|
1079
|
+
|
|
996
1080
|
{showAddRow && !readOnly && (
|
|
997
1081
|
<View>
|
|
998
1082
|
<Button
|
|
@@ -1006,7 +1090,7 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
1006
1090
|
</View>
|
|
1007
1091
|
)}
|
|
1008
1092
|
|
|
1009
|
-
{!showCards && enablePagination && (
|
|
1093
|
+
{!showCards && enablePagination && !infinite && (
|
|
1010
1094
|
<View width="100%" {...(disabled ? disabledState.chromeKnobProps : {})}>
|
|
1011
1095
|
{renderPaginationComponent()}
|
|
1012
1096
|
</View>
|
|
@@ -1076,6 +1160,11 @@ function DataTableRoot<TData extends Record<string, any> = Record<string, any>>(
|
|
|
1076
1160
|
deriveSelectRowLabel,
|
|
1077
1161
|
displayRows,
|
|
1078
1162
|
queryInFlight,
|
|
1163
|
+
infinite,
|
|
1164
|
+
isVirtualGrid,
|
|
1165
|
+
rowHeightPx,
|
|
1166
|
+
bulkBarPlacement,
|
|
1167
|
+
resolvedBulkActions,
|
|
1079
1168
|
t,
|
|
1080
1169
|
],
|
|
1081
1170
|
);
|