@stackframe/dashboard-ui-components 2.8.89 → 2.8.91
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/components/button.d.ts +4 -4
- package/dist/components/data-grid/data-grid-sizing.d.ts +6 -5
- package/dist/components/data-grid/data-grid-sizing.d.ts.map +1 -1
- package/dist/components/data-grid/data-grid-sizing.js +9 -28
- package/dist/components/data-grid/data-grid-sizing.js.map +1 -1
- package/dist/components/data-grid/data-grid.d.ts +17 -237
- package/dist/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/components/data-grid/data-grid.js +377 -523
- package/dist/components/data-grid/data-grid.js.map +1 -1
- package/dist/components/data-grid/data-grid.test.js +82 -0
- package/dist/components/data-grid/data-grid.test.js.map +1 -1
- package/dist/components/data-grid/index.d.ts +4 -3
- package/dist/components/data-grid/index.js +17 -58
- package/dist/components/data-grid/state.d.ts +4 -61
- package/dist/components/data-grid/state.d.ts.map +1 -1
- package/dist/components/data-grid/state.js +13 -160
- package/dist/components/data-grid/state.js.map +1 -1
- package/dist/components/data-grid/types.d.ts +9 -4
- package/dist/components/data-grid/types.d.ts.map +1 -1
- package/dist/components/data-grid/use-url-state.d.ts +38 -0
- package/dist/components/data-grid/use-url-state.d.ts.map +1 -0
- package/dist/components/data-grid/use-url-state.js +214 -0
- package/dist/components/data-grid/use-url-state.js.map +1 -0
- package/dist/components/data-grid/use-url-state.test.d.ts +1 -0
- package/dist/components/data-grid/use-url-state.test.js +91 -0
- package/dist/components/data-grid/use-url-state.test.js.map +1 -0
- package/dist/components/dialog.d.ts +67 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/dialog.js +94 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/dashboard-ui-components.global.js +10648 -6394
- package/dist/dashboard-ui-components.global.js.map +4 -4
- package/dist/esm/components/button.d.ts +4 -4
- package/dist/esm/components/data-grid/data-grid-sizing.d.ts +6 -5
- package/dist/esm/components/data-grid/data-grid-sizing.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid-sizing.js +7 -26
- package/dist/esm/components/data-grid/data-grid-sizing.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.d.ts +17 -237
- package/dist/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid.js +380 -526
- package/dist/esm/components/data-grid/data-grid.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.test.js +82 -0
- package/dist/esm/components/data-grid/data-grid.test.js.map +1 -1
- package/dist/esm/components/data-grid/index.d.ts +4 -3
- package/dist/esm/components/data-grid/index.js +4 -3
- package/dist/esm/components/data-grid/state.d.ts +4 -61
- package/dist/esm/components/data-grid/state.d.ts.map +1 -1
- package/dist/esm/components/data-grid/state.js +15 -150
- package/dist/esm/components/data-grid/state.js.map +1 -1
- package/dist/esm/components/data-grid/types.d.ts +9 -4
- package/dist/esm/components/data-grid/types.d.ts.map +1 -1
- package/dist/esm/components/data-grid/use-url-state.d.ts +38 -0
- package/dist/esm/components/data-grid/use-url-state.d.ts.map +1 -0
- package/dist/esm/components/data-grid/use-url-state.js +212 -0
- package/dist/esm/components/data-grid/use-url-state.js.map +1 -0
- package/dist/esm/components/data-grid/use-url-state.test.d.ts +1 -0
- package/dist/esm/components/data-grid/use-url-state.test.js +91 -0
- package/dist/esm/components/data-grid/use-url-state.test.js.map +1 -0
- package/dist/esm/components/dialog.d.ts +67 -0
- package/dist/esm/components/dialog.d.ts.map +1 -0
- package/dist/esm/components/dialog.js +86 -0
- package/dist/esm/components/dialog.js.map +1 -0
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +2 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +37 -0
- package/package.json +4 -3
|
@@ -1,83 +1,26 @@
|
|
|
1
|
-
import { DataGridColumnDef, DataGridDateDisplay, DataGridDateFormat, DataGridPaginationModel,
|
|
1
|
+
import { DataGridColumnDef, DataGridDateDisplay, DataGridDateFormat, DataGridPaginationModel, DataGridSortModel, DataGridState } from "./types";
|
|
2
2
|
|
|
3
3
|
//#region src/components/data-grid/state.d.ts
|
|
4
|
-
declare const EMPTY_SORT_MODEL: DataGridSortModel;
|
|
5
|
-
declare const EMPTY_SELECTION: DataGridSelectionModel;
|
|
6
|
-
declare const DEFAULT_PAGINATION: DataGridPaginationModel;
|
|
7
4
|
/**
|
|
8
5
|
* Build the initial `DataGridState` for a set of columns. Pass this as the
|
|
9
|
-
* lazy initializer to `useState` —
|
|
6
|
+
* lazy initializer to `useState` — never hand-assemble the state object.
|
|
10
7
|
*
|
|
11
8
|
* ```tsx
|
|
12
9
|
* const [gridState, setGridState] = React.useState(() =>
|
|
13
10
|
* createDefaultDataGridState(columns)
|
|
14
11
|
* );
|
|
15
12
|
* ```
|
|
16
|
-
*
|
|
17
|
-
* `columns` must be defined BEFORE this call (obvious, but a common TDZ
|
|
18
|
-
* mistake: if you declare columns after the `useState`, you'll crash on
|
|
19
|
-
* the first render). Keep the columns reference stable across renders
|
|
20
|
-
* (define them outside the component or wrap in `React.useMemo`).
|
|
21
13
|
*/
|
|
22
14
|
declare function createDefaultDataGridState(columns: readonly DataGridColumnDef<any>[]): DataGridState;
|
|
23
15
|
declare function resolveColumnValue<TRow>(col: DataGridColumnDef<TRow>, row: TRow): unknown;
|
|
24
|
-
declare function resolveColumnWidth(col: DataGridColumnDef<any>, storedWidth: number | undefined): number;
|
|
25
|
-
declare function isColumnVisible(columnId: string, visibility: Record<string, boolean>): boolean;
|
|
26
|
-
declare function toggleSort(model: DataGridSortModel, columnId: string, multiSort: boolean): DataGridSortModel;
|
|
27
|
-
declare function getSortDirection(model: DataGridSortModel, columnId: string): false | "asc" | "desc";
|
|
28
|
-
declare function getSortIndex(model: DataGridSortModel, columnId: string): number | null;
|
|
29
16
|
declare function buildRowComparator<TRow>(sortModel: DataGridSortModel, columns: readonly DataGridColumnDef<TRow>[]): ((a: TRow, b: TRow) => number) | null;
|
|
30
17
|
declare function paginateRows<TRow>(rows: readonly TRow[], pagination: DataGridPaginationModel): TRow[];
|
|
31
|
-
|
|
32
|
-
declare function toggleRowSelection(selection: DataGridSelectionModel, rowId: string, mode: "single" | "multiple", shiftKey: boolean, ctrlKey: boolean, allRowIds: readonly string[]): DataGridSelectionModel;
|
|
33
|
-
declare function selectAll(allRowIds: readonly string[]): DataGridSelectionModel;
|
|
34
|
-
declare function clearSelection(): DataGridSelectionModel;
|
|
35
|
-
/** Default row matcher used by `applyQuickSearch`. Case-insensitive
|
|
36
|
-
* substring match across every column's resolved cell value. Columns
|
|
37
|
-
* with `null` / `undefined` values are skipped. The query is expected
|
|
38
|
-
* to be pre-trimmed and lowercased by `applyQuickSearch` — this helper
|
|
39
|
-
* does NOT trim or lowercase it again, so if you wire it up yourself,
|
|
40
|
-
* do that first. */
|
|
18
|
+
/** Default row matcher: case-insensitive substring across every column. */
|
|
41
19
|
declare function defaultMatchRow<TRow>(row: TRow, query: string, columns: readonly DataGridColumnDef<TRow>[]): boolean;
|
|
42
|
-
/** Client-side quick-search filter. Returns the original array
|
|
43
|
-
* reference when `query` is empty, so calling this in a hot `useMemo`
|
|
44
|
-
* is cheap in the common "no search" case.
|
|
45
|
-
*
|
|
46
|
-
* Used by `useDataSource` in client mode. Exported so consumers driving
|
|
47
|
-
* the grid manually (or doing their own pre-filtering before feeding
|
|
48
|
-
* rows to an async data source) can stay consistent with the built-in
|
|
49
|
-
* search behaviour.
|
|
50
|
-
*
|
|
51
|
-
* Override `matchRow` for custom matching logic — e.g. fuzzy matching,
|
|
52
|
-
* field-specific weighting, or skipping some columns. */
|
|
53
20
|
declare function applyQuickSearch<TRow>(rows: readonly TRow[], query: string, columns: readonly DataGridColumnDef<TRow>[], matchRow?: (row: TRow, query: string, columns: readonly DataGridColumnDef<TRow>[]) => boolean): readonly TRow[];
|
|
54
|
-
/** Parse a raw cell value into a `Date`. Returns `null` for nullish,
|
|
55
|
-
* unparseable, or invalid dates. Accepts strings (including ISO and
|
|
56
|
-
* "YYYY-MM-DD HH:MM:SS"-style ClickHouse output), numbers (ms since
|
|
57
|
-
* epoch), and `Date` instances. For truly weird formats, override via
|
|
58
|
-
* `col.parseValue`. */
|
|
59
21
|
declare function defaultParseDate(value: unknown): Date | null;
|
|
60
|
-
/** Default relative formatter — "1 day ago" / "in 2 hours" via
|
|
61
|
-
* `Intl.RelativeTimeFormat`. Pure function of the date; does NOT
|
|
62
|
-
* re-render as real time passes. */
|
|
63
22
|
declare function defaultFormatRelative(date: Date): string;
|
|
64
|
-
/** Default absolute formatter — full locale date + time. */
|
|
65
23
|
declare function defaultFormatAbsolute(date: Date): string;
|
|
66
|
-
/** Format a raw cell value for display in a `date` / `dateTime` column.
|
|
67
|
-
* Returns both the inline display string and the tooltip string (which
|
|
68
|
-
* is always the absolute form so users can read the exact datetime).
|
|
69
|
-
*
|
|
70
|
-
* Used internally by the grid's default date cell renderer, and exported
|
|
71
|
-
* so consumers writing a custom `renderCell` for a date column can stay
|
|
72
|
-
* visually consistent with the built-in behaviour.
|
|
73
|
-
*
|
|
74
|
-
* ```tsx
|
|
75
|
-
* renderCell: ({ value, dateDisplay }) => {
|
|
76
|
-
* const { display, tooltip } = formatGridDate(value, dateDisplay);
|
|
77
|
-
* if (!display) return <span className="text-muted-foreground/40">—</span>;
|
|
78
|
-
* return <span title={tooltip ?? undefined}>{display}</span>;
|
|
79
|
-
* }
|
|
80
|
-
* ``` */
|
|
81
24
|
declare function formatGridDate(value: unknown, mode: DataGridDateDisplay, opts?: {
|
|
82
25
|
parseValue?: (value: unknown) => Date | null;
|
|
83
26
|
dateFormat?: DataGridDateFormat;
|
|
@@ -87,5 +30,5 @@ declare function formatGridDate(value: unknown, mode: DataGridDateDisplay, opts?
|
|
|
87
30
|
};
|
|
88
31
|
declare function exportToCsv<TRow>(rows: readonly TRow[], columns: readonly DataGridColumnDef<TRow>[], filename: string): void;
|
|
89
32
|
//#endregion
|
|
90
|
-
export {
|
|
33
|
+
export { applyQuickSearch, buildRowComparator, createDefaultDataGridState, defaultFormatAbsolute, defaultFormatRelative, defaultMatchRow, defaultParseDate, exportToCsv, formatGridDate, paginateRows, resolveColumnValue };
|
|
91
34
|
//# sourceMappingURL=state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","names":[],"sources":["../../../../src/components/data-grid/state.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"state.d.ts","names":[],"sources":["../../../../src/components/data-grid/state.ts"],"mappings":";;;;;AAqBA;;;;;;;;iBAAgB,0BAAA,CACd,OAAA,WAAkB,iBAAA,UACjB,aAAA;AAAA,iBAwBa,kBAAA,MAAA,CACd,GAAA,EAAK,iBAAA,CAAkB,IAAA,GACvB,GAAA,EAAK,IAAA;AAAA,iBAkBS,kBAAA,MAAA,CACd,SAAA,EAAW,iBAAA,EACX,OAAA,WAAkB,iBAAA,CAAkB,IAAA,QACjC,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,IAAA;AAAA,iBAkBD,YAAA,MAAA,CACd,IAAA,WAAe,IAAA,IACf,UAAA,EAAY,uBAAA,GACX,IAAA;;iBAQa,eAAA,MAAA,CACd,GAAA,EAAK,IAAA,EACL,KAAA,UACA,OAAA,WAAkB,iBAAA,CAAkB,IAAA;AAAA,iBAUtB,gBAAA,MAAA,CACd,IAAA,WAAe,IAAA,IACf,KAAA,UACA,OAAA,WAAkB,iBAAA,CAAkB,IAAA,KACpC,QAAA,IACE,GAAA,EAAK,IAAA,EACL,KAAA,UACA,OAAA,WAAkB,iBAAA,CAAkB,IAAA,2BAE5B,IAAA;AAAA,iBAQI,gBAAA,CAAiB,KAAA,YAAiB,IAAA;AAAA,iBA+BlC,qBAAA,CAAsB,IAAA,EAAM,IAAA;AAAA,iBAY5B,qBAAA,CAAsB,IAAA,EAAM,IAAA;AAAA,iBAI5B,cAAA,CACd,KAAA,WACA,IAAA,EAAM,mBAAA,EACN,IAAA;EACE,UAAA,IAAc,KAAA,cAAmB,IAAA;EACjC,UAAA,GAAa,kBAAA;AAAA;EAEZ,OAAA;EAAwB,OAAA;AAAA;AAAA,iBAab,WAAA,MAAA,CACd,IAAA,WAAe,IAAA,IACf,OAAA,WAAkB,iBAAA,CAAkB,IAAA,KACpC,QAAA"}
|
|
@@ -1,41 +1,26 @@
|
|
|
1
|
-
import { clampColumnWidth } from "./data-grid-sizing.js";
|
|
1
|
+
import { DEFAULT_COL_WIDTH, clampColumnWidth } from "./data-grid-sizing.js";
|
|
2
2
|
import { stringCompare } from "@stackframe/stack-shared/dist/utils/strings";
|
|
3
3
|
|
|
4
4
|
//#region src/components/data-grid/state.ts
|
|
5
|
-
const EMPTY_SORT_MODEL = [];
|
|
6
|
-
const EMPTY_SELECTION = {
|
|
7
|
-
selectedIds: /* @__PURE__ */ new Set(),
|
|
8
|
-
anchorId: null
|
|
9
|
-
};
|
|
10
|
-
const DEFAULT_PAGINATION = {
|
|
11
|
-
pageIndex: 0,
|
|
12
|
-
pageSize: 50
|
|
13
|
-
};
|
|
14
5
|
/**
|
|
15
6
|
* Build the initial `DataGridState` for a set of columns. Pass this as the
|
|
16
|
-
* lazy initializer to `useState` —
|
|
7
|
+
* lazy initializer to `useState` — never hand-assemble the state object.
|
|
17
8
|
*
|
|
18
9
|
* ```tsx
|
|
19
10
|
* const [gridState, setGridState] = React.useState(() =>
|
|
20
11
|
* createDefaultDataGridState(columns)
|
|
21
12
|
* );
|
|
22
13
|
* ```
|
|
23
|
-
*
|
|
24
|
-
* `columns` must be defined BEFORE this call (obvious, but a common TDZ
|
|
25
|
-
* mistake: if you declare columns after the `useState`, you'll crash on
|
|
26
|
-
* the first render). Keep the columns reference stable across renders
|
|
27
|
-
* (define them outside the component or wrap in `React.useMemo`).
|
|
28
14
|
*/
|
|
29
15
|
function createDefaultDataGridState(columns) {
|
|
30
16
|
const columnWidths = {};
|
|
31
17
|
const columnOrder = [];
|
|
32
18
|
for (const col of columns) {
|
|
33
|
-
|
|
34
|
-
columnWidths[col.id] = clampColumnWidth(col, raw);
|
|
19
|
+
columnWidths[col.id] = clampColumnWidth(col, col.width ?? DEFAULT_COL_WIDTH);
|
|
35
20
|
columnOrder.push(col.id);
|
|
36
21
|
}
|
|
37
22
|
return {
|
|
38
|
-
sorting:
|
|
23
|
+
sorting: [],
|
|
39
24
|
columnVisibility: {},
|
|
40
25
|
columnWidths,
|
|
41
26
|
columnPinning: {
|
|
@@ -43,8 +28,14 @@ function createDefaultDataGridState(columns) {
|
|
|
43
28
|
right: []
|
|
44
29
|
},
|
|
45
30
|
columnOrder,
|
|
46
|
-
pagination:
|
|
47
|
-
|
|
31
|
+
pagination: {
|
|
32
|
+
pageIndex: 0,
|
|
33
|
+
pageSize: 50
|
|
34
|
+
},
|
|
35
|
+
selection: {
|
|
36
|
+
selectedIds: /* @__PURE__ */ new Set(),
|
|
37
|
+
anchorId: null
|
|
38
|
+
},
|
|
48
39
|
dateDisplay: "relative",
|
|
49
40
|
quickSearch: ""
|
|
50
41
|
};
|
|
@@ -53,39 +44,6 @@ function resolveColumnValue(col, row) {
|
|
|
53
44
|
if (typeof col.accessor === "function") return col.accessor(row);
|
|
54
45
|
return row[col.accessor ?? col.id];
|
|
55
46
|
}
|
|
56
|
-
function resolveColumnWidth(col, storedWidth) {
|
|
57
|
-
return clampColumnWidth(col, storedWidth ?? col.width ?? 150);
|
|
58
|
-
}
|
|
59
|
-
function isColumnVisible(columnId, visibility) {
|
|
60
|
-
return visibility[columnId] !== false;
|
|
61
|
-
}
|
|
62
|
-
function toggleSort(model, columnId, multiSort) {
|
|
63
|
-
const existing = model.find((s) => s.columnId === columnId);
|
|
64
|
-
if (!existing) {
|
|
65
|
-
const item = {
|
|
66
|
-
columnId,
|
|
67
|
-
direction: "asc"
|
|
68
|
-
};
|
|
69
|
-
return multiSort ? [...model, item] : [item];
|
|
70
|
-
}
|
|
71
|
-
if (existing.direction === "asc") {
|
|
72
|
-
const updated = {
|
|
73
|
-
columnId,
|
|
74
|
-
direction: "desc"
|
|
75
|
-
};
|
|
76
|
-
return model.map((s) => s.columnId === columnId ? updated : s);
|
|
77
|
-
}
|
|
78
|
-
return model.filter((s) => s.columnId !== columnId);
|
|
79
|
-
}
|
|
80
|
-
function getSortDirection(model, columnId) {
|
|
81
|
-
const item = model.find((s) => s.columnId === columnId);
|
|
82
|
-
return item ? item.direction : false;
|
|
83
|
-
}
|
|
84
|
-
function getSortIndex(model, columnId) {
|
|
85
|
-
if (model.length <= 1) return null;
|
|
86
|
-
const idx = model.findIndex((s) => s.columnId === columnId);
|
|
87
|
-
return idx >= 0 ? idx + 1 : null;
|
|
88
|
-
}
|
|
89
47
|
function defaultComparator(a, b) {
|
|
90
48
|
if (a == null && b == null) return 0;
|
|
91
49
|
if (a == null) return -1;
|
|
@@ -113,61 +71,7 @@ function paginateRows(rows, pagination) {
|
|
|
113
71
|
const start = pagination.pageIndex * pagination.pageSize;
|
|
114
72
|
return rows.slice(start, start + pagination.pageSize);
|
|
115
73
|
}
|
|
116
|
-
|
|
117
|
-
return Math.max(1, Math.ceil(totalRows / pageSize));
|
|
118
|
-
}
|
|
119
|
-
function toggleRowSelection(selection, rowId, mode, shiftKey, ctrlKey, allRowIds) {
|
|
120
|
-
if (mode === "single") {
|
|
121
|
-
const isSelected = selection.selectedIds.has(rowId);
|
|
122
|
-
return {
|
|
123
|
-
selectedIds: isSelected ? /* @__PURE__ */ new Set() : new Set([rowId]),
|
|
124
|
-
anchorId: isSelected ? null : rowId
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
if (shiftKey && selection.anchorId != null) {
|
|
128
|
-
const anchorIdx = allRowIds.indexOf(selection.anchorId);
|
|
129
|
-
const currentIdx = allRowIds.indexOf(rowId);
|
|
130
|
-
if (anchorIdx >= 0 && currentIdx >= 0) {
|
|
131
|
-
const start = Math.min(anchorIdx, currentIdx);
|
|
132
|
-
const end = Math.max(anchorIdx, currentIdx);
|
|
133
|
-
const rangeIds = allRowIds.slice(start, end + 1);
|
|
134
|
-
const next = ctrlKey ? new Set(selection.selectedIds) : /* @__PURE__ */ new Set();
|
|
135
|
-
for (const id of rangeIds) next.add(id);
|
|
136
|
-
return {
|
|
137
|
-
selectedIds: next,
|
|
138
|
-
anchorId: selection.anchorId
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (ctrlKey) {
|
|
143
|
-
const next = new Set(selection.selectedIds);
|
|
144
|
-
if (next.has(rowId)) next.delete(rowId);
|
|
145
|
-
else next.add(rowId);
|
|
146
|
-
return {
|
|
147
|
-
selectedIds: next,
|
|
148
|
-
anchorId: rowId
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
return {
|
|
152
|
-
selectedIds: new Set([rowId]),
|
|
153
|
-
anchorId: rowId
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
function selectAll(allRowIds) {
|
|
157
|
-
return {
|
|
158
|
-
selectedIds: new Set(allRowIds),
|
|
159
|
-
anchorId: null
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
function clearSelection() {
|
|
163
|
-
return EMPTY_SELECTION;
|
|
164
|
-
}
|
|
165
|
-
/** Default row matcher used by `applyQuickSearch`. Case-insensitive
|
|
166
|
-
* substring match across every column's resolved cell value. Columns
|
|
167
|
-
* with `null` / `undefined` values are skipped. The query is expected
|
|
168
|
-
* to be pre-trimmed and lowercased by `applyQuickSearch` — this helper
|
|
169
|
-
* does NOT trim or lowercase it again, so if you wire it up yourself,
|
|
170
|
-
* do that first. */
|
|
74
|
+
/** Default row matcher: case-insensitive substring across every column. */
|
|
171
75
|
function defaultMatchRow(row, query, columns) {
|
|
172
76
|
for (const col of columns) {
|
|
173
77
|
const v = resolveColumnValue(col, row);
|
|
@@ -176,35 +80,15 @@ function defaultMatchRow(row, query, columns) {
|
|
|
176
80
|
}
|
|
177
81
|
return false;
|
|
178
82
|
}
|
|
179
|
-
/** Client-side quick-search filter. Returns the original array
|
|
180
|
-
* reference when `query` is empty, so calling this in a hot `useMemo`
|
|
181
|
-
* is cheap in the common "no search" case.
|
|
182
|
-
*
|
|
183
|
-
* Used by `useDataSource` in client mode. Exported so consumers driving
|
|
184
|
-
* the grid manually (or doing their own pre-filtering before feeding
|
|
185
|
-
* rows to an async data source) can stay consistent with the built-in
|
|
186
|
-
* search behaviour.
|
|
187
|
-
*
|
|
188
|
-
* Override `matchRow` for custom matching logic — e.g. fuzzy matching,
|
|
189
|
-
* field-specific weighting, or skipping some columns. */
|
|
190
83
|
function applyQuickSearch(rows, query, columns, matchRow = defaultMatchRow) {
|
|
191
84
|
const trimmed = query.trim().toLowerCase();
|
|
192
85
|
if (!trimmed) return rows;
|
|
193
86
|
return rows.filter((r) => matchRow(r, trimmed, columns));
|
|
194
87
|
}
|
|
195
|
-
/** Parse a raw cell value into a `Date`. Returns `null` for nullish,
|
|
196
|
-
* unparseable, or invalid dates. Accepts strings (including ISO and
|
|
197
|
-
* "YYYY-MM-DD HH:MM:SS"-style ClickHouse output), numbers (ms since
|
|
198
|
-
* epoch), and `Date` instances. For truly weird formats, override via
|
|
199
|
-
* `col.parseValue`. */
|
|
200
88
|
function defaultParseDate(value) {
|
|
201
89
|
if (value == null) return null;
|
|
202
90
|
if (value instanceof Date) return isNaN(value.getTime()) ? null : value;
|
|
203
|
-
if (typeof value === "number") {
|
|
204
|
-
const d = new Date(value);
|
|
205
|
-
return isNaN(d.getTime()) ? null : d;
|
|
206
|
-
}
|
|
207
|
-
if (typeof value === "string") {
|
|
91
|
+
if (typeof value === "number" || typeof value === "string") {
|
|
208
92
|
const d = new Date(value);
|
|
209
93
|
return isNaN(d.getTime()) ? null : d;
|
|
210
94
|
}
|
|
@@ -250,9 +134,6 @@ function getRelativeTimeFormatter(locale) {
|
|
|
250
134
|
}
|
|
251
135
|
return cached;
|
|
252
136
|
}
|
|
253
|
-
/** Default relative formatter — "1 day ago" / "in 2 hours" via
|
|
254
|
-
* `Intl.RelativeTimeFormat`. Pure function of the date; does NOT
|
|
255
|
-
* re-render as real time passes. */
|
|
256
137
|
function defaultFormatRelative(date) {
|
|
257
138
|
const rtf = getRelativeTimeFormatter();
|
|
258
139
|
let duration = (date.getTime() - Date.now()) / 1e3;
|
|
@@ -262,25 +143,9 @@ function defaultFormatRelative(date) {
|
|
|
262
143
|
}
|
|
263
144
|
return rtf.format(Math.round(duration), "year");
|
|
264
145
|
}
|
|
265
|
-
/** Default absolute formatter — full locale date + time. */
|
|
266
146
|
function defaultFormatAbsolute(date) {
|
|
267
147
|
return date.toLocaleString();
|
|
268
148
|
}
|
|
269
|
-
/** Format a raw cell value for display in a `date` / `dateTime` column.
|
|
270
|
-
* Returns both the inline display string and the tooltip string (which
|
|
271
|
-
* is always the absolute form so users can read the exact datetime).
|
|
272
|
-
*
|
|
273
|
-
* Used internally by the grid's default date cell renderer, and exported
|
|
274
|
-
* so consumers writing a custom `renderCell` for a date column can stay
|
|
275
|
-
* visually consistent with the built-in behaviour.
|
|
276
|
-
*
|
|
277
|
-
* ```tsx
|
|
278
|
-
* renderCell: ({ value, dateDisplay }) => {
|
|
279
|
-
* const { display, tooltip } = formatGridDate(value, dateDisplay);
|
|
280
|
-
* if (!display) return <span className="text-muted-foreground/40">—</span>;
|
|
281
|
-
* return <span title={tooltip ?? undefined}>{display}</span>;
|
|
282
|
-
* }
|
|
283
|
-
* ``` */
|
|
284
149
|
function formatGridDate(value, mode, opts) {
|
|
285
150
|
const date = (opts?.parseValue ?? defaultParseDate)(value);
|
|
286
151
|
if (!date) return {
|
|
@@ -318,5 +183,5 @@ function exportToCsv(rows, columns, filename) {
|
|
|
318
183
|
}
|
|
319
184
|
|
|
320
185
|
//#endregion
|
|
321
|
-
export {
|
|
186
|
+
export { applyQuickSearch, buildRowComparator, createDefaultDataGridState, defaultFormatAbsolute, defaultFormatRelative, defaultMatchRow, defaultParseDate, exportToCsv, formatGridDate, paginateRows, resolveColumnValue };
|
|
322
187
|
//# sourceMappingURL=state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","names":[],"sources":["../../../../src/components/data-grid/state.ts"],"sourcesContent":["import { stringCompare } from \"@stackframe/stack-shared/dist/utils/strings\";\nimport { clampColumnWidth } from \"./data-grid-sizing\";\nimport type {\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridDateFormat,\n DataGridPaginationModel,\n DataGridSelectionModel,\n DataGridSortModel,\n DataGridState,\n} from \"./types\";\n\n// ─── Default state ───────────────────────────────────────────────────\n\nexport const EMPTY_SORT_MODEL: DataGridSortModel = [];\nexport const EMPTY_SELECTION: DataGridSelectionModel = {\n selectedIds: new Set(),\n anchorId: null,\n};\nexport const DEFAULT_PAGINATION: DataGridPaginationModel = {\n pageIndex: 0,\n pageSize: 50,\n};\n\n/**\n * Build the initial `DataGridState` for a set of columns. Pass this as the\n * lazy initializer to `useState` — NEVER hand-assemble the state object.\n *\n * ```tsx\n * const [gridState, setGridState] = React.useState(() =>\n * createDefaultDataGridState(columns)\n * );\n * ```\n *\n * `columns` must be defined BEFORE this call (obvious, but a common TDZ\n * mistake: if you declare columns after the `useState`, you'll crash on\n * the first render). Keep the columns reference stable across renders\n * (define them outside the component or wrap in `React.useMemo`).\n */\nexport function createDefaultDataGridState(\n columns: readonly DataGridColumnDef<any>[],\n): DataGridState {\n const columnWidths: Record<string, number> = {};\n const columnOrder: string[] = [];\n\n for (const col of columns) {\n const raw = col.width ?? 150;\n columnWidths[col.id] = clampColumnWidth(col, raw);\n columnOrder.push(col.id);\n }\n\n return {\n sorting: EMPTY_SORT_MODEL,\n columnVisibility: {},\n columnWidths,\n columnPinning: { left: [], right: [] },\n columnOrder,\n pagination: DEFAULT_PAGINATION,\n selection: EMPTY_SELECTION,\n dateDisplay: \"relative\",\n quickSearch: \"\",\n };\n}\n\n// ─── Column helpers ──────────────────────────────────────────────────\n\nexport function resolveColumnValue<TRow>(\n col: DataGridColumnDef<TRow>,\n row: TRow,\n): unknown {\n if (typeof col.accessor === \"function\") return col.accessor(row);\n const key = (col.accessor ?? col.id) as keyof TRow;\n return row[key];\n}\n\nexport function resolveColumnWidth(\n col: DataGridColumnDef<any>,\n storedWidth: number | undefined,\n): number {\n const raw = storedWidth ?? col.width ?? 150;\n return clampColumnWidth(col, raw);\n}\n\nexport function isColumnVisible(\n columnId: string,\n visibility: Record<string, boolean>,\n): boolean {\n return visibility[columnId] !== false;\n}\n\n// ─── Sort helpers ────────────────────────────────────────────────────\n\nexport function toggleSort(\n model: DataGridSortModel,\n columnId: string,\n multiSort: boolean,\n): DataGridSortModel {\n const existing = model.find((s) => s.columnId === columnId);\n\n if (!existing) {\n const item = { columnId, direction: \"asc\" as const };\n return multiSort ? [...model, item] : [item];\n }\n\n if (existing.direction === \"asc\") {\n const updated = { columnId, direction: \"desc\" as const };\n return model.map((s) => (s.columnId === columnId ? updated : s));\n }\n\n // desc → remove\n return model.filter((s) => s.columnId !== columnId);\n}\n\nexport function getSortDirection(\n model: DataGridSortModel,\n columnId: string,\n): false | \"asc\" | \"desc\" {\n const item = model.find((s) => s.columnId === columnId);\n return item ? item.direction : false;\n}\n\nexport function getSortIndex(\n model: DataGridSortModel,\n columnId: string,\n): number | null {\n if (model.length <= 1) return null;\n const idx = model.findIndex((s) => s.columnId === columnId);\n return idx >= 0 ? idx + 1 : null;\n}\n\n// ─── Default sort comparator ─────────────────────────────────────────\n\nfunction defaultComparator(a: unknown, b: unknown): number {\n if (a == null && b == null) return 0;\n if (a == null) return -1;\n if (b == null) return 1;\n\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n return stringCompare(String(a), String(b));\n}\n\nexport function buildRowComparator<TRow>(\n sortModel: DataGridSortModel,\n columns: readonly DataGridColumnDef<TRow>[],\n): ((a: TRow, b: TRow) => number) | null {\n if (sortModel.length === 0) return null;\n\n const colMap = new Map(columns.map((c) => [c.id, c]));\n\n return (a, b) => {\n for (const { columnId, direction } of sortModel) {\n const col = colMap.get(columnId);\n if (!col) continue;\n\n const va = resolveColumnValue(col, a);\n const vb = resolveColumnValue(col, b);\n const cmp = col.sortComparator\n ? col.sortComparator(va, vb)\n : defaultComparator(va, vb);\n if (cmp !== 0) return direction === \"asc\" ? cmp : -cmp;\n }\n return 0;\n };\n}\n\n// ─── Pagination helpers ──────────────────────────────────────────────\n\nexport function paginateRows<TRow>(\n rows: readonly TRow[],\n pagination: DataGridPaginationModel,\n): TRow[] {\n const start = pagination.pageIndex * pagination.pageSize;\n return rows.slice(start, start + pagination.pageSize) as TRow[];\n}\n\nexport function getTotalPages(\n totalRows: number,\n pageSize: number,\n): number {\n return Math.max(1, Math.ceil(totalRows / pageSize));\n}\n\n// ─── Selection helpers ───────────────────────────────────────────────\n\nexport function toggleRowSelection(\n selection: DataGridSelectionModel,\n rowId: string,\n mode: \"single\" | \"multiple\",\n shiftKey: boolean,\n ctrlKey: boolean,\n allRowIds: readonly string[],\n): DataGridSelectionModel {\n if (mode === \"single\") {\n const isSelected = selection.selectedIds.has(rowId);\n return {\n selectedIds: isSelected ? new Set() : new Set([rowId]),\n anchorId: isSelected ? null : rowId,\n };\n }\n\n // Multiple mode\n if (shiftKey && selection.anchorId != null) {\n const anchorIdx = allRowIds.indexOf(selection.anchorId);\n const currentIdx = allRowIds.indexOf(rowId);\n if (anchorIdx >= 0 && currentIdx >= 0) {\n const start = Math.min(anchorIdx, currentIdx);\n const end = Math.max(anchorIdx, currentIdx);\n const rangeIds = allRowIds.slice(start, end + 1);\n\n const next = ctrlKey ? new Set(selection.selectedIds) : new Set<string>();\n for (const id of rangeIds) next.add(id);\n\n return { selectedIds: next, anchorId: selection.anchorId };\n }\n }\n\n if (ctrlKey) {\n // Toggle single in multi mode\n const next = new Set(selection.selectedIds);\n if (next.has(rowId)) {\n next.delete(rowId);\n } else {\n next.add(rowId);\n }\n return { selectedIds: next, anchorId: rowId };\n }\n\n // Plain click in multi mode — select only this row\n return {\n selectedIds: new Set([rowId]),\n anchorId: rowId,\n };\n}\n\nexport function selectAll(\n allRowIds: readonly string[],\n): DataGridSelectionModel {\n return {\n selectedIds: new Set(allRowIds),\n anchorId: null,\n };\n}\n\nexport function clearSelection(): DataGridSelectionModel {\n return EMPTY_SELECTION;\n}\n\n// ─── Quick search ────────────────────────────────────────────────────\n\n/** Default row matcher used by `applyQuickSearch`. Case-insensitive\n * substring match across every column's resolved cell value. Columns\n * with `null` / `undefined` values are skipped. The query is expected\n * to be pre-trimmed and lowercased by `applyQuickSearch` — this helper\n * does NOT trim or lowercase it again, so if you wire it up yourself,\n * do that first. */\nexport function defaultMatchRow<TRow>(\n row: TRow,\n query: string,\n columns: readonly DataGridColumnDef<TRow>[],\n): boolean {\n for (const col of columns) {\n const v = resolveColumnValue(col, row);\n if (v == null) continue;\n if (String(v).toLowerCase().includes(query)) return true;\n }\n return false;\n}\n\n/** Client-side quick-search filter. Returns the original array\n * reference when `query` is empty, so calling this in a hot `useMemo`\n * is cheap in the common \"no search\" case.\n *\n * Used by `useDataSource` in client mode. Exported so consumers driving\n * the grid manually (or doing their own pre-filtering before feeding\n * rows to an async data source) can stay consistent with the built-in\n * search behaviour.\n *\n * Override `matchRow` for custom matching logic — e.g. fuzzy matching,\n * field-specific weighting, or skipping some columns. */\nexport function applyQuickSearch<TRow>(\n rows: readonly TRow[],\n query: string,\n columns: readonly DataGridColumnDef<TRow>[],\n matchRow: (\n row: TRow,\n query: string,\n columns: readonly DataGridColumnDef<TRow>[],\n ) => boolean = defaultMatchRow,\n): readonly TRow[] {\n const trimmed = query.trim().toLowerCase();\n if (!trimmed) return rows;\n return rows.filter((r) => matchRow(r, trimmed, columns));\n}\n\n// ─── Date helpers ────────────────────────────────────────────────────\n\n/** Parse a raw cell value into a `Date`. Returns `null` for nullish,\n * unparseable, or invalid dates. Accepts strings (including ISO and\n * \"YYYY-MM-DD HH:MM:SS\"-style ClickHouse output), numbers (ms since\n * epoch), and `Date` instances. For truly weird formats, override via\n * `col.parseValue`. */\nexport function defaultParseDate(value: unknown): Date | null {\n if (value == null) return null;\n if (value instanceof Date) return isNaN(value.getTime()) ? null : value;\n if (typeof value === \"number\") {\n const d = new Date(value);\n return isNaN(d.getTime()) ? null : d;\n }\n if (typeof value === \"string\") {\n const d = new Date(value);\n return isNaN(d.getTime()) ? null : d;\n }\n return null;\n}\n\nconst DIVISIONS: Array<{ amount: number; unit: Intl.RelativeTimeFormatUnit }> = [\n { amount: 60, unit: \"second\" },\n { amount: 60, unit: \"minute\" },\n { amount: 24, unit: \"hour\" },\n { amount: 7, unit: \"day\" },\n { amount: 4.34524, unit: \"week\" },\n { amount: 12, unit: \"month\" },\n { amount: Number.POSITIVE_INFINITY, unit: \"year\" },\n];\n\n// Memoized per-locale formatter. `Intl.RelativeTimeFormat` construction\n// shows up as a real cost in flamegraphs for grids with many date cells,\n// so cache one instance per locale (\"undefined\" = default).\nconst relativeTimeFormatterCache = new Map<string, Intl.RelativeTimeFormat>();\nfunction getRelativeTimeFormatter(locale?: string): Intl.RelativeTimeFormat {\n const key = locale ?? \"__default__\";\n let cached = relativeTimeFormatterCache.get(key);\n if (cached == null) {\n cached = new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" });\n relativeTimeFormatterCache.set(key, cached);\n }\n return cached;\n}\n\n/** Default relative formatter — \"1 day ago\" / \"in 2 hours\" via\n * `Intl.RelativeTimeFormat`. Pure function of the date; does NOT\n * re-render as real time passes. */\nexport function defaultFormatRelative(date: Date): string {\n const rtf = getRelativeTimeFormatter();\n let duration = (date.getTime() - Date.now()) / 1000;\n for (const div of DIVISIONS) {\n if (Math.abs(duration) < div.amount) {\n return rtf.format(Math.round(duration), div.unit);\n }\n duration /= div.amount;\n }\n return rtf.format(Math.round(duration), \"year\");\n}\n\n/** Default absolute formatter — full locale date + time. */\nexport function defaultFormatAbsolute(date: Date): string {\n return date.toLocaleString();\n}\n\n/** Format a raw cell value for display in a `date` / `dateTime` column.\n * Returns both the inline display string and the tooltip string (which\n * is always the absolute form so users can read the exact datetime).\n *\n * Used internally by the grid's default date cell renderer, and exported\n * so consumers writing a custom `renderCell` for a date column can stay\n * visually consistent with the built-in behaviour.\n *\n * ```tsx\n * renderCell: ({ value, dateDisplay }) => {\n * const { display, tooltip } = formatGridDate(value, dateDisplay);\n * if (!display) return <span className=\"text-muted-foreground/40\">—</span>;\n * return <span title={tooltip ?? undefined}>{display}</span>;\n * }\n * ``` */\nexport function formatGridDate(\n value: unknown,\n mode: DataGridDateDisplay,\n opts?: {\n parseValue?: (value: unknown) => Date | null;\n dateFormat?: DataGridDateFormat;\n },\n): { display: string | null; tooltip: string | null } {\n const parse = opts?.parseValue ?? defaultParseDate;\n const date = parse(value);\n if (!date) return { display: null, tooltip: null };\n\n const relative = opts?.dateFormat?.relative ?? defaultFormatRelative;\n const absolute = opts?.dateFormat?.absolute ?? defaultFormatAbsolute;\n\n const tooltip = absolute(date);\n const display = mode === \"relative\" ? relative(date) : tooltip;\n return { display, tooltip };\n}\n\n// ─── CSV Export ──────────────────────────────────────────────────────\n\nexport function exportToCsv<TRow>(\n rows: readonly TRow[],\n columns: readonly DataGridColumnDef<TRow>[],\n filename: string,\n): void {\n const header = columns.map((col) =>\n typeof col.header === \"string\" ? col.header : col.id,\n );\n\n const csvRows = rows.map((row) =>\n columns.map((col) => {\n const val = resolveColumnValue(col, row);\n // Coerce through `?? \"\"` so a `formatValue` that returns undefined/null\n // (easy to do from a ternary) doesn't crash `.includes` below.\n // The type says `formatValue` returns string, but a consumer can\n // easily return undefined/null from a ternary. Guard at runtime.\n const formatted = col.formatValue\n ? String((col.formatValue(val, row) as string | null | undefined) ?? \"\")\n : String(val ?? \"\");\n // Escape CSV special characters\n if (formatted.includes(\",\") || formatted.includes('\"') || formatted.includes(\"\\n\")) {\n return `\"${formatted.replace(/\"/g, '\"\"')}\"`;\n }\n return formatted;\n }),\n );\n\n // Prepend a UTF-8 BOM so Excel (Windows) opens the CSV as UTF-8 instead of\n // falling back to latin-1 and mangling every display name with a non-ascii\n // character.\n const csvContent = \"\\ufeff\" + [\n header.join(\",\"),\n ...csvRows.map((row) => row.join(\",\")),\n ].join(\"\\n\");\n\n const blob = new Blob([csvContent], { type: \"text/csv;charset=utf-8;\" });\n const url = URL.createObjectURL(blob);\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = `${filename}.csv`;\n // Safari / older Firefox need the link in the DOM to honour `.click()`.\n document.body.appendChild(link);\n try {\n link.click();\n } finally {\n link.remove();\n URL.revokeObjectURL(url);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"state.js","names":[],"sources":["../../../../src/components/data-grid/state.ts"],"sourcesContent":["import { stringCompare } from \"@stackframe/stack-shared/dist/utils/strings\";\nimport { clampColumnWidth, DEFAULT_COL_WIDTH } from \"./data-grid-sizing\";\nimport type {\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridDateFormat,\n DataGridPaginationModel,\n DataGridSortModel,\n DataGridState,\n} from \"./types\";\n\n/**\n * Build the initial `DataGridState` for a set of columns. Pass this as the\n * lazy initializer to `useState` — never hand-assemble the state object.\n *\n * ```tsx\n * const [gridState, setGridState] = React.useState(() =>\n * createDefaultDataGridState(columns)\n * );\n * ```\n */\nexport function createDefaultDataGridState(\n columns: readonly DataGridColumnDef<any>[],\n): DataGridState {\n const columnWidths: Record<string, number> = {};\n const columnOrder: string[] = [];\n\n for (const col of columns) {\n columnWidths[col.id] = clampColumnWidth(col, col.width ?? DEFAULT_COL_WIDTH);\n columnOrder.push(col.id);\n }\n\n return {\n sorting: [],\n columnVisibility: {},\n columnWidths,\n columnPinning: { left: [], right: [] },\n columnOrder,\n pagination: { pageIndex: 0, pageSize: 50 },\n selection: { selectedIds: new Set(), anchorId: null },\n dateDisplay: \"relative\",\n quickSearch: \"\",\n };\n}\n\n// ─── Column value resolution ─────────────────────────────────────────\n\nexport function resolveColumnValue<TRow>(\n col: DataGridColumnDef<TRow>,\n row: TRow,\n): unknown {\n if (typeof col.accessor === \"function\") return col.accessor(row);\n const key = (col.accessor ?? col.id) as keyof TRow;\n return row[key];\n}\n\n// ─── Default sort comparator (used by client-mode useDataSource) ────\n\nfunction defaultComparator(a: unknown, b: unknown): number {\n if (a == null && b == null) return 0;\n if (a == null) return -1;\n if (b == null) return 1;\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n return stringCompare(String(a), String(b));\n}\n\nexport function buildRowComparator<TRow>(\n sortModel: DataGridSortModel,\n columns: readonly DataGridColumnDef<TRow>[],\n): ((a: TRow, b: TRow) => number) | null {\n if (sortModel.length === 0) return null;\n const colMap = new Map(columns.map((c) => [c.id, c]));\n return (a, b) => {\n for (const { columnId, direction } of sortModel) {\n const col = colMap.get(columnId);\n if (!col) continue;\n const va = resolveColumnValue(col, a);\n const vb = resolveColumnValue(col, b);\n const cmp = col.sortComparator ? col.sortComparator(va, vb) : defaultComparator(va, vb);\n if (cmp !== 0) return direction === \"asc\" ? cmp : -cmp;\n }\n return 0;\n };\n}\n\n// ─── Pagination ──────────────────────────────────────────────────────\n\nexport function paginateRows<TRow>(\n rows: readonly TRow[],\n pagination: DataGridPaginationModel,\n): TRow[] {\n const start = pagination.pageIndex * pagination.pageSize;\n return rows.slice(start, start + pagination.pageSize) as TRow[];\n}\n\n// ─── Quick search ────────────────────────────────────────────────────\n\n/** Default row matcher: case-insensitive substring across every column. */\nexport function defaultMatchRow<TRow>(\n row: TRow,\n query: string,\n columns: readonly DataGridColumnDef<TRow>[],\n): boolean {\n for (const col of columns) {\n const v = resolveColumnValue(col, row);\n if (v == null) continue;\n if (String(v).toLowerCase().includes(query)) return true;\n }\n return false;\n}\n\nexport function applyQuickSearch<TRow>(\n rows: readonly TRow[],\n query: string,\n columns: readonly DataGridColumnDef<TRow>[],\n matchRow: (\n row: TRow,\n query: string,\n columns: readonly DataGridColumnDef<TRow>[],\n ) => boolean = defaultMatchRow,\n): readonly TRow[] {\n const trimmed = query.trim().toLowerCase();\n if (!trimmed) return rows;\n return rows.filter((r) => matchRow(r, trimmed, columns));\n}\n\n// ─── Date helpers ────────────────────────────────────────────────────\n\nexport function defaultParseDate(value: unknown): Date | null {\n if (value == null) return null;\n if (value instanceof Date) return isNaN(value.getTime()) ? null : value;\n if (typeof value === \"number\" || typeof value === \"string\") {\n const d = new Date(value);\n return isNaN(d.getTime()) ? null : d;\n }\n return null;\n}\n\nconst DIVISIONS: Array<{ amount: number; unit: Intl.RelativeTimeFormatUnit }> = [\n { amount: 60, unit: \"second\" },\n { amount: 60, unit: \"minute\" },\n { amount: 24, unit: \"hour\" },\n { amount: 7, unit: \"day\" },\n { amount: 4.34524, unit: \"week\" },\n { amount: 12, unit: \"month\" },\n { amount: Number.POSITIVE_INFINITY, unit: \"year\" },\n];\n\nconst relativeTimeFormatterCache = new Map<string, Intl.RelativeTimeFormat>();\nfunction getRelativeTimeFormatter(locale?: string): Intl.RelativeTimeFormat {\n const key = locale ?? \"__default__\";\n let cached = relativeTimeFormatterCache.get(key);\n if (cached == null) {\n cached = new Intl.RelativeTimeFormat(locale, { numeric: \"auto\" });\n relativeTimeFormatterCache.set(key, cached);\n }\n return cached;\n}\n\nexport function defaultFormatRelative(date: Date): string {\n const rtf = getRelativeTimeFormatter();\n // Wall-clock comparison to \"now\" (e.g. \"5 minutes ago\"). performance.now()\n // would be wrong here — it's a monotonic timer, not a wall-clock instant.\n let duration = (date.getTime() - Date.now()) / 1000;\n for (const div of DIVISIONS) {\n if (Math.abs(duration) < div.amount) return rtf.format(Math.round(duration), div.unit);\n duration /= div.amount;\n }\n return rtf.format(Math.round(duration), \"year\");\n}\n\nexport function defaultFormatAbsolute(date: Date): string {\n return date.toLocaleString();\n}\n\nexport function formatGridDate(\n value: unknown,\n mode: DataGridDateDisplay,\n opts?: {\n parseValue?: (value: unknown) => Date | null;\n dateFormat?: DataGridDateFormat;\n },\n): { display: string | null; tooltip: string | null } {\n const parse = opts?.parseValue ?? defaultParseDate;\n const date = parse(value);\n if (!date) return { display: null, tooltip: null };\n const relative = opts?.dateFormat?.relative ?? defaultFormatRelative;\n const absolute = opts?.dateFormat?.absolute ?? defaultFormatAbsolute;\n const tooltip = absolute(date);\n const display = mode === \"relative\" ? relative(date) : tooltip;\n return { display, tooltip };\n}\n\n// ─── CSV Export ──────────────────────────────────────────────────────\n\nexport function exportToCsv<TRow>(\n rows: readonly TRow[],\n columns: readonly DataGridColumnDef<TRow>[],\n filename: string,\n): void {\n const header = columns.map((col) =>\n typeof col.header === \"string\" ? col.header : col.id,\n );\n const csvRows = rows.map((row) =>\n columns.map((col) => {\n const val = resolveColumnValue(col, row);\n const formatted = col.formatValue\n ? String((col.formatValue(val, row) as string | null | undefined) ?? \"\")\n : String(val ?? \"\");\n if (formatted.includes(\",\") || formatted.includes('\"') || formatted.includes(\"\\n\")) {\n return `\"${formatted.replace(/\"/g, '\"\"')}\"`;\n }\n return formatted;\n }),\n );\n // UTF-8 BOM so Excel opens the CSV as UTF-8.\n const csvContent = \"\\uFEFF\" + [\n header.join(\",\"),\n ...csvRows.map((row) => row.join(\",\")),\n ].join(\"\\n\");\n\n const blob = new Blob([csvContent], { type: \"text/csv;charset=utf-8;\" });\n const url = URL.createObjectURL(blob);\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = `${filename}.csv`;\n document.body.appendChild(link);\n try {\n link.click();\n } finally {\n link.remove();\n URL.revokeObjectURL(url);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAqBA,SAAgB,2BACd,SACe;CACf,MAAM,eAAuC,EAAE;CAC/C,MAAM,cAAwB,EAAE;AAEhC,MAAK,MAAM,OAAO,SAAS;AACzB,eAAa,IAAI,MAAM,iBAAiB,KAAK,IAAI,SAAS,kBAAkB;AAC5E,cAAY,KAAK,IAAI,GAAG;;AAG1B,QAAO;EACL,SAAS,EAAE;EACX,kBAAkB,EAAE;EACpB;EACA,eAAe;GAAE,MAAM,EAAE;GAAE,OAAO,EAAE;GAAE;EACtC;EACA,YAAY;GAAE,WAAW;GAAG,UAAU;GAAI;EAC1C,WAAW;GAAE,6BAAa,IAAI,KAAK;GAAE,UAAU;GAAM;EACrD,aAAa;EACb,aAAa;EACd;;AAKH,SAAgB,mBACd,KACA,KACS;AACT,KAAI,OAAO,IAAI,aAAa,WAAY,QAAO,IAAI,SAAS,IAAI;AAEhE,QAAO,IADM,IAAI,YAAY,IAAI;;AAMnC,SAAS,kBAAkB,GAAY,GAAoB;AACzD,KAAI,KAAK,QAAQ,KAAK,KAAM,QAAO;AACnC,KAAI,KAAK,KAAM,QAAO;AACtB,KAAI,KAAK,KAAM,QAAO;AACtB,KAAI,OAAO,MAAM,YAAY,OAAO,MAAM,SAAU,QAAO,IAAI;AAC/D,KAAI,aAAa,QAAQ,aAAa,KAAM,QAAO,EAAE,SAAS,GAAG,EAAE,SAAS;AAC5E,QAAO,cAAc,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC;;AAG5C,SAAgB,mBACd,WACA,SACuC;AACvC,KAAI,UAAU,WAAW,EAAG,QAAO;CACnC,MAAM,SAAS,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AACrD,SAAQ,GAAG,MAAM;AACf,OAAK,MAAM,EAAE,UAAU,eAAe,WAAW;GAC/C,MAAM,MAAM,OAAO,IAAI,SAAS;AAChC,OAAI,CAAC,IAAK;GACV,MAAM,KAAK,mBAAmB,KAAK,EAAE;GACrC,MAAM,KAAK,mBAAmB,KAAK,EAAE;GACrC,MAAM,MAAM,IAAI,iBAAiB,IAAI,eAAe,IAAI,GAAG,GAAG,kBAAkB,IAAI,GAAG;AACvF,OAAI,QAAQ,EAAG,QAAO,cAAc,QAAQ,MAAM,CAAC;;AAErD,SAAO;;;AAMX,SAAgB,aACd,MACA,YACQ;CACR,MAAM,QAAQ,WAAW,YAAY,WAAW;AAChD,QAAO,KAAK,MAAM,OAAO,QAAQ,WAAW,SAAS;;;AAMvD,SAAgB,gBACd,KACA,OACA,SACS;AACT,MAAK,MAAM,OAAO,SAAS;EACzB,MAAM,IAAI,mBAAmB,KAAK,IAAI;AACtC,MAAI,KAAK,KAAM;AACf,MAAI,OAAO,EAAE,CAAC,aAAa,CAAC,SAAS,MAAM,CAAE,QAAO;;AAEtD,QAAO;;AAGT,SAAgB,iBACd,MACA,OACA,SACA,WAIe,iBACE;CACjB,MAAM,UAAU,MAAM,MAAM,CAAC,aAAa;AAC1C,KAAI,CAAC,QAAS,QAAO;AACrB,QAAO,KAAK,QAAQ,MAAM,SAAS,GAAG,SAAS,QAAQ,CAAC;;AAK1D,SAAgB,iBAAiB,OAA6B;AAC5D,KAAI,SAAS,KAAM,QAAO;AAC1B,KAAI,iBAAiB,KAAM,QAAO,MAAM,MAAM,SAAS,CAAC,GAAG,OAAO;AAClE,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;EAC1D,MAAM,IAAI,IAAI,KAAK,MAAM;AACzB,SAAO,MAAM,EAAE,SAAS,CAAC,GAAG,OAAO;;AAErC,QAAO;;AAGT,MAAM,YAA0E;CAC9E;EAAE,QAAQ;EAAI,MAAM;EAAU;CAC9B;EAAE,QAAQ;EAAI,MAAM;EAAU;CAC9B;EAAE,QAAQ;EAAI,MAAM;EAAQ;CAC5B;EAAE,QAAQ;EAAG,MAAM;EAAO;CAC1B;EAAE,QAAQ;EAAS,MAAM;EAAQ;CACjC;EAAE,QAAQ;EAAI,MAAM;EAAS;CAC7B;EAAE,QAAQ,OAAO;EAAmB,MAAM;EAAQ;CACnD;AAED,MAAM,6CAA6B,IAAI,KAAsC;AAC7E,SAAS,yBAAyB,QAA0C;CAC1E,MAAM,MAAM,UAAU;CACtB,IAAI,SAAS,2BAA2B,IAAI,IAAI;AAChD,KAAI,UAAU,MAAM;AAClB,WAAS,IAAI,KAAK,mBAAmB,QAAQ,EAAE,SAAS,QAAQ,CAAC;AACjE,6BAA2B,IAAI,KAAK,OAAO;;AAE7C,QAAO;;AAGT,SAAgB,sBAAsB,MAAoB;CACxD,MAAM,MAAM,0BAA0B;CAGtC,IAAI,YAAY,KAAK,SAAS,GAAG,KAAK,KAAK,IAAI;AAC/C,MAAK,MAAM,OAAO,WAAW;AAC3B,MAAI,KAAK,IAAI,SAAS,GAAG,IAAI,OAAQ,QAAO,IAAI,OAAO,KAAK,MAAM,SAAS,EAAE,IAAI,KAAK;AACtF,cAAY,IAAI;;AAElB,QAAO,IAAI,OAAO,KAAK,MAAM,SAAS,EAAE,OAAO;;AAGjD,SAAgB,sBAAsB,MAAoB;AACxD,QAAO,KAAK,gBAAgB;;AAG9B,SAAgB,eACd,OACA,MACA,MAIoD;CAEpD,MAAM,QADQ,MAAM,cAAc,kBACf,MAAM;AACzB,KAAI,CAAC,KAAM,QAAO;EAAE,SAAS;EAAM,SAAS;EAAM;CAClD,MAAM,WAAW,MAAM,YAAY,YAAY;CAE/C,MAAM,WADW,MAAM,YAAY,YAAY,uBACtB,KAAK;AAE9B,QAAO;EAAE,SADO,SAAS,aAAa,SAAS,KAAK,GAAG;EACrC;EAAS;;AAK7B,SAAgB,YACd,MACA,SACA,UACM;CACN,MAAM,SAAS,QAAQ,KAAK,QAC1B,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS,IAAI,GACnD;CACD,MAAM,UAAU,KAAK,KAAK,QACxB,QAAQ,KAAK,QAAQ;EACnB,MAAM,MAAM,mBAAmB,KAAK,IAAI;EACxC,MAAM,YAAY,IAAI,cAClB,OAAQ,IAAI,YAAY,KAAK,IAAI,IAAkC,GAAG,GACtE,OAAO,OAAO,GAAG;AACrB,MAAI,UAAU,SAAS,IAAI,IAAI,UAAU,SAAS,KAAI,IAAI,UAAU,SAAS,KAAK,CAChF,QAAO,IAAI,UAAU,QAAQ,MAAM,OAAK,CAAC;AAE3C,SAAO;GACP,CACH;CAED,MAAM,aAAa,MAAW,CAC5B,OAAO,KAAK,IAAI,EAChB,GAAG,QAAQ,KAAK,QAAQ,IAAI,KAAK,IAAI,CAAC,CACvC,CAAC,KAAK,KAAK;CAEZ,MAAM,OAAO,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,MAAM,2BAA2B,CAAC;CACxE,MAAM,MAAM,IAAI,gBAAgB,KAAK;CACrC,MAAM,OAAO,SAAS,cAAc,IAAI;AACxC,MAAK,OAAO;AACZ,MAAK,WAAW,GAAG,SAAS;AAC5B,UAAS,KAAK,YAAY,KAAK;AAC/B,KAAI;AACF,OAAK,OAAO;WACJ;AACR,OAAK,QAAQ;AACb,MAAI,gBAAgB,IAAI"}
|
|
@@ -153,6 +153,14 @@ type DataGridCallbacks<TRow> = {
|
|
|
153
153
|
onRowClick?: (row: TRow, rowId: RowId, event: React.MouseEvent) => void;
|
|
154
154
|
onRowDoubleClick?: (row: TRow, rowId: RowId, event: React.MouseEvent) => void;
|
|
155
155
|
onCellClick?: (row: TRow, columnId: string, value: unknown, event: React.MouseEvent) => void;
|
|
156
|
+
/**
|
|
157
|
+
* Fires when the selection set changes. **Page-scoped:** the header "select
|
|
158
|
+
* all" checkbox and `selectedRows` only cover the rows currently rendered
|
|
159
|
+
* (the visible page in paginated mode, or the loaded prefix in infinite
|
|
160
|
+
* mode). The grid does not load other pages to satisfy the selection — if
|
|
161
|
+
* you need cross-page selection, drive `selectedIds` from your own state
|
|
162
|
+
* and load all rows you care about up-front.
|
|
163
|
+
*/
|
|
156
164
|
onSelectionChange?: (selectedIds: ReadonlySet<RowId>, selectedRows: TRow[]) => void;
|
|
157
165
|
onSortChange?: (model: DataGridSortModel) => void;
|
|
158
166
|
onColumnResize?: (columnId: string, width: number) => void;
|
|
@@ -202,10 +210,7 @@ type DataGridProps<TRow> = {
|
|
|
202
210
|
* When `false`, the grid is only as tall as toolbar + header + rows (`h-auto`), so sibling
|
|
203
211
|
* content (e.g. metadata) sits directly under the table without a large empty gap.
|
|
204
212
|
*/
|
|
205
|
-
fillHeight?: boolean;
|
|
206
|
-
/** Top offset for the sticky toolbar + header (px or CSS string).
|
|
207
|
-
* Set this to the page header height so the grid chrome sticks
|
|
208
|
-
* below it instead of overlapping. Defaults to 0. */
|
|
213
|
+
fillHeight?: boolean; /** Top offset for the sticky toolbar + header (px or CSS string). */
|
|
209
214
|
stickyTop?: number | string;
|
|
210
215
|
} & DataGridCallbacks<TRow> & {
|
|
211
216
|
/** Custom toolbar renderer. When `false`, toolbar is hidden entirely. */toolbar?: false | ((ctx: DataGridToolbarContext<TRow>) => ReactNode);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../../src/components/data-grid/types.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../../src/components/data-grid/types.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DataGridColumnDef, DataGridState } from "./types";
|
|
2
|
+
|
|
3
|
+
//#region src/components/data-grid/use-url-state.d.ts
|
|
4
|
+
type UrlStateOptions = {
|
|
5
|
+
/** Disambiguates URL params when multiple grids share a page. Defaults
|
|
6
|
+
* to `"grid"`. Use unique prefixes per-grid (e.g. `"users"`, `"teams"`). */
|
|
7
|
+
paramPrefix?: string;
|
|
8
|
+
/** Overrides for default state used when the URL has no value for a
|
|
9
|
+
* given key. Useful for things like a sensible initial sort (e.g.
|
|
10
|
+
* "newest signups first") that should appear on first load but be
|
|
11
|
+
* overridden when the user navigates to a bookmarked URL. */
|
|
12
|
+
initial?: Partial<Pick<DataGridState, "sorting" | "quickSearch" | "columnVisibility">>;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Drop-in replacement for `useState(() => createDefaultDataGridState(columns))`
|
|
16
|
+
* that persists user view preferences to URL search params, so a view
|
|
17
|
+
* can be bookmarked / shared / restored on reload.
|
|
18
|
+
*
|
|
19
|
+
* **Persisted:** column widths, hidden columns, sort model, quick-search.
|
|
20
|
+
* **Not persisted** (deliberately): pagination scroll position, selection,
|
|
21
|
+
* column pinning/order, date display mode — these are session-scoped.
|
|
22
|
+
*
|
|
23
|
+
* ```tsx
|
|
24
|
+
* const [gridState, setGridState] = useDataGridUrlState(columns, {
|
|
25
|
+
* paramPrefix: "users",
|
|
26
|
+
* initial: { sorting: [{ columnId: "signedUpAt", direction: "desc" }] },
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* URL encoding: `?{prefix}_w=...&{prefix}_h=...&{prefix}_s=...&{prefix}_q=...`.
|
|
31
|
+
* Default values are omitted so URLs stay clean. Updates use
|
|
32
|
+
* `history.replaceState` (not pushState) so back/forward isn't polluted,
|
|
33
|
+
* and `popstate` is observed so external URL changes flow back into state.
|
|
34
|
+
*/
|
|
35
|
+
declare function useDataGridUrlState<TRow>(columns: readonly DataGridColumnDef<TRow>[], opts?: UrlStateOptions): [DataGridState, React.Dispatch<React.SetStateAction<DataGridState>>];
|
|
36
|
+
//#endregion
|
|
37
|
+
export { useDataGridUrlState };
|
|
38
|
+
//# sourceMappingURL=use-url-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-url-state.d.ts","names":[],"sources":["../../../../src/components/data-grid/use-url-state.ts"],"mappings":";;;KAqJK,eAAA;;AA3IY;EA8If,WAAA;;;;;EAKA,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,aAAA;AAAA;;;;;;;;AAwBzB;;;;;;;;;;;;;;iBAAgB,mBAAA,MAAA,CACd,OAAA,WAAkB,iBAAA,CAAkB,IAAA,KACpC,IAAA,GAAO,eAAA,IACL,aAAA,EAAe,KAAA,CAAM,QAAA,CAAS,KAAA,CAAM,cAAA,CAAe,aAAA"}
|