@homebound/beam 2.99.1 → 2.101.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Icon.d.ts +1 -1
- package/dist/components/Table/GridTable.d.ts +9 -30
- package/dist/components/Table/GridTable.js +25 -60
- package/dist/components/Table/SortHeader.js +6 -1
- 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/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
|
/**
|
|
@@ -103,13 +103,13 @@ export declare type RowTuple<R extends Kinded> = [GridDataRow<R> | undefined, Re
|
|
|
103
103
|
export declare type GridSortConfig<S> = {
|
|
104
104
|
on: "client";
|
|
105
105
|
/** The optional initial column (index in columns) and direction to sort. */
|
|
106
|
-
initial?: [S | GridColumn<any>, Direction];
|
|
106
|
+
initial?: [S | GridColumn<any>, Direction] | undefined;
|
|
107
107
|
} | {
|
|
108
108
|
on: "server";
|
|
109
109
|
/** The current sort by value + direction (if server-side sorting). */
|
|
110
110
|
value?: [S, Direction];
|
|
111
|
-
/** Callback for when the column is sorted (if server-side sorting). */
|
|
112
|
-
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;
|
|
113
113
|
};
|
|
114
114
|
export interface GridTableProps<R extends Kinded, S, X> {
|
|
115
115
|
id?: string;
|
|
@@ -185,18 +185,10 @@ export declare type GridTableApi = {
|
|
|
185
185
|
*/
|
|
186
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;
|
|
187
187
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* Because of two things:
|
|
191
|
-
*
|
|
192
|
-
* a) react-virtuoso puts the header in a different div than the normal rows, and
|
|
193
|
-
*
|
|
194
|
-
* b) content-aware sizing just in general look janky/constantly resize while scrolling
|
|
195
|
-
*
|
|
196
|
-
* 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)
|
|
197
190
|
*/
|
|
198
|
-
export declare function
|
|
199
|
-
export declare function calcDivGridColumns(columns: GridColumn<any>[], firstLastColumnWidth: number | undefined): string;
|
|
191
|
+
export declare function calcColumnSizes(columns: GridColumn<any>[], firstLastColumnWidth: number | undefined): string[];
|
|
200
192
|
/**
|
|
201
193
|
* Given an ADT of type T, performs a look up and returns the type of kind K.
|
|
202
194
|
*
|
|
@@ -225,21 +217,8 @@ export declare type GridColumn<R extends Kinded, S = {}> = {
|
|
|
225
217
|
} ? (data: D, row: GridRowKind<R, K>) => ReactNode | GridCellContent : (row: GridRowKind<R, K>) => ReactNode | GridCellContent);
|
|
226
218
|
} & {
|
|
227
219
|
/**
|
|
228
|
-
* The column's
|
|
229
|
-
*
|
|
230
|
-
* For `as=div` output:
|
|
231
|
-
*
|
|
232
|
-
* - Any CSS grid units are supported
|
|
233
|
-
* - Numbers are treated as `fr` units
|
|
234
|
-
* - The default value is `auto`, which in CSS grid will do content-aware/responsive layout.
|
|
235
|
-
*
|
|
236
|
-
* For `as=virtual` output:
|
|
237
|
-
*
|
|
238
|
-
* - Only px, percentage, or fr units are supported, due to a) react-virtuoso puts the sticky header
|
|
239
|
-
* rows in a separate `div` and so we end up with two `grid-template-columns`, so cannot rely on
|
|
240
|
-
* any content-aware sizing, and b) content-aware sizing in a scrolling/virtual table results in
|
|
241
|
-
* a ~janky experience as the columns will constantly resize as new/different content is put in/out
|
|
242
|
-
* 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.
|
|
243
222
|
* - Numbers are treated as `fr` units
|
|
244
223
|
* - The default value is `1fr`
|
|
245
224
|
*/
|
|
@@ -277,7 +256,7 @@ export declare type GridCellAlignment = "left" | "right" | "center";
|
|
|
277
256
|
* primitive value for filtering and sorting.
|
|
278
257
|
*/
|
|
279
258
|
export declare type GridCellContent = {
|
|
280
|
-
/** 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. */
|
|
281
260
|
content: ReactNode | (() => ReactNode);
|
|
282
261
|
alignment?: GridCellAlignment;
|
|
283
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,7 +104,7 @@ 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.
|
|
@@ -219,11 +217,11 @@ exports.GridTable = GridTable;
|
|
|
219
217
|
// Determine which HTML element to use to build the GridTable
|
|
220
218
|
const renders = {
|
|
221
219
|
table: renderTable,
|
|
222
|
-
div:
|
|
220
|
+
div: renderDiv,
|
|
223
221
|
virtual: renderVirtual,
|
|
224
222
|
};
|
|
225
|
-
/** Renders
|
|
226
|
-
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) {
|
|
227
225
|
var _a;
|
|
228
226
|
// We must determine if the header is using nested card styles to account for
|
|
229
227
|
// the opening and closing Chrome rows.
|
|
@@ -249,7 +247,8 @@ function renderCssGrid(style, id, columns, headerRows, filteredRows, firstRowMes
|
|
|
249
247
|
*/
|
|
250
248
|
const firstNonHeaderRowIndex = (!isNestedCardStyleHeader ? 1 : 3) + 1;
|
|
251
249
|
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
|
|
252
|
-
|
|
250
|
+
// Ensure all rows extend the same width
|
|
251
|
+
...Css_1.Css.mw("fit-content").$,
|
|
253
252
|
/*
|
|
254
253
|
Using n + (firstNonHeaderRowIndex + 1) here to target all rows that
|
|
255
254
|
are after the first non-header row. Since n starts at 0, we can use
|
|
@@ -265,7 +264,7 @@ function renderCssGrid(style, id, columns, headerRows, filteredRows, firstRowMes
|
|
|
265
264
|
: {}),
|
|
266
265
|
...style.rootCss,
|
|
267
266
|
...xss,
|
|
268
|
-
}, "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));
|
|
269
268
|
}
|
|
270
269
|
/** Renders as a table, primarily/solely for good print support. */
|
|
271
270
|
function renderTable(style, id, columns, headerRows, filteredRows, firstRowMessage, _stickyHeader, _firstLastColumnWidth, xss, _virtuosoRef) {
|
|
@@ -305,7 +304,9 @@ function renderVirtual(style, id, columns, headerRows, filteredRows, firstRowMes
|
|
|
305
304
|
const { paddingBottom, ...otherRootStyles } = (_a = style.rootCss) !== null && _a !== void 0 ? _a : {};
|
|
306
305
|
return { footerStyle: { paddingBottom }, listStyle: { ...style, rootCss: otherRootStyles } };
|
|
307
306
|
}, [style]);
|
|
308
|
-
return ((0, jsx_runtime_1.jsx)(react_virtuoso_1.Virtuoso, { overscan: 5, ref: virtuosoRef,
|
|
307
|
+
return ((0, jsx_runtime_1.jsx)(react_virtuoso_1.Virtuoso, { overscan: 5, ref: virtuosoRef,
|
|
308
|
+
// Add `minWidth: fit-content` to ensure a sticky header and the virtualized table body maintain same width
|
|
309
|
+
style: { minWidth: "fit-content" }, components: {
|
|
309
310
|
List: VirtualRoot(listStyle, columns, id, firstLastColumnWidth, xss),
|
|
310
311
|
Footer: () => (0, jsx_runtime_1.jsx)("div", { css: footerStyle }, void 0),
|
|
311
312
|
},
|
|
@@ -348,7 +349,7 @@ function renderVirtual(style, id, columns, headerRows, filteredRows, firstRowMes
|
|
|
348
349
|
* rows and the second represents the non-header rows (list rows).
|
|
349
350
|
*
|
|
350
351
|
* The main goal of this custom component is to:
|
|
351
|
-
* - Customize the list wrapper to our
|
|
352
|
+
* - Customize the list wrapper to our styles
|
|
352
353
|
*
|
|
353
354
|
* We wrap this in memoizeOne so that React.createElement sees a
|
|
354
355
|
* consistent/stable component identity, even though technically we have a
|
|
@@ -361,7 +362,7 @@ const VirtualRoot = (0, memoize_one_1.default)((gs, _columns, id, _firstLastColu
|
|
|
361
362
|
// table list generally has styles to scroll the page for windowing.
|
|
362
363
|
const isHeader = Object.keys(style || {}).length === 0;
|
|
363
364
|
// This re-renders each time we have new children in the viewport
|
|
364
|
-
return ((0, jsx_runtime_1.jsx)("div", Object.assign({ ref: ref, style: { ...style, ...
|
|
365
|
+
return ((0, jsx_runtime_1.jsx)("div", Object.assign({ ref: ref, style: { ...style, ...{ minWidth: "fit-content" } }, css: {
|
|
365
366
|
// Add an extra `> div` due to Item + itemContent both having divs
|
|
366
367
|
...Css_1.Css.addIn("& > div + div > div > *", gs.betweenRowsCss || {}).$,
|
|
367
368
|
// Table list styles only
|
|
@@ -376,17 +377,10 @@ const VirtualRoot = (0, memoize_one_1.default)((gs, _columns, id, _firstLastColu
|
|
|
376
377
|
});
|
|
377
378
|
});
|
|
378
379
|
/**
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
* Because of two things:
|
|
382
|
-
*
|
|
383
|
-
* a) react-virtuoso puts the header in a different div than the normal rows, and
|
|
384
|
-
*
|
|
385
|
-
* b) content-aware sizing just in general look janky/constantly resize while scrolling
|
|
386
|
-
*
|
|
387
|
-
* When we're as=virtual, we change our default + enforce only fixed-sized units (% and px)
|
|
380
|
+
* Calculates column widths using a flexible `calc()` definition that allows for consistent column alignment without the use of `<table />`, CSS Grid, etc layouts.
|
|
381
|
+
* Enforces only fixed-sized units (% and px)
|
|
388
382
|
*/
|
|
389
|
-
function
|
|
383
|
+
function calcColumnSizes(columns, firstLastColumnWidth) {
|
|
390
384
|
// For both default columns (1fr) as well as `w: 4fr` columns, we translate the width into an expression that looks like:
|
|
391
385
|
// calc((100% - allOtherPercent - allOtherPx) * ((myFr / totalFr))`
|
|
392
386
|
//
|
|
@@ -412,7 +406,7 @@ function calcVirtualGridColumns(columns, firstLastColumnWidth) {
|
|
|
412
406
|
return { ...acc, claimedPercentages: acc.claimedPercentages + Number(w.replace("%", "")) };
|
|
413
407
|
}
|
|
414
408
|
else {
|
|
415
|
-
throw new Error("
|
|
409
|
+
throw new Error("Beam Table column width definition only supports px, percentage, or fr units");
|
|
416
410
|
}
|
|
417
411
|
}, { claimedPercentages: 0, claimedPixels: firstLastColumnWidth ? firstLastColumnWidth * 2 : 0, totalFr: 0 });
|
|
418
412
|
// This is our "fake but for some reason it lines up better" fr calc
|
|
@@ -431,7 +425,7 @@ function calcVirtualGridColumns(columns, firstLastColumnWidth) {
|
|
|
431
425
|
return fr(Number(w.replace("fr", "")));
|
|
432
426
|
}
|
|
433
427
|
else {
|
|
434
|
-
throw new Error("
|
|
428
|
+
throw new Error("Beam Table column width definition only supports px, percentage, or fr units");
|
|
435
429
|
}
|
|
436
430
|
}
|
|
437
431
|
else {
|
|
@@ -440,25 +434,7 @@ function calcVirtualGridColumns(columns, firstLastColumnWidth) {
|
|
|
440
434
|
});
|
|
441
435
|
return maybeAddCardColumns(sizes, firstLastColumnWidth);
|
|
442
436
|
}
|
|
443
|
-
exports.
|
|
444
|
-
function calcDivGridColumns(columns, firstLastColumnWidth) {
|
|
445
|
-
const sizes = columns.map(({ w }) => {
|
|
446
|
-
if (typeof w === "undefined") {
|
|
447
|
-
// Hrm, I waffle between 'auto' or '1fr' being the better default here...
|
|
448
|
-
return "auto";
|
|
449
|
-
}
|
|
450
|
-
else if (typeof w === "string") {
|
|
451
|
-
// Use whatever the user passed in
|
|
452
|
-
return w;
|
|
453
|
-
}
|
|
454
|
-
else {
|
|
455
|
-
// Otherwise assume fr units
|
|
456
|
-
return `${w}fr`;
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
return maybeAddCardColumns(sizes, firstLastColumnWidth).join(" ");
|
|
460
|
-
}
|
|
461
|
-
exports.calcDivGridColumns = calcDivGridColumns;
|
|
437
|
+
exports.calcColumnSizes = calcColumnSizes;
|
|
462
438
|
// If we're doing nested cards, we add extra 1st/last cells...
|
|
463
439
|
function maybeAddCardColumns(sizes, firstLastColumnWidth) {
|
|
464
440
|
return !firstLastColumnWidth ? sizes : [`${firstLastColumnWidth}px`, ...sizes, `${firstLastColumnWidth}px`];
|
|
@@ -482,19 +458,15 @@ function GridRow(props) {
|
|
|
482
458
|
const rowStyle = rowStyles === null || rowStyles === void 0 ? void 0 : rowStyles[row.kind];
|
|
483
459
|
const rowStyleCellCss = maybeApplyFunction(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.cellCss);
|
|
484
460
|
const rowCss = {
|
|
485
|
-
// We add a display-contents so that we can have "row-level" div elements in our
|
|
486
|
-
// DOM structure. I.e. grid is normally root-element > cell-elements, but we want
|
|
487
|
-
// root-element > row-element > cell-elements, so that we can have a hook for
|
|
488
|
-
// hovers and styling. In theory this would change with subgrids.
|
|
489
|
-
// Only enable when using div as elements
|
|
490
461
|
// 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
|
|
491
|
-
...(as === "table" ? {} :
|
|
462
|
+
...(as === "table" ? {} : Css_1.Css.df.addIn("&>*", Css_1.Css.flexNone.$).$),
|
|
492
463
|
...(((rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowLink) || (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.onClick)) &&
|
|
493
464
|
style.rowHoverColor && {
|
|
494
465
|
// Even though backgroundColor is set on the cellCss (due to display: content), the hover target is the row.
|
|
495
466
|
"&:hover > *": Css_1.Css.cursorPointer.bgColor(maybeDarken(rowStyleCellCss === null || rowStyleCellCss === void 0 ? void 0 : rowStyleCellCss.backgroundColor, style.rowHoverColor)).$,
|
|
496
467
|
}),
|
|
497
468
|
...maybeApplyFunction(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowCss),
|
|
469
|
+
...(isHeader && stickyHeader ? Css_1.Css.sticky.top(stickyOffset).z1.$ : undefined),
|
|
498
470
|
};
|
|
499
471
|
const Row = as === "table" ? "tr" : "div";
|
|
500
472
|
const openCardStyles = typeof openCards === "string"
|
|
@@ -545,18 +517,11 @@ function GridRow(props) {
|
|
|
545
517
|
...getIndentationCss(style, rowStyle, columnIndex, maybeContent),
|
|
546
518
|
// Then apply any header-specific override
|
|
547
519
|
...(isHeader && style.headerCellCss),
|
|
548
|
-
// Non-virtualized tables use h100 so that all cells are the same height across the row.
|
|
549
|
-
// Virtualized table rows use `display: flex;`, so the flex children are set to `align-self: stretch` by default, which achieves the same goal.
|
|
550
|
-
// 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
|
|
551
|
-
...(isHeader && as !== "virtual" ? Css_1.Css.h100.$ : undefined),
|
|
552
|
-
...maybeStickyHeaderStyles,
|
|
553
520
|
// If we're within a card, use its background color
|
|
554
521
|
...(currentCard && Css_1.Css.bgColor(currentCard.bgColor).$),
|
|
555
|
-
// Add in colspan css if needed
|
|
556
|
-
...(currentColspan > 1 ? Css_1.Css.gc(`span ${currentColspan}`).$ : {}),
|
|
557
522
|
// And finally the specific cell's css (if any from GridCellContent)
|
|
558
523
|
...rowStyleCellCss,
|
|
559
|
-
//
|
|
524
|
+
// Define the width of the column on each cell. Supports col spans.
|
|
560
525
|
...(columnSizes && {
|
|
561
526
|
width: `calc(${columnSizes
|
|
562
527
|
.slice(maybeNestedCardColumnIndex, maybeNestedCardColumnIndex + currentColspan)
|
|
@@ -643,8 +608,8 @@ function applyRowFn(column, row) {
|
|
|
643
608
|
exports.applyRowFn = applyRowFn;
|
|
644
609
|
/** Renders our default cell element, i.e. if no row links and no custom renderCell are used. */
|
|
645
610
|
const defaultRenderFn = (as) => (key, css, content) => {
|
|
646
|
-
const
|
|
647
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
611
|
+
const Cell = as === "table" ? "td" : "div";
|
|
612
|
+
return ((0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...tableRowStyles(as) } }, { children: content }), key));
|
|
648
613
|
};
|
|
649
614
|
exports.GridCollapseContext = react_1.default.createContext({
|
|
650
615
|
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,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;
|