@homebound/beam 2.99.0 → 2.101.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/components/Icon.d.ts +1 -1
- package/dist/components/Table/GridTable.d.ts +17 -31
- package/dist/components/Table/GridTable.js +115 -90
- package/dist/components/Table/SortHeader.js +6 -1
- package/dist/components/Table/nestedCards.d.ts +36 -22
- package/dist/components/Table/nestedCards.js +59 -29
- package/dist/components/Table/sortRows.d.ts +1 -1
- package/dist/components/Table/sortRows.js +8 -12
- package/dist/components/Table/useSortState.d.ts +1 -0
- package/dist/components/Table/useSortState.js +30 -14
- package/dist/components/internal/CompoundField.js +9 -22
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ export interface IconProps extends AriaAttributes, DOMProps {
|
|
|
9
9
|
/** The size of the icon in increments, i.e. 1 == 8px, default is 3 == 24px. */
|
|
10
10
|
inc?: number;
|
|
11
11
|
/** Styles overrides */
|
|
12
|
-
xss?: Xss<Margin>;
|
|
12
|
+
xss?: Xss<Margin | "visibility">;
|
|
13
13
|
}
|
|
14
14
|
export declare const Icon: React.MemoExoticComponent<(props: IconProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
|
|
15
15
|
/**
|
|
@@ -21,7 +21,14 @@ export interface GridStyle {
|
|
|
21
21
|
firstNonHeaderRowCss?: Properties;
|
|
22
22
|
/** Applied to all cell divs (via a selector off the base div). */
|
|
23
23
|
cellCss?: Properties;
|
|
24
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Applied to the header row divs.
|
|
26
|
+
*
|
|
27
|
+
* NOTE `as=virtual`: When using a virtual table with the goal of adding space
|
|
28
|
+
* between the header and the first row use `firstNonHeaderRowCss` with a
|
|
29
|
+
* margin-top instead. Using `headerCellCss` will not work since the header
|
|
30
|
+
* rows are wrapper with Chrome rows.
|
|
31
|
+
*/
|
|
25
32
|
headerCellCss?: Properties;
|
|
26
33
|
/** Applied to the first cell of all rows, i.e. for table-wide padding or left-side borders. */
|
|
27
34
|
firstCellCss?: Properties;
|
|
@@ -96,13 +103,13 @@ export declare type RowTuple<R extends Kinded> = [GridDataRow<R> | undefined, Re
|
|
|
96
103
|
export declare type GridSortConfig<S> = {
|
|
97
104
|
on: "client";
|
|
98
105
|
/** The optional initial column (index in columns) and direction to sort. */
|
|
99
|
-
initial?: [S | GridColumn<any>, Direction];
|
|
106
|
+
initial?: [S | GridColumn<any>, Direction] | undefined;
|
|
100
107
|
} | {
|
|
101
108
|
on: "server";
|
|
102
109
|
/** The current sort by value + direction (if server-side sorting). */
|
|
103
110
|
value?: [S, Direction];
|
|
104
|
-
/** Callback for when the column is sorted (if server-side sorting). */
|
|
105
|
-
onSort: (orderBy: S, direction: Direction) => void;
|
|
111
|
+
/** Callback for when the column is sorted (if server-side sorting). Parameters set to `undefined` is a signal to return to the initial sort state */
|
|
112
|
+
onSort: (orderBy: S | undefined, direction: Direction | undefined) => void;
|
|
106
113
|
};
|
|
107
114
|
export interface GridTableProps<R extends Kinded, S, X> {
|
|
108
115
|
id?: string;
|
|
@@ -178,18 +185,10 @@ export declare type GridTableApi = {
|
|
|
178
185
|
*/
|
|
179
186
|
export declare function GridTable<R extends Kinded, S = {}, X extends Only<GridTableXss, X> = {}>(props: GridTableProps<R, S, X>): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
180
187
|
/**
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* Because of two things:
|
|
184
|
-
*
|
|
185
|
-
* a) react-virtuoso puts the header in a different div than the normal rows, and
|
|
186
|
-
*
|
|
187
|
-
* b) content-aware sizing just in general look janky/constantly resize while scrolling
|
|
188
|
-
*
|
|
189
|
-
* When we're as=virtual, we change our default + enforce only fixed-sized units (% and px)
|
|
188
|
+
* Calculates column widths using a flexible `calc()` definition that allows for consistent column alignment without the use of `<table />`, CSS Grid, etc layouts.
|
|
189
|
+
* Enforces only fixed-sized units (% and px)
|
|
190
190
|
*/
|
|
191
|
-
export declare function
|
|
192
|
-
export declare function calcDivGridColumns(columns: GridColumn<any>[], firstLastColumnWidth: number | undefined): string;
|
|
191
|
+
export declare function calcColumnSizes(columns: GridColumn<any>[], firstLastColumnWidth: number | undefined): string[];
|
|
193
192
|
/**
|
|
194
193
|
* Given an ADT of type T, performs a look up and returns the type of kind K.
|
|
195
194
|
*
|
|
@@ -218,21 +217,8 @@ export declare type GridColumn<R extends Kinded, S = {}> = {
|
|
|
218
217
|
} ? (data: D, row: GridRowKind<R, K>) => ReactNode | GridCellContent : (row: GridRowKind<R, K>) => ReactNode | GridCellContent);
|
|
219
218
|
} & {
|
|
220
219
|
/**
|
|
221
|
-
* The column's
|
|
222
|
-
*
|
|
223
|
-
* For `as=div` output:
|
|
224
|
-
*
|
|
225
|
-
* - Any CSS grid units are supported
|
|
226
|
-
* - Numbers are treated as `fr` units
|
|
227
|
-
* - The default value is `auto`, which in CSS grid will do content-aware/responsive layout.
|
|
228
|
-
*
|
|
229
|
-
* For `as=virtual` output:
|
|
230
|
-
*
|
|
231
|
-
* - Only px, percentage, or fr units are supported, due to a) react-virtuoso puts the sticky header
|
|
232
|
-
* rows in a separate `div` and so we end up with two `grid-template-columns`, so cannot rely on
|
|
233
|
-
* any content-aware sizing, and b) content-aware sizing in a scrolling/virtual table results in
|
|
234
|
-
* a ~janky experience as the columns will constantly resize as new/different content is put in/out
|
|
235
|
-
* of the DOM.
|
|
220
|
+
* The column's width.
|
|
221
|
+
* - Only px, percentage, or fr units are supported, due to each GridRow acting as an independent table. This ensures consistent alignment between rows.
|
|
236
222
|
* - Numbers are treated as `fr` units
|
|
237
223
|
* - The default value is `1fr`
|
|
238
224
|
*/
|
|
@@ -270,7 +256,7 @@ export declare type GridCellAlignment = "left" | "right" | "center";
|
|
|
270
256
|
* primitive value for filtering and sorting.
|
|
271
257
|
*/
|
|
272
258
|
export declare type GridCellContent = {
|
|
273
|
-
/** The JSX content of the cell. Virtual tables that client-side sort should use a function to
|
|
259
|
+
/** The JSX content of the cell. Virtual tables that client-side sort should use a function to avoid perf overhead. */
|
|
274
260
|
content: ReactNode | (() => ReactNode);
|
|
275
261
|
alignment?: GridCellAlignment;
|
|
276
262
|
/** Allow value to be a function in case it's a dynamic value i.e. reading from an inline-edited proxy. */
|
|
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.matchesFilter = exports.GridCollapseContext = exports.applyRowFn = exports.
|
|
25
|
+
exports.matchesFilter = exports.GridCollapseContext = exports.applyRowFn = exports.calcColumnSizes = exports.GridTable = exports.setGridTableDefaults = exports.setDefaultStyle = exports.setRunningInJest = exports.emptyCell = exports.DESC = exports.ASC = void 0;
|
|
26
26
|
const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
27
27
|
const memoize_one_1 = __importDefault(require("memoize-one"));
|
|
28
28
|
const mobx_react_1 = require("mobx-react");
|
|
@@ -92,12 +92,10 @@ function GridTable(props) {
|
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
const [sortState, setSortKey] = (0, useSortState_1.useSortState)(columns, sorting);
|
|
95
|
-
// Disclaimer that technically even though this is a useMemo, sortRows is mutating `rows` directly
|
|
96
95
|
const maybeSorted = (0, react_1.useMemo)(() => {
|
|
97
96
|
if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client" && sortState) {
|
|
98
97
|
// If using client-side sort, the sortState use S = number
|
|
99
|
-
(0, sortRows_1.sortRows)(columns, rows, sortState);
|
|
100
|
-
return rows;
|
|
98
|
+
return (0, sortRows_1.sortRows)(columns, rows, sortState);
|
|
101
99
|
}
|
|
102
100
|
return rows;
|
|
103
101
|
}, [columns, rows, sorting, sortState]);
|
|
@@ -106,12 +104,13 @@ function GridTable(props) {
|
|
|
106
104
|
var _a;
|
|
107
105
|
// Break up "foo bar" into `[foo, bar]` and a row must match both `foo` and `bar`
|
|
108
106
|
const filters = (filter && filter.split(/ +/)) || [];
|
|
109
|
-
const columnSizes =
|
|
107
|
+
const columnSizes = calcColumnSizes(columns, (_a = style.nestedCards) === null || _a === void 0 ? void 0 : _a.firstLastColumnWidth);
|
|
110
108
|
function makeRowComponent(row) {
|
|
111
109
|
// We only pass sortState to header rows, b/c non-headers rows shouldn't have to re-render on sorting
|
|
112
110
|
// changes, and so by not passing the sortProps, it means the data rows' React.memo will still cache them.
|
|
113
111
|
const sortProps = row.kind === "header" ? { sorting, sortState, setSortKey } : { sorting };
|
|
114
112
|
const RowComponent = observeRows ? ObservedGridRow : MemoizedGridRow;
|
|
113
|
+
const openCards = row.kind === "header" ? headerCards : rowCards;
|
|
115
114
|
return ((0, jsx_runtime_1.jsx)(exports.GridCollapseContext.Provider, Object.assign({ value: row.kind === "header" ? collapseAllContext : collapseRowContext }, { children: (0, jsx_runtime_1.jsx)(RowComponent, Object.assign({}, {
|
|
116
115
|
as,
|
|
117
116
|
columns,
|
|
@@ -120,16 +119,18 @@ function GridTable(props) {
|
|
|
120
119
|
rowStyles,
|
|
121
120
|
stickyHeader,
|
|
122
121
|
stickyOffset,
|
|
123
|
-
openCards:
|
|
122
|
+
openCards: openCards ? openCards.currentOpenCards() : undefined,
|
|
124
123
|
columnSizes,
|
|
125
124
|
...sortProps,
|
|
126
|
-
}),
|
|
125
|
+
}), void 0) }), `${row.kind}-${row.id}`));
|
|
127
126
|
}
|
|
128
127
|
// Split out the header rows from the data rows so that we can put an `infoMessage` in between them (if needed).
|
|
129
128
|
const headerRows = [];
|
|
130
129
|
const filteredRows = [];
|
|
131
130
|
// Misc state to track our nested card-ification, i.e. interleaved actual rows + chrome rows
|
|
132
|
-
|
|
131
|
+
// for the header and row (non-header rows) cards.
|
|
132
|
+
const headerCards = !!style.nestedCards && new nestedCards_1.NestedCards(columns, headerRows, style.nestedCards);
|
|
133
|
+
const rowCards = !!style.nestedCards && new nestedCards_1.NestedCards(columns, filteredRows, style.nestedCards);
|
|
133
134
|
// Depth-first to filter
|
|
134
135
|
function visit(row) {
|
|
135
136
|
var _a;
|
|
@@ -139,32 +140,38 @@ function GridTable(props) {
|
|
|
139
140
|
// Even if we don't pass the filter, one of our children might, so we continue on after this check
|
|
140
141
|
let isCard = false;
|
|
141
142
|
if (matches) {
|
|
142
|
-
isCard =
|
|
143
|
+
isCard = rowCards && rowCards.maybeOpenCard(row);
|
|
143
144
|
filteredRows.push([row, makeRowComponent(row)]);
|
|
144
145
|
}
|
|
145
146
|
const isCollapsed = collapsedIds.includes(row.id);
|
|
146
147
|
if (!isCollapsed && !!((_a = row.children) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
147
|
-
|
|
148
|
+
rowCards && matches && rowCards.addSpacer();
|
|
148
149
|
visitRows(row.children, isCard);
|
|
149
150
|
}
|
|
150
|
-
isCard &&
|
|
151
|
+
isCard && rowCards && rowCards.closeCard();
|
|
151
152
|
}
|
|
152
153
|
function visitRows(rows, addSpacer) {
|
|
153
154
|
const length = rows.length;
|
|
154
155
|
rows.forEach((row, i) => {
|
|
156
|
+
var _a;
|
|
155
157
|
if (row.kind === "header") {
|
|
156
|
-
|
|
158
|
+
// Flag to determine if the header has nested card styles.
|
|
159
|
+
// This will determine if we should include opening and closing
|
|
160
|
+
// Chrome rows.
|
|
161
|
+
const isHeaderNested = !!((_a = style.nestedCards) === null || _a === void 0 ? void 0 : _a.kinds["header"]);
|
|
162
|
+
isHeaderNested && headerCards && headerCards.maybeOpenCard(row);
|
|
157
163
|
headerRows.push([row, makeRowComponent(row)]);
|
|
158
|
-
|
|
164
|
+
isHeaderNested && headerCards && headerCards.closeCard();
|
|
165
|
+
isHeaderNested && headerCards && headerCards.done();
|
|
159
166
|
return;
|
|
160
167
|
}
|
|
161
168
|
visit(row);
|
|
162
|
-
addSpacer &&
|
|
169
|
+
addSpacer && rowCards && i !== length - 1 && rowCards.addSpacer();
|
|
163
170
|
});
|
|
164
171
|
}
|
|
165
172
|
// If nestedCards is set, we assume the top-level kind is a card, and so should add spacers between them
|
|
166
|
-
visitRows(maybeSorted, !!
|
|
167
|
-
|
|
173
|
+
visitRows(maybeSorted, !!rowCards);
|
|
174
|
+
rowCards && rowCards.done();
|
|
168
175
|
return [headerRows, filteredRows];
|
|
169
176
|
}, [
|
|
170
177
|
as,
|
|
@@ -210,22 +217,54 @@ exports.GridTable = GridTable;
|
|
|
210
217
|
// Determine which HTML element to use to build the GridTable
|
|
211
218
|
const renders = {
|
|
212
219
|
table: renderTable,
|
|
213
|
-
div:
|
|
220
|
+
div: renderDiv,
|
|
214
221
|
virtual: renderVirtual,
|
|
215
222
|
};
|
|
216
|
-
/** Renders
|
|
217
|
-
function
|
|
223
|
+
/** Renders table using divs with flexbox rows, which is the default render */
|
|
224
|
+
function renderDiv(style, id, columns, headerRows, filteredRows, firstRowMessage, _stickyHeader, firstLastColumnWidth, xss, _virtuosoRef) {
|
|
225
|
+
var _a;
|
|
226
|
+
// We must determine if the header is using nested card styles to account for
|
|
227
|
+
// the opening and closing Chrome rows.
|
|
228
|
+
const isNestedCardStyleHeader = !!((_a = style.nestedCards) === null || _a === void 0 ? void 0 : _a.kinds["header"]);
|
|
229
|
+
/*
|
|
230
|
+
Determine at what CSS selector index is the first non header row. Note that
|
|
231
|
+
CSS selectors are not zero-based, unlike JavaScript, so we must add 1 to
|
|
232
|
+
what we'd normally expect.
|
|
233
|
+
|
|
234
|
+
Ex: When we don't have nestedCard styled headers, then we don't have opening
|
|
235
|
+
and closing Chrome rows. Therefore, the first non-header row is the second
|
|
236
|
+
row and since CSS selectors are not zero-based, we are aiming for a value
|
|
237
|
+
of 2 (1 + 1).
|
|
238
|
+
|
|
239
|
+
Ex: When we have nestedCard styled headers, then we have opening and closing
|
|
240
|
+
Chrome rows. Therefore, the first non-header row is the fourth row because:
|
|
241
|
+
- Row 1 is the opening Chrome Row
|
|
242
|
+
- Row 2 is the header
|
|
243
|
+
- Row 3 is the closing Chrome Row
|
|
244
|
+
- Row 4 is the first non-header row
|
|
245
|
+
And since CSS selectors are not zero-based, we are aiming for a value of 4
|
|
246
|
+
(3 + 1).
|
|
247
|
+
*/
|
|
248
|
+
const firstNonHeaderRowIndex = (!isNestedCardStyleHeader ? 1 : 3) + 1;
|
|
218
249
|
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
250
|
+
// Ensure all rows extend the same width
|
|
251
|
+
...Css_1.Css.mw("fit-content").$,
|
|
252
|
+
/*
|
|
253
|
+
Using n + (firstNonHeaderRowIndex + 1) here to target all rows that
|
|
254
|
+
are after the first non-header row. Since n starts at 0, we can use
|
|
255
|
+
the + operator as an offset.
|
|
256
|
+
|
|
257
|
+
Inspired by: https://stackoverflow.com/a/25005740/2551333
|
|
258
|
+
*/
|
|
259
|
+
...(style.betweenRowsCss
|
|
260
|
+
? Css_1.Css.addIn(`& > div:nth-of-type(n + ${firstNonHeaderRowIndex + 1}) > *`, style.betweenRowsCss).$
|
|
261
|
+
: {}),
|
|
262
|
+
...(style.firstNonHeaderRowCss
|
|
263
|
+
? Css_1.Css.addIn(`& > div:nth-of-type(${firstNonHeaderRowIndex}) > *`, style.firstNonHeaderRowCss).$
|
|
264
|
+
: {}),
|
|
226
265
|
...style.rootCss,
|
|
227
266
|
...xss,
|
|
228
|
-
}, "data-testid": id }, { children: [headerRows.map(([, node]) => node), firstRowMessage && (
|
|
267
|
+
}, "data-testid": id }, { children: [headerRows.map(([, node]) => node), firstRowMessage && (0, jsx_runtime_1.jsx)("div", Object.assign({ css: { ...style.firstRowMessageCss } }, { children: firstRowMessage }), void 0), filteredRows.map(([, node]) => node)] }), void 0));
|
|
229
268
|
}
|
|
230
269
|
/** Renders as a table, primarily/solely for good print support. */
|
|
231
270
|
function renderTable(style, id, columns, headerRows, filteredRows, firstRowMessage, _stickyHeader, _firstLastColumnWidth, xss, _virtuosoRef) {
|
|
@@ -259,6 +298,7 @@ function renderTable(style, id, columns, headerRows, filteredRows, firstRowMessa
|
|
|
259
298
|
* [3]: https://github.com/tannerlinsley/react-virtual/issues/108
|
|
260
299
|
*/
|
|
261
300
|
function renderVirtual(style, id, columns, headerRows, filteredRows, firstRowMessage, stickyHeader, firstLastColumnWidth, xss, virtuosoRef) {
|
|
301
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
262
302
|
const { footerStyle, listStyle } = (0, react_1.useMemo)(() => {
|
|
263
303
|
var _a;
|
|
264
304
|
const { paddingBottom, ...otherRootStyles } = (_a = style.rootCss) !== null && _a !== void 0 ? _a : {};
|
|
@@ -279,52 +319,66 @@ function renderVirtual(style, id, columns, headerRows, filteredRows, firstRowMes
|
|
|
279
319
|
// so instead drill into the 1st real content cell.
|
|
280
320
|
return maybeContentsDiv.firstElementChild.getBoundingClientRect().height;
|
|
281
321
|
}, itemContent: (index) => {
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
if (
|
|
286
|
-
return headerRows[
|
|
322
|
+
// Since we have two arrays of rows: `headerRows` and `filteredRow` we
|
|
323
|
+
// must determine which one to render.
|
|
324
|
+
// Determine if we need to render a header row
|
|
325
|
+
if (index < headerRows.length) {
|
|
326
|
+
return headerRows[index][1];
|
|
287
327
|
}
|
|
288
|
-
|
|
328
|
+
// Reset index
|
|
329
|
+
index -= headerRows.length;
|
|
330
|
+
// Show firstRowMessage as the first `filteredRow`
|
|
289
331
|
if (firstRowMessage) {
|
|
290
|
-
if (
|
|
332
|
+
if (index === 0) {
|
|
291
333
|
return ((0, jsx_runtime_1.jsx)("div", Object.assign({ css: Css_1.Css.add("gridColumn", `${columns.length} span`).$ }, { children: (0, jsx_runtime_1.jsx)("div", Object.assign({ css: { ...style.firstRowMessageCss } }, { children: firstRowMessage }), void 0) }), void 0));
|
|
292
334
|
}
|
|
293
|
-
|
|
335
|
+
// Shift index -1 when there is a firstRowMessage to not skip the
|
|
336
|
+
// first `filteredRow`
|
|
337
|
+
index--;
|
|
294
338
|
}
|
|
295
|
-
|
|
339
|
+
// Lastly render `filteredRow`
|
|
340
|
+
return filteredRows[index][1];
|
|
296
341
|
}, totalCount: (headerRows.length || 0) + (firstRowMessage ? 1 : 0) + (filteredRows.length || 0) }, void 0));
|
|
297
342
|
}
|
|
298
343
|
/**
|
|
299
|
-
*
|
|
344
|
+
* A table might render two of these components to represent two virtual lists.
|
|
345
|
+
* This generally happens when `topItemCount` prop is used and React-Virtuoso
|
|
346
|
+
* creates to Virtual lists where the first represents, generally, the header
|
|
347
|
+
* rows and the second represents the non-header rows (list rows).
|
|
348
|
+
*
|
|
349
|
+
* The main goal of this custom component is to:
|
|
350
|
+
* - Customize the list wrapper to our styles
|
|
300
351
|
*
|
|
301
|
-
* We wrap this in memoizeOne so that React.createElement sees a
|
|
302
|
-
* identity, even though technically we have a
|
|
303
|
-
*
|
|
352
|
+
* We wrap this in memoizeOne so that React.createElement sees a
|
|
353
|
+
* consistent/stable component identity, even though technically we have a
|
|
354
|
+
* different "component" per the given set of props (solely to capture as
|
|
355
|
+
* params that we can't pass through react-virtuoso's API as props).
|
|
304
356
|
*/
|
|
305
|
-
const VirtualRoot = (0, memoize_one_1.default)((gs,
|
|
357
|
+
const VirtualRoot = (0, memoize_one_1.default)((gs, _columns, id, _firstLastColumnWidth, xss) => {
|
|
306
358
|
return react_1.default.forwardRef(function VirtualRoot({ style, children }, ref) {
|
|
307
|
-
// This
|
|
308
|
-
|
|
359
|
+
// This VirtualRoot list represent the header when no styles are given. The
|
|
360
|
+
// table list generally has styles to scroll the page for windowing.
|
|
361
|
+
const isHeader = Object.keys(style || {}).length === 0;
|
|
362
|
+
// This re-renders each time we have new children in the viewport
|
|
363
|
+
return ((0, jsx_runtime_1.jsx)("div", Object.assign({ ref: ref, style: { ...style, ...{ minWidth: "fit-content" } }, css: {
|
|
309
364
|
// Add an extra `> div` due to Item + itemContent both having divs
|
|
310
365
|
...Css_1.Css.addIn("& > div + div > div > *", gs.betweenRowsCss || {}).$,
|
|
366
|
+
// Table list styles only
|
|
367
|
+
...(isHeader
|
|
368
|
+
? {}
|
|
369
|
+
: {
|
|
370
|
+
...Css_1.Css.addIn("& > div:first-of-type > *", gs.firstNonHeaderRowCss).$,
|
|
371
|
+
}),
|
|
311
372
|
...gs.rootCss,
|
|
312
373
|
...xss,
|
|
313
374
|
}, "data-testid": id }, { children: children }), void 0));
|
|
314
375
|
});
|
|
315
376
|
});
|
|
316
377
|
/**
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
* Because of two things:
|
|
320
|
-
*
|
|
321
|
-
* a) react-virtuoso puts the header in a different div than the normal rows, and
|
|
322
|
-
*
|
|
323
|
-
* b) content-aware sizing just in general look janky/constantly resize while scrolling
|
|
324
|
-
*
|
|
325
|
-
* When we're as=virtual, we change our default + enforce only fixed-sized units (% and px)
|
|
378
|
+
* Calculates column widths using a flexible `calc()` definition that allows for consistent column alignment without the use of `<table />`, CSS Grid, etc layouts.
|
|
379
|
+
* Enforces only fixed-sized units (% and px)
|
|
326
380
|
*/
|
|
327
|
-
function
|
|
381
|
+
function calcColumnSizes(columns, firstLastColumnWidth) {
|
|
328
382
|
// For both default columns (1fr) as well as `w: 4fr` columns, we translate the width into an expression that looks like:
|
|
329
383
|
// calc((100% - allOtherPercent - allOtherPx) * ((myFr / totalFr))`
|
|
330
384
|
//
|
|
@@ -350,7 +404,7 @@ function calcVirtualGridColumns(columns, firstLastColumnWidth) {
|
|
|
350
404
|
return { ...acc, claimedPercentages: acc.claimedPercentages + Number(w.replace("%", "")) };
|
|
351
405
|
}
|
|
352
406
|
else {
|
|
353
|
-
throw new Error("
|
|
407
|
+
throw new Error("Beam Table column width definition only supports px, percentage, or fr units");
|
|
354
408
|
}
|
|
355
409
|
}, { claimedPercentages: 0, claimedPixels: firstLastColumnWidth ? firstLastColumnWidth * 2 : 0, totalFr: 0 });
|
|
356
410
|
// This is our "fake but for some reason it lines up better" fr calc
|
|
@@ -369,7 +423,7 @@ function calcVirtualGridColumns(columns, firstLastColumnWidth) {
|
|
|
369
423
|
return fr(Number(w.replace("fr", "")));
|
|
370
424
|
}
|
|
371
425
|
else {
|
|
372
|
-
throw new Error("
|
|
426
|
+
throw new Error("Beam Table column width definition only supports px, percentage, or fr units");
|
|
373
427
|
}
|
|
374
428
|
}
|
|
375
429
|
else {
|
|
@@ -378,25 +432,7 @@ function calcVirtualGridColumns(columns, firstLastColumnWidth) {
|
|
|
378
432
|
});
|
|
379
433
|
return maybeAddCardColumns(sizes, firstLastColumnWidth);
|
|
380
434
|
}
|
|
381
|
-
exports.
|
|
382
|
-
function calcDivGridColumns(columns, firstLastColumnWidth) {
|
|
383
|
-
const sizes = columns.map(({ w }) => {
|
|
384
|
-
if (typeof w === "undefined") {
|
|
385
|
-
// Hrm, I waffle between 'auto' or '1fr' being the better default here...
|
|
386
|
-
return "auto";
|
|
387
|
-
}
|
|
388
|
-
else if (typeof w === "string") {
|
|
389
|
-
// Use whatever the user passed in
|
|
390
|
-
return w;
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
// Otherwise assume fr units
|
|
394
|
-
return `${w}fr`;
|
|
395
|
-
}
|
|
396
|
-
});
|
|
397
|
-
return maybeAddCardColumns(sizes, firstLastColumnWidth).join(" ");
|
|
398
|
-
}
|
|
399
|
-
exports.calcDivGridColumns = calcDivGridColumns;
|
|
435
|
+
exports.calcColumnSizes = calcColumnSizes;
|
|
400
436
|
// If we're doing nested cards, we add extra 1st/last cells...
|
|
401
437
|
function maybeAddCardColumns(sizes, firstLastColumnWidth) {
|
|
402
438
|
return !firstLastColumnWidth ? sizes : [`${firstLastColumnWidth}px`, ...sizes, `${firstLastColumnWidth}px`];
|
|
@@ -420,19 +456,15 @@ function GridRow(props) {
|
|
|
420
456
|
const rowStyle = rowStyles === null || rowStyles === void 0 ? void 0 : rowStyles[row.kind];
|
|
421
457
|
const rowStyleCellCss = maybeApplyFunction(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.cellCss);
|
|
422
458
|
const rowCss = {
|
|
423
|
-
// We add a display-contents so that we can have "row-level" div elements in our
|
|
424
|
-
// DOM structure. I.e. grid is normally root-element > cell-elements, but we want
|
|
425
|
-
// root-element > row-element > cell-elements, so that we can have a hook for
|
|
426
|
-
// hovers and styling. In theory this would change with subgrids.
|
|
427
|
-
// Only enable when using div as elements
|
|
428
459
|
// For virtual tables use `display: flex` to keep all cells on the same row, but use `flexNone` to ensure the cells stay their defined widths
|
|
429
|
-
...(as === "table" ? {} :
|
|
460
|
+
...(as === "table" ? {} : Css_1.Css.df.addIn("&>*", Css_1.Css.flexNone.$).$),
|
|
430
461
|
...(((rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowLink) || (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.onClick)) &&
|
|
431
462
|
style.rowHoverColor && {
|
|
432
463
|
// Even though backgroundColor is set on the cellCss (due to display: content), the hover target is the row.
|
|
433
464
|
"&:hover > *": Css_1.Css.cursorPointer.bgColor(maybeDarken(rowStyleCellCss === null || rowStyleCellCss === void 0 ? void 0 : rowStyleCellCss.backgroundColor, style.rowHoverColor)).$,
|
|
434
465
|
}),
|
|
435
466
|
...maybeApplyFunction(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowCss),
|
|
467
|
+
...(isHeader && stickyHeader ? Css_1.Css.sticky.top(stickyOffset).z1.$ : undefined),
|
|
436
468
|
};
|
|
437
469
|
const Row = as === "table" ? "tr" : "div";
|
|
438
470
|
const openCardStyles = typeof openCards === "string"
|
|
@@ -483,18 +515,11 @@ function GridRow(props) {
|
|
|
483
515
|
...getIndentationCss(style, rowStyle, columnIndex, maybeContent),
|
|
484
516
|
// Then apply any header-specific override
|
|
485
517
|
...(isHeader && style.headerCellCss),
|
|
486
|
-
// Non-virtualized tables use h100 so that all cells are the same height across the row.
|
|
487
|
-
// Virtualized table rows use `display: flex;`, so the flex children are set to `align-self: stretch` by default, which achieves the same goal.
|
|
488
|
-
// Though, we need to omit setting `h100` on the flex children, as a flex container needs a defined height set for `h100` to work on flex children
|
|
489
|
-
...(isHeader && as !== "virtual" ? Css_1.Css.h100.$ : undefined),
|
|
490
|
-
...maybeStickyHeaderStyles,
|
|
491
518
|
// If we're within a card, use its background color
|
|
492
519
|
...(currentCard && Css_1.Css.bgColor(currentCard.bgColor).$),
|
|
493
|
-
// Add in colspan css if needed
|
|
494
|
-
...(currentColspan > 1 ? Css_1.Css.gc(`span ${currentColspan}`).$ : {}),
|
|
495
520
|
// And finally the specific cell's css (if any from GridCellContent)
|
|
496
521
|
...rowStyleCellCss,
|
|
497
|
-
//
|
|
522
|
+
// Define the width of the column on each cell. Supports col spans.
|
|
498
523
|
...(columnSizes && {
|
|
499
524
|
width: `calc(${columnSizes
|
|
500
525
|
.slice(maybeNestedCardColumnIndex, maybeNestedCardColumnIndex + currentColspan)
|
|
@@ -581,8 +606,8 @@ function applyRowFn(column, row) {
|
|
|
581
606
|
exports.applyRowFn = applyRowFn;
|
|
582
607
|
/** Renders our default cell element, i.e. if no row links and no custom renderCell are used. */
|
|
583
608
|
const defaultRenderFn = (as) => (key, css, content) => {
|
|
584
|
-
const
|
|
585
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
609
|
+
const Cell = as === "table" ? "td" : "div";
|
|
610
|
+
return ((0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...tableRowStyles(as) } }, { children: content }), key));
|
|
586
611
|
};
|
|
587
612
|
exports.GridCollapseContext = react_1.default.createContext({
|
|
588
613
|
headerCollapsed: false,
|
|
@@ -6,6 +6,7 @@ const react_1 = require("react");
|
|
|
6
6
|
const Icon_1 = require("../Icon");
|
|
7
7
|
const GridSortContext_1 = require("./GridSortContext");
|
|
8
8
|
const Css_1 = require("../../Css");
|
|
9
|
+
const hooks_1 = require("../../hooks");
|
|
9
10
|
const useTestIds_1 = require("../../utils/useTestIds");
|
|
10
11
|
/**
|
|
11
12
|
* Wraps column header names with up/down sorting icons.
|
|
@@ -20,8 +21,12 @@ const useTestIds_1 = require("../../utils/useTestIds");
|
|
|
20
21
|
*/
|
|
21
22
|
function SortHeader(props) {
|
|
22
23
|
const { content, xss } = props;
|
|
24
|
+
const { isHovered, hoverProps } = (0, hooks_1.useHover)({});
|
|
23
25
|
const { sorted, toggleSort } = (0, react_1.useContext)(GridSortContext_1.GridSortContext);
|
|
24
26
|
const tid = (0, useTestIds_1.useTestIds)(props, "sortHeader");
|
|
25
|
-
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({}, tid, { css: { ...Css_1.Css.df.aic.cursorPointer.selectNone.$, ...xss }, onClick: toggleSort }, { children: [content,
|
|
27
|
+
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({}, tid, { css: { ...Css_1.Css.df.aic.h100.cursorPointer.selectNone.$, ...xss } }, hoverProps, { onClick: toggleSort }, { children: [content, (0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.fs0.$ }, { children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, Object.assign({ icon: sorted === "DESC" ? "sortDown" : "sortUp", color: sorted !== undefined ? Css_1.Palette.LightBlue700 : Css_1.Palette.Gray400, xss: Css_1.Css.ml1
|
|
28
|
+
.visibility("hidden")
|
|
29
|
+
.if(isHovered || sorted !== undefined)
|
|
30
|
+
.visibility("visible").$, inc: 2 }, tid.icon), void 0) }), void 0)] }), void 0));
|
|
26
31
|
}
|
|
27
32
|
exports.SortHeader = SortHeader;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ReactElement } from "react";
|
|
2
|
-
import { GridColumn, GridDataRow,
|
|
2
|
+
import { GridColumn, GridDataRow, Kinded, NestedCardsStyle, NestedCardStyle, NestedCardStyleByKind, RowTuple } from "./GridTable";
|
|
3
|
+
declare type Chrome = () => JSX.Element;
|
|
4
|
+
declare type ChromeBuffer = Chrome[];
|
|
3
5
|
/**
|
|
4
6
|
* A helper class to create our nested card DOM shenanigans.
|
|
5
7
|
*
|
|
@@ -12,22 +14,47 @@ import { GridColumn, GridDataRow, GridStyle, Kinded, NestedCardsStyle, NestedCar
|
|
|
12
14
|
* a content row itself, the nested padding is handled separately by the
|
|
13
15
|
* GridRow component.
|
|
14
16
|
*/
|
|
15
|
-
declare type Chrome = () => JSX.Element;
|
|
16
|
-
declare type ChromeBuffer = Chrome[];
|
|
17
17
|
export declare class NestedCards {
|
|
18
|
-
private columns;
|
|
19
|
-
private
|
|
20
|
-
private
|
|
18
|
+
private readonly columns;
|
|
19
|
+
private readonly rows;
|
|
20
|
+
private readonly styles;
|
|
21
21
|
private readonly openCards;
|
|
22
22
|
private readonly chromeBuffer;
|
|
23
|
-
private
|
|
24
|
-
constructor(columns: GridColumn<any>[],
|
|
23
|
+
private chromeRowIndex;
|
|
24
|
+
constructor(columns: GridColumn<any>[], rows: RowTuple<any>[], styles: NestedCardsStyle);
|
|
25
|
+
/**
|
|
26
|
+
* Maybe add an opening Chrome row to the given `row` if its a nested card.
|
|
27
|
+
*
|
|
28
|
+
* @param row The row which will be opened. The open Chrome row will appear
|
|
29
|
+
* above this row.
|
|
30
|
+
*/
|
|
25
31
|
maybeOpenCard(row: GridDataRow<any>): boolean;
|
|
26
32
|
closeCard(): void;
|
|
27
33
|
addSpacer(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Close the remaining open rows with a close Chrome row.
|
|
36
|
+
*
|
|
37
|
+
* @param row The row that is completing/closing nested open Chrome rows.
|
|
38
|
+
*/
|
|
28
39
|
done(): void;
|
|
29
40
|
/** Return a stable copy of the cards, so it won't change as we keep going. */
|
|
30
41
|
currentOpenCards(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Takes the current Chrome row buffer of close row(s), spacers, and open row,
|
|
44
|
+
* and creates a single chrome DOM row.
|
|
45
|
+
*
|
|
46
|
+
* This allows a minimal amount of DOM overhead, insofar as to the css-grid or
|
|
47
|
+
* react-virtuoso we only add 1 extra DOM node between each row of content to
|
|
48
|
+
* achieve our nested card look & feel.
|
|
49
|
+
*
|
|
50
|
+
* i.e.:
|
|
51
|
+
* - chrome row (open)
|
|
52
|
+
* - card1 content row
|
|
53
|
+
* - chrome row (card2 open)
|
|
54
|
+
* - nested card2 content row
|
|
55
|
+
* - chrome row (card2 close, card1 close)
|
|
56
|
+
*/
|
|
57
|
+
maybeCreateChromeRow(): void;
|
|
31
58
|
}
|
|
32
59
|
/**
|
|
33
60
|
* Draws the rounded corners (either open or close) for a new card.
|
|
@@ -55,23 +82,10 @@ export declare function maybeAddCardPadding(openCards: NestedCardStyle[], column
|
|
|
55
82
|
* have any open cards, but still want a space between top-level cards.
|
|
56
83
|
*/
|
|
57
84
|
export declare function makeSpacer(height: number, openCards: string[], styles: NestedCardsStyle): Chrome;
|
|
58
|
-
/**
|
|
59
|
-
* Takes the current buffer of close row(s), spacers, and open row, and creates a single chrome DOM row.
|
|
60
|
-
*
|
|
61
|
-
* This allows a minimal amount of DOM overhead, insofar as to the css-grid or react-virtuoso we only
|
|
62
|
-
* 1 extra DOM node between each row of content to achieve our nested card look & feel, i.e.:
|
|
63
|
-
*
|
|
64
|
-
* - chrome row (open)
|
|
65
|
-
* - card1 content row
|
|
66
|
-
* - chrome row (card2 open)
|
|
67
|
-
* - nested card2 content row
|
|
68
|
-
* - chrome row (card2 close, card1 close)
|
|
69
|
-
*/
|
|
70
|
-
export declare function maybeCreateChromeRow(columns: GridColumn<any>[], filteredRows: RowTuple<any>[], chromeBuffer: ChromeBuffer): void;
|
|
71
85
|
interface ChromeRowProps {
|
|
72
86
|
chromeBuffer: ChromeBuffer;
|
|
73
87
|
columns: number;
|
|
74
88
|
}
|
|
75
89
|
export declare function ChromeRow({ chromeBuffer, columns }: ChromeRowProps): import("@emotion/react/jsx-runtime").JSX.Element;
|
|
76
|
-
export declare function dropChromeRows<R extends Kinded>(
|
|
90
|
+
export declare function dropChromeRows<R extends Kinded>(rows: RowTuple<R>[]): [GridDataRow<R>, ReactElement][];
|
|
77
91
|
export {};
|
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.dropChromeRows = exports.ChromeRow = exports.
|
|
3
|
+
exports.dropChromeRows = exports.ChromeRow = exports.makeSpacer = exports.maybeAddCardPadding = exports.makeOpenOrCloseCard = exports.NestedCards = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const Css_1 = require("../../Css");
|
|
7
|
+
/**
|
|
8
|
+
* A helper class to create our nested card DOM shenanigans.
|
|
9
|
+
*
|
|
10
|
+
* This acts as a one-off visitor that accepts "begin row", "between row",
|
|
11
|
+
* "end row" calls from GridTable while its translating the user's nested
|
|
12
|
+
* GridDataRows into a flat list of RowTuples, and interjects fake/chrome
|
|
13
|
+
* rows into `filteredRows` as necessary.
|
|
14
|
+
*
|
|
15
|
+
* Note that this class only handles *between row* chrome and that within
|
|
16
|
+
* a content row itself, the nested padding is handled separately by the
|
|
17
|
+
* GridRow component.
|
|
18
|
+
*/
|
|
7
19
|
class NestedCards {
|
|
8
|
-
constructor(columns,
|
|
20
|
+
constructor(columns,
|
|
21
|
+
// An array of rows which we will add open Chrome rows too to create the table.
|
|
22
|
+
rows, styles) {
|
|
9
23
|
this.columns = columns;
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
24
|
+
this.rows = rows;
|
|
25
|
+
this.styles = styles;
|
|
12
26
|
// A stack of the current cards we're showing
|
|
13
27
|
this.openCards = [];
|
|
14
28
|
// A buffer of the open/close/spacer rows we need between each content row.
|
|
15
29
|
this.chromeBuffer = [];
|
|
16
|
-
this.
|
|
30
|
+
this.chromeRowIndex = 0;
|
|
17
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Maybe add an opening Chrome row to the given `row` if its a nested card.
|
|
34
|
+
*
|
|
35
|
+
* @param row The row which will be opened. The open Chrome row will appear
|
|
36
|
+
* above this row.
|
|
37
|
+
*/
|
|
18
38
|
maybeOpenCard(row) {
|
|
19
39
|
const card = this.styles.kinds[row.kind];
|
|
20
40
|
// If this kind doesn't have a card defined, don't put it on the card stack
|
|
@@ -23,7 +43,7 @@ class NestedCards {
|
|
|
23
43
|
this.chromeBuffer.push(makeOpenOrCloseCard(this.openCards, this.styles.kinds, "open"));
|
|
24
44
|
}
|
|
25
45
|
// But always close previous cards if needed
|
|
26
|
-
maybeCreateChromeRow(
|
|
46
|
+
this.maybeCreateChromeRow();
|
|
27
47
|
return !!card;
|
|
28
48
|
}
|
|
29
49
|
closeCard() {
|
|
@@ -33,13 +53,43 @@ class NestedCards {
|
|
|
33
53
|
addSpacer() {
|
|
34
54
|
this.chromeBuffer.push(makeSpacer(this.styles.spacerPx, this.openCards, this.styles));
|
|
35
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Close the remaining open rows with a close Chrome row.
|
|
58
|
+
*
|
|
59
|
+
* @param row The row that is completing/closing nested open Chrome rows.
|
|
60
|
+
*/
|
|
36
61
|
done() {
|
|
37
|
-
maybeCreateChromeRow(
|
|
62
|
+
this.maybeCreateChromeRow();
|
|
38
63
|
}
|
|
39
64
|
/** Return a stable copy of the cards, so it won't change as we keep going. */
|
|
40
65
|
currentOpenCards() {
|
|
41
66
|
return this.openCards.join(":");
|
|
42
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Takes the current Chrome row buffer of close row(s), spacers, and open row,
|
|
70
|
+
* and creates a single chrome DOM row.
|
|
71
|
+
*
|
|
72
|
+
* This allows a minimal amount of DOM overhead, insofar as to the css-grid or
|
|
73
|
+
* react-virtuoso we only add 1 extra DOM node between each row of content to
|
|
74
|
+
* achieve our nested card look & feel.
|
|
75
|
+
*
|
|
76
|
+
* i.e.:
|
|
77
|
+
* - chrome row (open)
|
|
78
|
+
* - card1 content row
|
|
79
|
+
* - chrome row (card2 open)
|
|
80
|
+
* - nested card2 content row
|
|
81
|
+
* - chrome row (card2 close, card1 close)
|
|
82
|
+
*/
|
|
83
|
+
maybeCreateChromeRow() {
|
|
84
|
+
if (this.chromeBuffer.length > 0) {
|
|
85
|
+
this.rows.push([
|
|
86
|
+
undefined,
|
|
87
|
+
(0, jsx_runtime_1.jsx)(ChromeRow, { chromeBuffer: [...this.chromeBuffer], columns: this.columns.length }, this.chromeRowIndex++),
|
|
88
|
+
]);
|
|
89
|
+
// clear the Chrome buffer
|
|
90
|
+
this.chromeBuffer.splice(0, this.chromeBuffer.length);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
43
93
|
}
|
|
44
94
|
exports.NestedCards = NestedCards;
|
|
45
95
|
/**
|
|
@@ -125,33 +175,13 @@ function makeSpacer(height, openCards, styles) {
|
|
|
125
175
|
};
|
|
126
176
|
}
|
|
127
177
|
exports.makeSpacer = makeSpacer;
|
|
128
|
-
/**
|
|
129
|
-
* Takes the current buffer of close row(s), spacers, and open row, and creates a single chrome DOM row.
|
|
130
|
-
*
|
|
131
|
-
* This allows a minimal amount of DOM overhead, insofar as to the css-grid or react-virtuoso we only
|
|
132
|
-
* 1 extra DOM node between each row of content to achieve our nested card look & feel, i.e.:
|
|
133
|
-
*
|
|
134
|
-
* - chrome row (open)
|
|
135
|
-
* - card1 content row
|
|
136
|
-
* - chrome row (card2 open)
|
|
137
|
-
* - nested card2 content row
|
|
138
|
-
* - chrome row (card2 close, card1 close)
|
|
139
|
-
*/
|
|
140
|
-
function maybeCreateChromeRow(columns, filteredRows, chromeBuffer) {
|
|
141
|
-
if (chromeBuffer.length > 0) {
|
|
142
|
-
filteredRows.push([undefined, (0, jsx_runtime_1.jsx)(ChromeRow, { chromeBuffer: [...chromeBuffer], columns: columns.length }, void 0)]);
|
|
143
|
-
// clear the buffer
|
|
144
|
-
chromeBuffer.splice(0, chromeBuffer.length);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
exports.maybeCreateChromeRow = maybeCreateChromeRow;
|
|
148
178
|
function ChromeRow({ chromeBuffer, columns }) {
|
|
149
179
|
return (
|
|
150
180
|
// We add 2 to account for our dedicated open/close columns
|
|
151
181
|
(0, jsx_runtime_1.jsx)("div", Object.assign({ css: Css_1.Css.gc(`span ${columns + 2}`).$, "data-chrome": "true" }, { children: chromeBuffer.map((c, i) => ((0, jsx_runtime_1.jsx)(react_1.Fragment, { children: c() }, i))) }), void 0));
|
|
152
182
|
}
|
|
153
183
|
exports.ChromeRow = ChromeRow;
|
|
154
|
-
function dropChromeRows(
|
|
155
|
-
return
|
|
184
|
+
function dropChromeRows(rows) {
|
|
185
|
+
return rows.filter(([r]) => !!r);
|
|
156
186
|
}
|
|
157
187
|
exports.dropChromeRows = dropChromeRows;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { GridCellContent, GridColumn, GridDataRow, GridSortConfig, Kinded } from "./GridTable";
|
|
3
3
|
import { SortState } from "./useSortState";
|
|
4
|
-
export declare function sortRows<R extends Kinded>(columns: GridColumn<R>[], rows: GridDataRow<R>[], sortState: SortState<number>):
|
|
4
|
+
export declare function sortRows<R extends Kinded>(columns: GridColumn<R>[], rows: GridDataRow<R>[], sortState: SortState<number>): GridDataRow<R>[];
|
|
5
5
|
export declare function ensureClientSideSortValueIsSortable(sorting: GridSortConfig<any> | undefined, isHeader: boolean, column: GridColumn<any>, idx: number, maybeContent: ReactNode | GridCellContent): void;
|
|
@@ -2,21 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ensureClientSideSortValueIsSortable = exports.sortRows = void 0;
|
|
4
4
|
const GridTable_1 = require("./GridTable");
|
|
5
|
-
//
|
|
6
|
-
// read from an immutable store like the apollo cache, but we basically always make
|
|
7
|
-
// a copy in the process of adding our `kind` tags.
|
|
8
|
-
//
|
|
9
|
-
// I suppose that is an interesting idea, would we ever want to render a GQL query/cache
|
|
10
|
-
// result directly into the table without first doing a kind-mapping? Like maybe we could
|
|
11
|
-
// use __typename as the kind.
|
|
5
|
+
// Returns a shallow copy of the `rows` parameter sorted based on `sortState`
|
|
12
6
|
function sortRows(columns, rows, sortState) {
|
|
13
|
-
sortBatch(columns, rows, sortState);
|
|
7
|
+
const sorted = sortBatch(columns, rows, sortState);
|
|
14
8
|
// Recursively sort child rows
|
|
15
|
-
|
|
9
|
+
sorted.forEach((row, i) => {
|
|
16
10
|
if (row.children) {
|
|
17
|
-
sortRows(columns, row.children, sortState);
|
|
11
|
+
sorted[i] = { ...sorted[i], children: sortRows(columns, row.children, sortState) };
|
|
18
12
|
}
|
|
19
|
-
}
|
|
13
|
+
});
|
|
14
|
+
return sorted;
|
|
20
15
|
}
|
|
21
16
|
exports.sortRows = sortRows;
|
|
22
17
|
function sortBatch(columns, batch, sortState) {
|
|
@@ -24,7 +19,8 @@ function sortBatch(columns, batch, sortState) {
|
|
|
24
19
|
const [value, direction] = sortState;
|
|
25
20
|
const column = columns[value];
|
|
26
21
|
const invert = direction === "DESC";
|
|
27
|
-
|
|
22
|
+
// Make a shallow copy for sorting to avoid mutating the original list
|
|
23
|
+
return [...batch].sort((a, b) => {
|
|
28
24
|
const v1 = sortValue((0, GridTable_1.applyRowFn)(column, a));
|
|
29
25
|
const v2 = sortValue((0, GridTable_1.applyRowFn)(column, b));
|
|
30
26
|
const v1e = v1 === null || v1 === undefined;
|
|
@@ -10,3 +10,4 @@ import { Direction, GridColumn, GridSortConfig, Kinded } from "./GridTable";
|
|
|
10
10
|
export declare type SortState<S> = readonly [S, Direction];
|
|
11
11
|
/** Small custom hook that wraps the "setSortColumn inverts the current sort" logic. */
|
|
12
12
|
export declare function useSortState<R extends Kinded, S>(columns: GridColumn<R, S>[], sorting?: GridSortConfig<S>): [SortState<S> | undefined, (value: S) => void];
|
|
13
|
+
export declare function deriveSortState<S>(currentSortState: SortState<S> | undefined, clickedKey: S, initialSortState: SortState<S> | undefined): SortState<S> | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useSortState = void 0;
|
|
3
|
+
exports.deriveSortState = exports.useSortState = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const GridTable_1 = require("./GridTable");
|
|
6
6
|
/** Small custom hook that wraps the "setSortColumn inverts the current sort" logic. */
|
|
@@ -8,34 +8,34 @@ function useSortState(columns, sorting) {
|
|
|
8
8
|
// If we're server-side sorting, use the caller's `sorting.value` prop to initialize our internal
|
|
9
9
|
// `useState`. After this, we ignore `sorting.value` because we assume it should match what our
|
|
10
10
|
// `setSortState` just changed anyway (in response to the user sorting a column).
|
|
11
|
-
const
|
|
11
|
+
const initialSortState = (0, react_1.useMemo)(() => {
|
|
12
12
|
if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client") {
|
|
13
13
|
const { initial } = sorting;
|
|
14
|
-
if (initial) {
|
|
14
|
+
if (initial === undefined && "initial" in sorting) {
|
|
15
|
+
// if explicitly set to `undefined`, then do not sort
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
else if (initial) {
|
|
15
19
|
const key = typeof initial[0] === "number" ? initial[0] : columns.indexOf(initial[0]);
|
|
16
20
|
return [key, initial[1]];
|
|
17
21
|
}
|
|
18
22
|
else {
|
|
19
23
|
// If no explicit sorting, assume 1st column ascending
|
|
20
24
|
const firstSortableColumn = columns.findIndex((c) => c.clientSideSort !== false);
|
|
21
|
-
return [firstSortableColumn,
|
|
25
|
+
return [firstSortableColumn, GridTable_1.ASC];
|
|
22
26
|
}
|
|
23
27
|
}
|
|
24
28
|
else {
|
|
25
29
|
return sorting === null || sorting === void 0 ? void 0 : sorting.value;
|
|
26
30
|
}
|
|
27
|
-
});
|
|
28
|
-
|
|
31
|
+
}, [sorting, columns]);
|
|
32
|
+
const [sortState, setSortState] = (0, react_1.useState)(initialSortState);
|
|
33
|
+
// Make a custom setSortKey that is useState-like but contains the ASC->DESC->RESET logic.
|
|
29
34
|
const setSortKey = (0, react_1.useCallback)((clickedKey) => {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
// If clickedKey === currentKey, then toggle direction
|
|
33
|
-
clickedKey === currentKey
|
|
34
|
-
? [currentKey, currentDirection === GridTable_1.ASC ? GridTable_1.DESC : GridTable_1.ASC]
|
|
35
|
-
: // Otherwise, use the new key, and default to ascending
|
|
36
|
-
[clickedKey, GridTable_1.ASC];
|
|
37
|
-
setSortState([newKey, newDirection]);
|
|
35
|
+
const newState = deriveSortState(sortState, clickedKey, initialSortState);
|
|
36
|
+
setSortState(newState);
|
|
38
37
|
if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "server") {
|
|
38
|
+
const [newKey, newDirection] = newState !== null && newState !== void 0 ? newState : [undefined, undefined];
|
|
39
39
|
sorting.onSort(newKey, newDirection);
|
|
40
40
|
}
|
|
41
41
|
},
|
|
@@ -44,3 +44,19 @@ function useSortState(columns, sorting) {
|
|
|
44
44
|
return [sortState, setSortKey];
|
|
45
45
|
}
|
|
46
46
|
exports.useSortState = useSortState;
|
|
47
|
+
// Exported for testing purposes
|
|
48
|
+
function deriveSortState(currentSortState, clickedKey, initialSortState) {
|
|
49
|
+
const [currentKey, currentDirection] = currentSortState || [];
|
|
50
|
+
// If the current sort state is not defined, or clicking a new column, then sort ASC on the clicked key
|
|
51
|
+
if (!currentSortState || clickedKey !== currentKey) {
|
|
52
|
+
return [clickedKey, GridTable_1.ASC];
|
|
53
|
+
}
|
|
54
|
+
// Otherwise when clicking the current column, toggle through sort states
|
|
55
|
+
if (currentDirection === GridTable_1.ASC) {
|
|
56
|
+
// if ASC -> go to desc
|
|
57
|
+
return [clickedKey, GridTable_1.DESC];
|
|
58
|
+
}
|
|
59
|
+
// Else, direction is already DESC, so revert to original sort value.
|
|
60
|
+
return initialSortState;
|
|
61
|
+
}
|
|
62
|
+
exports.deriveSortState = deriveSortState;
|
|
@@ -4,40 +4,27 @@ exports.CompoundField = void 0;
|
|
|
4
4
|
const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const Css_1 = require("../../Css");
|
|
7
|
-
const utils_1 = require("../../utils");
|
|
8
7
|
/** Internal component to help create compound fields */
|
|
9
8
|
function CompoundField({ children }) {
|
|
10
9
|
if ((children === null || children === void 0 ? void 0 : children.length) !== 2) {
|
|
11
10
|
throw global.Error("CompoundField requires two children components");
|
|
12
11
|
}
|
|
13
|
-
const [focusedEl, setFocusedEl] = (0, react_1.useState)();
|
|
14
12
|
const commonStyles = Css_1.Css.df.aic.fs1.maxwPx(550).bt.bb.bGray300.$;
|
|
15
13
|
const internalProps = { compound: true };
|
|
16
|
-
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css:
|
|
14
|
+
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
|
|
15
|
+
...Css_1.Css.df.$,
|
|
16
|
+
"&:focus-within > div:nth-of-type(2)": Css_1.Css.bgLightBlue700.$, // Separation line when inputs are focused
|
|
17
|
+
} }, { children: [(0, jsx_runtime_1.jsx)("div", Object.assign({ css: {
|
|
17
18
|
...commonStyles,
|
|
18
|
-
...Css_1.Css.bl.borderRadius("4px 0 0 4px")
|
|
19
|
+
...Css_1.Css.bl.borderRadius("4px 0 0 4px").$,
|
|
20
|
+
"&:focus-within": Css_1.Css.bLightBlue700.$,
|
|
19
21
|
} }, { children: (0, react_1.cloneElement)(children[0], {
|
|
20
|
-
onFocus: () => {
|
|
21
|
-
(0, utils_1.maybeCall)(children[0].props.onFocus);
|
|
22
|
-
setFocusedEl("left");
|
|
23
|
-
},
|
|
24
|
-
onBlur: () => {
|
|
25
|
-
(0, utils_1.maybeCall)(children[0].props.onBlur);
|
|
26
|
-
setFocusedEl(undefined);
|
|
27
|
-
},
|
|
28
22
|
internalProps,
|
|
29
|
-
}) }), void 0), (0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.wPx(1).flexNone.bgGray300
|
|
23
|
+
}) }), void 0), (0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.wPx(1).flexNone.bgGray300.$ }, void 0), (0, jsx_runtime_1.jsx)("div", Object.assign({ css: {
|
|
30
24
|
...commonStyles,
|
|
31
|
-
...Css_1.Css.fg1.br.borderRadius("0 4px 4px 0")
|
|
25
|
+
...Css_1.Css.fg1.br.borderRadius("0 4px 4px 0").$,
|
|
26
|
+
"&:focus-within": Css_1.Css.bLightBlue700.$,
|
|
32
27
|
} }, { children: (0, react_1.cloneElement)(children[1], {
|
|
33
|
-
onFocus: () => {
|
|
34
|
-
(0, utils_1.maybeCall)(children[1].props.onFocus);
|
|
35
|
-
setFocusedEl("right");
|
|
36
|
-
},
|
|
37
|
-
onBlur: () => {
|
|
38
|
-
(0, utils_1.maybeCall)(children[1].props.onBlur);
|
|
39
|
-
setFocusedEl(undefined);
|
|
40
|
-
},
|
|
41
28
|
internalProps,
|
|
42
29
|
}) }), void 0)] }), void 0));
|
|
43
30
|
}
|