@homebound/beam 2.113.0 → 2.115.0
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/Table/GridTable.d.ts +15 -3
- package/dist/components/Table/GridTable.js +40 -28
- package/dist/components/Table/RowState.d.ts +2 -1
- package/dist/components/Table/RowState.js +2 -1
- package/dist/components/Table/nestedCards.d.ts +2 -1
- package/dist/components/Table/nestedCards.js +13 -10
- package/dist/components/Table/sortRows.js +2 -2
- package/dist/components/Table/styles.js +1 -1
- package/dist/hooks/useComputed.js +25 -8
- package/package.json +1 -1
|
@@ -54,6 +54,8 @@ export interface GridStyle {
|
|
|
54
54
|
levels?: Record<number, {
|
|
55
55
|
cellCss: Properties;
|
|
56
56
|
}>;
|
|
57
|
+
/** Allows for customization of the background color used to denote an "active" row */
|
|
58
|
+
activeBgColor?: Palette;
|
|
57
59
|
}
|
|
58
60
|
export declare type NestedCardStyleByKind = Record<string, NestedCardStyle>;
|
|
59
61
|
export interface NestedCardsStyle {
|
|
@@ -67,6 +69,8 @@ export interface NestedCardsStyle {
|
|
|
67
69
|
* Entries are optional, i.e. you can leave out kinds and they won't be wrapped/turned into cards.
|
|
68
70
|
*/
|
|
69
71
|
kinds: NestedCardStyleByKind;
|
|
72
|
+
/** Allows for customization of the border color used to denote an "active" row */
|
|
73
|
+
activeBColor?: Palette;
|
|
70
74
|
}
|
|
71
75
|
/**
|
|
72
76
|
* Styles for making cards nested within other cards.
|
|
@@ -172,6 +176,12 @@ export interface GridTableProps<R extends Kinded, S, X> {
|
|
|
172
176
|
api?: MutableRefObject<GridTableApi<R> | undefined>;
|
|
173
177
|
/** Experimental, expecting to be removed - Specify the element in which the table should resize its columns against. If not set, the table will resize columns based on its owns container's width */
|
|
174
178
|
resizeTarget?: MutableRefObject<HTMLElement | null>;
|
|
179
|
+
/**
|
|
180
|
+
* Defines which row in the table should be provided with an "active" styling.
|
|
181
|
+
* Expected format is `${row.kind}_${row.id}`. This helps avoid id conflicts between rows of different types/kinds that may have the same id.
|
|
182
|
+
* Example "data_123"
|
|
183
|
+
*/
|
|
184
|
+
activeRowId?: string;
|
|
175
185
|
}
|
|
176
186
|
/** NOTE: This API is experimental and primarily intended for story and testing purposes */
|
|
177
187
|
export declare type GridTableApi<R extends Kinded> = {
|
|
@@ -180,6 +190,8 @@ export declare type GridTableApi<R extends Kinded> = {
|
|
|
180
190
|
getSelectedRowIds(): string[];
|
|
181
191
|
/** Returns the currently-selected rows. */
|
|
182
192
|
getSelectedRows(): GridDataRow<R>[];
|
|
193
|
+
/** Sets the internal state of 'activeRowId' */
|
|
194
|
+
setActiveRowId: (id: string | undefined) => void;
|
|
183
195
|
};
|
|
184
196
|
/**
|
|
185
197
|
* Renders data in our table layout.
|
|
@@ -228,7 +240,7 @@ declare type GridRowKind<R extends Kinded, P extends R["kind"]> = DiscriminateUn
|
|
|
228
240
|
export declare type GridColumn<R extends Kinded, S = {}> = {
|
|
229
241
|
[K in R["kind"]]: string | GridCellContent | (DiscriminateUnion<R, "kind", K> extends {
|
|
230
242
|
data: infer D;
|
|
231
|
-
} ? (data: D, row: GridRowKind<R, K>) => ReactNode | GridCellContent : (row: GridRowKind<R, K>) => ReactNode | GridCellContent);
|
|
243
|
+
} ? (data: D, row: GridRowKind<R, K>, api: GridTableApi<R>) => ReactNode | GridCellContent : (row: GridRowKind<R, K>, api: GridTableApi<R>) => ReactNode | GridCellContent);
|
|
232
244
|
} & {
|
|
233
245
|
/**
|
|
234
246
|
* The column's width.
|
|
@@ -267,7 +279,7 @@ export interface RowStyle<R extends Kinded> {
|
|
|
267
279
|
/** Whether the row should be a link. */
|
|
268
280
|
rowLink?: (row: R) => string;
|
|
269
281
|
/** Fired when the row is clicked, similar to rowLink but for actions that aren't 'go to this link'. */
|
|
270
|
-
onClick?: (row: GridDataRow<R>) => void;
|
|
282
|
+
onClick?: (row: GridDataRow<R>, api: GridTableApi<R>) => void;
|
|
271
283
|
}
|
|
272
284
|
export declare type GridCellAlignment = "left" | "right" | "center";
|
|
273
285
|
/**
|
|
@@ -310,6 +322,6 @@ export declare type GridDataRow<R extends Kinded> = {
|
|
|
310
322
|
} & IfAny<R, {}, DiscriminateUnion<R, "kind", R["kind"]>>;
|
|
311
323
|
declare type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N;
|
|
312
324
|
/** Return the content for a given column def applied to a given row. */
|
|
313
|
-
export declare function applyRowFn<R extends Kinded>(column: GridColumn<R>, row: GridDataRow<R
|
|
325
|
+
export declare function applyRowFn<R extends Kinded>(column: GridColumn<R>, row: GridDataRow<R>, api: MutableRefObject<GridTableApi<R>>): ReactNode | GridCellContent;
|
|
314
326
|
export declare function matchesFilter(maybeContent: ReactNode | GridCellContent, filter: string): boolean;
|
|
315
327
|
export {};
|
|
@@ -85,30 +85,35 @@ exports.setGridTableDefaults = setGridTableDefaults;
|
|
|
85
85
|
*/
|
|
86
86
|
function GridTable(props) {
|
|
87
87
|
var _a, _b, _c, _d;
|
|
88
|
-
const { id = "gridTable", as = "div", columns, rows, style = defaults.style, rowStyles, stickyHeader = defaults.stickyHeader, stickyOffset = "0", xss, sorting, filter, filterMaxRows, fallbackMessage = "No rows found.", infoMessage, setRowCount, observeRows, persistCollapse, api, resizeTarget, } = props;
|
|
88
|
+
const { id = "gridTable", as = "div", columns, rows, style = defaults.style, rowStyles, stickyHeader = defaults.stickyHeader, stickyOffset = "0", xss, sorting, filter, filterMaxRows, fallbackMessage = "No rows found.", infoMessage, setRowCount, observeRows, persistCollapse, api: callerApi, resizeTarget, activeRowId, } = props;
|
|
89
89
|
// Create a ref that always contains the latest rows, for our effectively-singleton RowState to use
|
|
90
90
|
const rowsRef = (0, react_1.useRef)(rows);
|
|
91
91
|
rowsRef.current = rows;
|
|
92
|
-
const [rowState] = (0, react_1.useState)(() => new RowState_1.RowState(rowsRef, persistCollapse));
|
|
92
|
+
const [rowState] = (0, react_1.useState)(() => new RowState_1.RowState(rowsRef, persistCollapse, activeRowId));
|
|
93
93
|
// We only use this in as=virtual mode, but keep this here for rowLookup to use
|
|
94
94
|
const virtuosoRef = (0, react_1.useRef)(null);
|
|
95
95
|
const tableRef = (0, react_1.useRef)(null);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
96
|
+
const api = (0, react_1.useRef)({
|
|
97
|
+
scrollToIndex: (index) => virtuosoRef.current && virtuosoRef.current.scrollToIndex(index),
|
|
98
|
+
getSelectedRowIds: () => rowState.selectedIds,
|
|
99
|
+
getSelectedRows() {
|
|
100
|
+
const ids = rowState.selectedIds;
|
|
101
|
+
const selected = [];
|
|
102
|
+
(0, visitor_1.visit)(rows, (row) => {
|
|
103
|
+
if (ids.includes(row.id)) {
|
|
104
|
+
selected.push(row);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return selected;
|
|
108
|
+
},
|
|
109
|
+
setActiveRowId: (id) => (rowState.activeRowId = id),
|
|
110
|
+
});
|
|
111
|
+
if (callerApi) {
|
|
112
|
+
callerApi.current = api.current;
|
|
111
113
|
}
|
|
114
|
+
(0, react_1.useEffect)(() => {
|
|
115
|
+
rowState.activeRowId = activeRowId;
|
|
116
|
+
}, [activeRowId]);
|
|
112
117
|
// We track render count at the table level, which seems odd (we should be able to track this
|
|
113
118
|
// internally within each GridRow using a useRef), but we have suspicions that react-virtuoso
|
|
114
119
|
// (or us) is resetting component state more than necessary, so we track render counts from
|
|
@@ -146,6 +151,7 @@ function GridTable(props) {
|
|
|
146
151
|
columnSizes,
|
|
147
152
|
level,
|
|
148
153
|
getCount,
|
|
154
|
+
api,
|
|
149
155
|
...sortProps,
|
|
150
156
|
}), `${row.kind}-${row.id}`));
|
|
151
157
|
}
|
|
@@ -159,7 +165,7 @@ function GridTable(props) {
|
|
|
159
165
|
var _a;
|
|
160
166
|
const matches = filters.length === 0 ||
|
|
161
167
|
row.pin ||
|
|
162
|
-
filters.every((filter) => columns.map((c) => applyRowFn(c, row)).some((maybeContent) => matchesFilter(maybeContent, filter)));
|
|
168
|
+
filters.every((filter) => columns.map((c) => applyRowFn(c, row, api)).some((maybeContent) => matchesFilter(maybeContent, filter)));
|
|
163
169
|
let isCard = false;
|
|
164
170
|
// Even if we don't pass the filter, one of our children might, so we continue on after this check
|
|
165
171
|
if (matches) {
|
|
@@ -452,7 +458,9 @@ function getFirstOrLastCellCss(style, columnIndex, columns) {
|
|
|
452
458
|
// We extract GridRow to its own mini-component primarily so we can React.memo'ize it.
|
|
453
459
|
function GridRow(props) {
|
|
454
460
|
var _a;
|
|
455
|
-
const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset, sorting, sortState, setSortKey, openCards, columnSizes, level, getCount, ...others } = props;
|
|
461
|
+
const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset, sorting, sortState, setSortKey, openCards, columnSizes, level, getCount, api, ...others } = props;
|
|
462
|
+
const { rowState } = (0, react_1.useContext)(RowState_1.RowStateContext);
|
|
463
|
+
const isActive = (0, hooks_1.useComputed)(() => rowState.activeRowId === `${row.kind}_${row.id}`, [row, rowState]);
|
|
456
464
|
// We treat the "header" kind as special for "good defaults" styling
|
|
457
465
|
const isHeader = row.kind === "header";
|
|
458
466
|
const rowStyle = rowStyles === null || rowStyles === void 0 ? void 0 : rowStyles[row.kind];
|
|
@@ -474,11 +482,11 @@ function GridRow(props) {
|
|
|
474
482
|
...maybeApplyFunction(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowCss),
|
|
475
483
|
// Maybe add the sticky header styles
|
|
476
484
|
...(isHeader && stickyHeader ? Css_1.Css.sticky.top(stickyOffset).z2.$ : undefined),
|
|
477
|
-
...(0, nestedCards_1.getNestedCardStyles)(row, openCardStyles, style),
|
|
485
|
+
...(0, nestedCards_1.getNestedCardStyles)(row, openCardStyles, style, isActive),
|
|
478
486
|
};
|
|
479
487
|
let currentColspan = 1;
|
|
480
488
|
const rowNode = ((0, jsx_runtime_1.jsx)(Row, Object.assign({ css: rowCss }, others, { "data-gridrow": true }, getCount(row.id), { children: columns.map((column, columnIndex) => {
|
|
481
|
-
var _a, _b, _c, _d;
|
|
489
|
+
var _a, _b, _c, _d, _e;
|
|
482
490
|
if (column.mw) {
|
|
483
491
|
// Validate the column's minWidth definition if set.
|
|
484
492
|
if (!column.mw.endsWith("px") && !column.mw.endsWith("%")) {
|
|
@@ -490,7 +498,7 @@ function GridRow(props) {
|
|
|
490
498
|
currentColspan -= 1;
|
|
491
499
|
return null;
|
|
492
500
|
}
|
|
493
|
-
const maybeContent = applyRowFn(column, row);
|
|
501
|
+
const maybeContent = applyRowFn(column, row, api);
|
|
494
502
|
currentColspan = isGridCellContent(maybeContent) ? (_a = maybeContent.colspan) !== null && _a !== void 0 ? _a : 1 : 1;
|
|
495
503
|
const canSortColumn = ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client" && column.clientSideSort !== false) ||
|
|
496
504
|
((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "server" && !!column.serverSideSortKey);
|
|
@@ -547,6 +555,10 @@ function GridRow(props) {
|
|
|
547
555
|
...(!isHeader && !!style.levels && ((_d = style.levels[level]) === null || _d === void 0 ? void 0 : _d.cellCss)),
|
|
548
556
|
// The specific cell's css (if any from GridCellContent)
|
|
549
557
|
...rowStyleCellCss,
|
|
558
|
+
// Apply active row styling for non-nested card styles.
|
|
559
|
+
...(style.nestedCards === undefined && isActive
|
|
560
|
+
? Css_1.Css.bgColor((_e = style.activeBgColor) !== null && _e !== void 0 ? _e : Css_1.Palette.LightBlue50).$
|
|
561
|
+
: {}),
|
|
550
562
|
// Add any cell specific style overrides
|
|
551
563
|
...(isGridCellContent(maybeContent) && maybeContent.typeScale ? Css_1.Css[maybeContent.typeScale].$ : {}),
|
|
552
564
|
// Define the width of the column on each cell. Supports col spans.
|
|
@@ -562,7 +574,7 @@ function GridRow(props) {
|
|
|
562
574
|
: isHeader
|
|
563
575
|
? headerRenderFn(columns, column, sortState, setSortKey, as)
|
|
564
576
|
: (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.onClick)
|
|
565
|
-
? rowClickRenderFn(as)
|
|
577
|
+
? rowClickRenderFn(as, api)
|
|
566
578
|
: defaultRenderFn(as);
|
|
567
579
|
return renderFn(columnIndex, cellCss, content, row, rowStyle);
|
|
568
580
|
}) }), void 0));
|
|
@@ -619,16 +631,16 @@ function isContentEmpty(content) {
|
|
|
619
631
|
return emptyValues.includes(content);
|
|
620
632
|
}
|
|
621
633
|
/** Return the content for a given column def applied to a given row. */
|
|
622
|
-
function applyRowFn(column, row) {
|
|
634
|
+
function applyRowFn(column, row, api) {
|
|
623
635
|
// Usually this is a function to apply against the row, but sometimes it's a hard-coded value, i.e. for headers
|
|
624
636
|
const maybeContent = column[row.kind];
|
|
625
637
|
if (typeof maybeContent === "function") {
|
|
626
638
|
if ("data" in row && "id" in row) {
|
|
627
639
|
// Auto-destructure data
|
|
628
|
-
return maybeContent(row["data"], row["id"]);
|
|
640
|
+
return maybeContent(row["data"], row["id"], api.current);
|
|
629
641
|
}
|
|
630
642
|
else {
|
|
631
|
-
return maybeContent(row);
|
|
643
|
+
return maybeContent(row, api.current);
|
|
632
644
|
}
|
|
633
645
|
}
|
|
634
646
|
else {
|
|
@@ -662,9 +674,9 @@ const rowLinkRenderFn = (as) => (key, css, content, row, rowStyle) => {
|
|
|
662
674
|
return ((0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({ to: to, css: { ...Css_1.Css.noUnderline.color("unset").$, ...css }, className: CssReset_1.navLink }, { children: content }), key));
|
|
663
675
|
};
|
|
664
676
|
/** Renders a cell that will fire the RowStyle.onClick. */
|
|
665
|
-
const rowClickRenderFn = (as) => (key, css, content, row, rowStyle) => {
|
|
677
|
+
const rowClickRenderFn = (as, api) => (key, css, content, row, rowStyle) => {
|
|
666
678
|
const Row = as === "table" ? "tr" : "div";
|
|
667
|
-
return ((0, jsx_runtime_1.jsx)(Row, Object.assign({}, { key }, { css: { ...css, ...tableRowStyles(as) }, onClick: () => rowStyle.onClick(row) }, { children: content }), void 0));
|
|
679
|
+
return ((0, jsx_runtime_1.jsx)(Row, Object.assign({}, { key }, { css: { ...css, ...tableRowStyles(as) }, onClick: () => rowStyle.onClick(row, api.current) }, { children: content }), void 0));
|
|
668
680
|
};
|
|
669
681
|
const alignmentToJustify = {
|
|
670
682
|
left: "flex-start",
|
|
@@ -21,10 +21,11 @@ export declare class RowState {
|
|
|
21
21
|
private persistCollapse;
|
|
22
22
|
private readonly collapsedRows;
|
|
23
23
|
private readonly selectedRows;
|
|
24
|
+
activeRowId: string | undefined;
|
|
24
25
|
/**
|
|
25
26
|
* Creates the `RowState` for a given `GridTable`.
|
|
26
27
|
*/
|
|
27
|
-
constructor(rows: MutableRefObject<GridDataRow<any>[]>, persistCollapse: string | undefined);
|
|
28
|
+
constructor(rows: MutableRefObject<GridDataRow<any>[]>, persistCollapse: string | undefined, activeRowId: string | undefined);
|
|
28
29
|
get selectedIds(): string[];
|
|
29
30
|
getSelected(id: string): SelectedState;
|
|
30
31
|
selectRow(id: string, selected: boolean): void;
|
|
@@ -26,11 +26,12 @@ class RowState {
|
|
|
26
26
|
/**
|
|
27
27
|
* Creates the `RowState` for a given `GridTable`.
|
|
28
28
|
*/
|
|
29
|
-
constructor(rows, persistCollapse) {
|
|
29
|
+
constructor(rows, persistCollapse, activeRowId) {
|
|
30
30
|
this.rows = rows;
|
|
31
31
|
this.persistCollapse = persistCollapse;
|
|
32
32
|
this.selectedRows = new mobx_1.ObservableMap();
|
|
33
33
|
this.collapsedRows = new mobx_1.ObservableSet(persistCollapse ? readLocalCollapseState(persistCollapse) : []);
|
|
34
|
+
this.activeRowId = activeRowId;
|
|
34
35
|
// Make ourselves an observable so that mobx will do caching of .collapseIds so
|
|
35
36
|
// that it'll be a stable identity for GridTable to useMemo against.
|
|
36
37
|
(0, mobx_1.makeAutoObservable)(this, { rows: false }); // as any b/c rows is private, so the mapped type doesn't see it
|
|
@@ -77,7 +77,8 @@ export declare function makeOpenOrCloseCard(openCards: string[], cardStyles: Nes
|
|
|
77
77
|
* <div parent> <div child> <div grandchild /> </div> </div>
|
|
78
78
|
*/
|
|
79
79
|
export declare function wrapCard(openCards: NestedCardStyle[], row: JSX.Element): JSX.Element;
|
|
80
|
-
export declare function getNestedCardStyles(row: GridDataRow<any>, openCardStyles: NestedCardStyle[] | undefined, style: GridStyle): {
|
|
80
|
+
export declare function getNestedCardStyles(row: GridDataRow<any>, openCardStyles: NestedCardStyle[] | undefined, style: GridStyle, isActive: boolean): {
|
|
81
|
+
boxShadow?: import("csstype").Property.BoxShadow | undefined;
|
|
81
82
|
paddingTop?: import("csstype").Property.PaddingTop<0 | (string & {})> | undefined;
|
|
82
83
|
paddingBottom?: import("csstype").Property.PaddingBottom<0 | (string & {})> | undefined;
|
|
83
84
|
borderRadius?: import("csstype").Property.BorderRadius<0 | (string & {})> | undefined;
|
|
@@ -143,15 +143,13 @@ exports.makeOpenOrCloseCard = makeOpenOrCloseCard;
|
|
|
143
143
|
function wrapCard(openCards, row) {
|
|
144
144
|
let div = row;
|
|
145
145
|
[...openCards].reverse().forEach((card) => {
|
|
146
|
-
div = ((0, jsx_runtime_1.jsx)("div", Object.assign({ css: {
|
|
147
|
-
...Css_1.Css.h100.pxPx(card.pxPx).bgColor(card.bgColor).if(!!card.bColor).bc(card.bColor).bl.br.$,
|
|
148
|
-
} }, { children: div }), void 0));
|
|
146
|
+
div = ((0, jsx_runtime_1.jsx)("div", Object.assign({ css: Css_1.Css.h100.pxPx(card.pxPx).bgColor(card.bgColor).if(!!card.bColor).bc(card.bColor).bl.br.$ }, { children: div }), void 0));
|
|
149
147
|
});
|
|
150
148
|
return div;
|
|
151
149
|
}
|
|
152
150
|
exports.wrapCard = wrapCard;
|
|
153
|
-
function getNestedCardStyles(row, openCardStyles, style) {
|
|
154
|
-
var _a, _b, _c;
|
|
151
|
+
function getNestedCardStyles(row, openCardStyles, style, isActive) {
|
|
152
|
+
var _a, _b, _c, _d, _e;
|
|
155
153
|
const leafCardStyles = isLeafRow(row) ? (_a = style.nestedCards) === null || _a === void 0 ? void 0 : _a.kinds[row.kind] : undefined;
|
|
156
154
|
// Calculate the horizontal space already allocated by the open cards (paddings and borders)
|
|
157
155
|
const openCardWidth = openCardStyles ? openCardStyles.reduce((acc, o) => acc + o.pxPx + (o.bColor ? 1 : 0), 0) : 0;
|
|
@@ -167,11 +165,16 @@ function getNestedCardStyles(row, openCardStyles, style) {
|
|
|
167
165
|
// When it is not a leaf then it has chrome rows that create the top and bottom "padding" based on border-radius size. (brPx = "chrome" row height)
|
|
168
166
|
// When it is a leaf, then we need to apply the brPx to the row to ensure consistent spacing between leaf & non-leaf renders
|
|
169
167
|
// Additionally, if the leaf card has a border, then subtract the 1px border width from the padding to keep consistent with the "chrome" row
|
|
170
|
-
|
|
171
|
-
.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
168
|
+
{
|
|
169
|
+
...Css_1.Css.pyPx(leafCardStyles.brPx - (leafCardStyles.bColor ? 1 : 0))
|
|
170
|
+
.borderRadius(`${leafCardStyles.brPx}px`)
|
|
171
|
+
.bgColor(leafCardStyles.bgColor)
|
|
172
|
+
.if(!!leafCardStyles.bColor)
|
|
173
|
+
.bc(leafCardStyles.bColor).ba.$,
|
|
174
|
+
...(isActive
|
|
175
|
+
? Css_1.Css.boxShadow(`0px 0px 0px 2px rgba(254,254,254,1), 0px 0px 0px 4px ${(_e = (_d = style.nestedCards) === null || _d === void 0 ? void 0 : _d.activeBColor) !== null && _e !== void 0 ? _e : Css_1.Palette.LightBlue700}`).$
|
|
176
|
+
: {}),
|
|
177
|
+
}
|
|
175
178
|
: undefined),
|
|
176
179
|
};
|
|
177
180
|
}
|
|
@@ -21,8 +21,8 @@ function sortBatch(columns, batch, sortState) {
|
|
|
21
21
|
const invert = direction === "DESC";
|
|
22
22
|
// Make a shallow copy for sorting to avoid mutating the original list
|
|
23
23
|
return [...batch].sort((a, b) => {
|
|
24
|
-
const v1 = sortValue((0, GridTable_1.applyRowFn)(column, a));
|
|
25
|
-
const v2 = sortValue((0, GridTable_1.applyRowFn)(column, b));
|
|
24
|
+
const v1 = sortValue((0, GridTable_1.applyRowFn)(column, a, {}));
|
|
25
|
+
const v2 = sortValue((0, GridTable_1.applyRowFn)(column, b, {}));
|
|
26
26
|
const v1e = v1 === null || v1 === undefined;
|
|
27
27
|
const v2e = v2 === null || v2 === undefined;
|
|
28
28
|
if (a.pin || b.pin) {
|
|
@@ -13,7 +13,7 @@ exports.defaultStyle = {
|
|
|
13
13
|
indentOneCss: Css_1.Css.pl4.$,
|
|
14
14
|
indentTwoCss: Css_1.Css.pl7.$,
|
|
15
15
|
headerCellCss: Css_1.Css.nowrap.py1.bgGray100.aife.$,
|
|
16
|
-
firstRowMessageCss: Css_1.Css.
|
|
16
|
+
firstRowMessageCss: Css_1.Css.tc.p3.$,
|
|
17
17
|
};
|
|
18
18
|
/** Tightens up the padding of rows, great for rows that have form elements in them. */
|
|
19
19
|
exports.condensedStyle = {
|
|
@@ -7,28 +7,45 @@ const react_1 = require("react");
|
|
|
7
7
|
function useComputed(fn, deps) {
|
|
8
8
|
// We always return the useRef value, and use this just to trigger re-renders
|
|
9
9
|
const [, setValue] = (0, react_1.useState)(0);
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const ref = (0, react_1.useRef)({
|
|
11
|
+
runner: undefined,
|
|
12
|
+
value: undefined,
|
|
13
|
+
hasRan: false,
|
|
14
|
+
});
|
|
15
|
+
// We use a `useMemo` b/c we want this to synchronously calc, so that even
|
|
16
|
+
// the very 1st render can use the result of our computed, i.e. instead of
|
|
17
|
+
// with `useEffect`, which would only get calc'd after the 1st render has
|
|
18
|
+
// already been done.
|
|
12
19
|
(0, react_1.useMemo)(() => {
|
|
13
20
|
let tick = 0;
|
|
21
|
+
const { current } = ref;
|
|
14
22
|
// If deps has changed, unhook the previous observer
|
|
15
|
-
if (
|
|
16
|
-
|
|
23
|
+
if (current.runner) {
|
|
24
|
+
current.runner();
|
|
17
25
|
}
|
|
18
|
-
|
|
26
|
+
current.runner = (0, mobx_1.autorun)(() => {
|
|
19
27
|
// Always eval fn() (even on 1st render) to register our observable.
|
|
20
|
-
|
|
28
|
+
const newValue = fn();
|
|
29
|
+
const oldValue = current.value;
|
|
30
|
+
current.value = newValue;
|
|
31
|
+
current.hasRan = true;
|
|
21
32
|
// Only trigger a re-render if this is not the 1st autorun. Note
|
|
22
33
|
// that if deps has changed, we're inherently in a re-render so also
|
|
23
34
|
// don't need to trigger an additional re-render.
|
|
24
|
-
if (tick > 0) {
|
|
35
|
+
if (tick > 0 && newValue !== oldValue) {
|
|
25
36
|
setValue(tick);
|
|
26
37
|
}
|
|
27
38
|
tick++;
|
|
28
39
|
});
|
|
29
40
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
30
41
|
}, deps);
|
|
42
|
+
// Occasionally autorun will not have run yet, in which case we have to just
|
|
43
|
+
// accept running the eval fn twice (here to get the value for the 1st render,
|
|
44
|
+
// and again for mobx to watch what observables we touch).
|
|
45
|
+
if (!ref.current.hasRan) {
|
|
46
|
+
ref.current.value = fn();
|
|
47
|
+
}
|
|
31
48
|
// We can use `!` here b/c we know that `autorun` set current
|
|
32
|
-
return
|
|
49
|
+
return ref.current.value;
|
|
33
50
|
}
|
|
34
51
|
exports.useComputed = useComputed;
|