@homebound/beam 2.187.0 → 2.187.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/SuperDrawer/ConfirmCloseModal.js +1 -1
- package/dist/components/SuperDrawer/SuperDrawer.js +4 -10
- package/dist/components/Table/GridTable.d.ts +11 -218
- package/dist/components/Table/GridTable.js +15 -426
- package/dist/components/Table/GridTableApi.d.ts +3 -2
- package/dist/components/Table/GridTableApi.js +2 -2
- package/dist/components/Table/TableStyles.d.ts +86 -0
- package/dist/components/Table/{styles.js → TableStyles.js} +55 -34
- package/dist/components/Table/{CollapseToggle.d.ts → components/CollapseToggle.d.ts} +1 -1
- package/dist/components/Table/{CollapseToggle.js → components/CollapseToggle.js} +4 -4
- package/dist/components/Table/{EditColumnsButton.d.ts → components/EditColumnsButton.d.ts} +2 -2
- package/dist/components/Table/{EditColumnsButton.js → components/EditColumnsButton.js} +5 -5
- package/dist/components/Table/components/Row.d.ts +71 -0
- package/dist/components/Table/components/Row.js +177 -0
- package/dist/components/Table/{SelectToggle.d.ts → components/SelectToggle.d.ts} +0 -0
- package/dist/components/Table/{SelectToggle.js → components/SelectToggle.js} +5 -5
- package/dist/components/Table/{SortHeader.d.ts → components/SortHeader.d.ts} +1 -1
- package/dist/components/Table/{SortHeader.js → components/SortHeader.js} +5 -5
- package/dist/components/Table/components/cell.d.ts +41 -0
- package/dist/components/Table/components/cell.js +46 -0
- package/dist/components/Table/{useColumns.d.ts → hooks/useColumns.d.ts} +1 -1
- package/dist/components/Table/{useColumns.js → hooks/useColumns.js} +1 -1
- package/dist/components/Table/{columnSizes.d.ts → hooks/useSetupColumnSizes.d.ts} +2 -1
- package/dist/components/Table/{columnSizes.js → hooks/useSetupColumnSizes.js} +3 -3
- package/dist/components/Table/{useSortState.d.ts → hooks/useSortState.d.ts} +2 -1
- package/dist/components/Table/{useSortState.js → hooks/useSortState.js} +6 -6
- package/dist/components/Table/index.d.ts +30 -14
- package/dist/components/Table/index.js +38 -24
- package/dist/components/Table/types.d.ts +83 -0
- package/dist/components/Table/types.js +16 -0
- package/dist/components/Table/{GridRowLookup.d.ts → utils/GridRowLookup.d.ts} +2 -1
- package/dist/components/Table/{GridRowLookup.js → utils/GridRowLookup.js} +2 -2
- package/dist/components/Table/{GridSortContext.d.ts → utils/GridSortContext.d.ts} +0 -0
- package/dist/components/Table/{GridSortContext.js → utils/GridSortContext.js} +0 -0
- package/dist/components/Table/{RowState.d.ts → utils/RowState.d.ts} +1 -1
- package/dist/components/Table/{RowState.js → utils/RowState.js} +0 -0
- package/dist/components/Table/{columns.d.ts → utils/columns.d.ts} +6 -1
- package/dist/components/Table/utils/columns.js +149 -0
- package/dist/components/Table/{simpleHelpers.d.ts → utils/simpleHelpers.d.ts} +1 -1
- package/dist/components/Table/{simpleHelpers.js → utils/simpleHelpers.js} +0 -0
- package/dist/components/Table/{sortRows.d.ts → utils/sortRows.d.ts} +4 -2
- package/dist/components/Table/{sortRows.js → utils/sortRows.js} +3 -3
- package/dist/components/Table/utils/utils.d.ts +23 -0
- package/dist/components/Table/utils/utils.js +148 -0
- package/dist/components/Table/{visitor.d.ts → utils/visitor.d.ts} +1 -1
- package/dist/components/Table/{visitor.js → utils/visitor.js} +0 -0
- package/package.json +1 -1
- package/dist/components/Table/columns.js +0 -84
- package/dist/components/Table/styles.d.ts +0 -15
|
@@ -22,34 +22,24 @@ 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.
|
|
25
|
+
exports.filterRows = exports.GridTable = exports.setGridTableDefaults = exports.setDefaultStyle = exports.setRunningInJest = void 0;
|
|
26
26
|
const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
|
|
27
27
|
const memoize_one_1 = __importDefault(require("memoize-one"));
|
|
28
|
-
const mobx_react_1 = require("mobx-react");
|
|
29
28
|
const react_1 = __importStar(require("react"));
|
|
30
|
-
const react_router_dom_1 = require("react-router-dom");
|
|
31
29
|
const react_virtuoso_1 = require("react-virtuoso");
|
|
32
|
-
const CssReset_1 = require("../CssReset");
|
|
33
30
|
const PresentationContext_1 = require("../PresentationContext");
|
|
34
|
-
const columnSizes_1 = require("./columnSizes");
|
|
35
|
-
const GridRowLookup_1 = require("./GridRowLookup");
|
|
36
|
-
const GridSortContext_1 = require("./GridSortContext");
|
|
37
31
|
const GridTableApi_1 = require("./GridTableApi");
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
const
|
|
32
|
+
const useSetupColumnSizes_1 = require("./hooks/useSetupColumnSizes");
|
|
33
|
+
const useSortState_1 = require("./hooks/useSortState");
|
|
34
|
+
const TableStyles_1 = require("./TableStyles");
|
|
35
|
+
const GridRowLookup_1 = require("./utils/GridRowLookup");
|
|
36
|
+
const RowState_1 = require("./utils/RowState");
|
|
37
|
+
const sortRows_1 = require("./utils/sortRows");
|
|
38
|
+
const utils_1 = require("./utils/utils");
|
|
43
39
|
const Css_1 = require("../../Css");
|
|
44
40
|
const hooks_1 = require("../../hooks");
|
|
45
41
|
const useRenderCount_1 = require("../../hooks/useRenderCount");
|
|
46
|
-
const
|
|
47
|
-
const getInteractiveElement_1 = require("../../utils/getInteractiveElement");
|
|
48
|
-
const shallowEqual_1 = require("../../utils/shallowEqual");
|
|
49
|
-
const _1 = require(".");
|
|
50
|
-
exports.ASC = "ASC";
|
|
51
|
-
exports.DESC = "DESC";
|
|
52
|
-
exports.emptyCell = { content: () => (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}, void 0), value: "" };
|
|
42
|
+
const Row_1 = require("./components/Row");
|
|
53
43
|
let runningInJest = false;
|
|
54
44
|
/** Tells GridTable we're running in Jest, which forces as=virtual to be as=div, to work in jsdom. */
|
|
55
45
|
function setRunningInJest() {
|
|
@@ -57,7 +47,7 @@ function setRunningInJest() {
|
|
|
57
47
|
}
|
|
58
48
|
exports.setRunningInJest = setRunningInJest;
|
|
59
49
|
let defaults = {
|
|
60
|
-
style:
|
|
50
|
+
style: TableStyles_1.defaultStyle,
|
|
61
51
|
stickyHeader: false,
|
|
62
52
|
};
|
|
63
53
|
/** Configures the default/app-wide GridStyle. */
|
|
@@ -101,7 +91,7 @@ function GridTable(props) {
|
|
|
101
91
|
api.setActiveCellId(activeCellId);
|
|
102
92
|
return api;
|
|
103
93
|
}, [props.api]);
|
|
104
|
-
const style = resolveStyles(maybeStyle);
|
|
94
|
+
const style = (0, TableStyles_1.resolveStyles)(maybeStyle);
|
|
105
95
|
const { rowState } = api;
|
|
106
96
|
rowState.setRows(rows);
|
|
107
97
|
(0, react_1.useEffect)(() => {
|
|
@@ -115,7 +105,7 @@ function GridTable(props) {
|
|
|
115
105
|
// (or us) is resetting component state more than necessary, so we track render counts from
|
|
116
106
|
// here instead.
|
|
117
107
|
const { getCount } = (0, useRenderCount_1.useRenderCount)();
|
|
118
|
-
const columnSizes = (0,
|
|
108
|
+
const columnSizes = (0, useSetupColumnSizes_1.useSetupColumnSizes)(style, columns, resizeTarget !== null && resizeTarget !== void 0 ? resizeTarget : resizeRef);
|
|
119
109
|
// Make a single copy of our current collapsed state, so we'll have a single observer.
|
|
120
110
|
const collapsedIds = (0, hooks_1.useComputed)(() => rowState.collapsedIds, [rowState]);
|
|
121
111
|
const [sortState, setSortKey, sortOn, caseSensitive] = (0, useSortState_1.useSortState)(columns, props.sorting);
|
|
@@ -133,7 +123,7 @@ function GridTable(props) {
|
|
|
133
123
|
// We only pass sortState to header rows, b/c non-headers rows shouldn't have to re-render on sorting
|
|
134
124
|
// changes, and so by not passing the sortProps, it means the data rows' React.memo will still cache them.
|
|
135
125
|
const sortProps = row.kind === "header" ? { sortOn, sortState, setSortKey } : { sortOn };
|
|
136
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
126
|
+
return ((0, jsx_runtime_1.jsx)(Row_1.Row, Object.assign({}, {
|
|
137
127
|
as,
|
|
138
128
|
columns,
|
|
139
129
|
row,
|
|
@@ -376,408 +366,6 @@ const VirtualRoot = (0, memoize_one_1.default)((gs, _columns, id, xss) => {
|
|
|
376
366
|
}, "data-testid": id }, { children: children }), void 0));
|
|
377
367
|
});
|
|
378
368
|
});
|
|
379
|
-
/**
|
|
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)
|
|
382
|
-
*/
|
|
383
|
-
function calcColumnSizes(columns, tableWidth, tableMinWidthPx = 0) {
|
|
384
|
-
// For both default columns (1fr) as well as `w: 4fr` columns, we translate the width into an expression that looks like:
|
|
385
|
-
// calc((100% - allOtherPercent - allOtherPx) * ((myFr / totalFr))`
|
|
386
|
-
//
|
|
387
|
-
// Which looks _a lot_ like how `fr` units just work out-of-the-box.
|
|
388
|
-
//
|
|
389
|
-
// Unfortunately, something about having our header & body rows in separate divs (which is controlled
|
|
390
|
-
// by react-virtuoso), even if they have the same width, for some reason `fr` units between the two
|
|
391
|
-
// will resolve every slightly differently, where as this approach they will match exactly.
|
|
392
|
-
const { claimedPercentages, claimedPixels, totalFr } = columns.reduce((acc, { w }) => {
|
|
393
|
-
if (typeof w === "undefined") {
|
|
394
|
-
return { ...acc, totalFr: acc.totalFr + 1 };
|
|
395
|
-
}
|
|
396
|
-
else if (typeof w === "number") {
|
|
397
|
-
return { ...acc, totalFr: acc.totalFr + w };
|
|
398
|
-
}
|
|
399
|
-
else if (w.endsWith("fr")) {
|
|
400
|
-
return { ...acc, totalFr: acc.totalFr + Number(w.replace("fr", "")) };
|
|
401
|
-
}
|
|
402
|
-
else if (w.endsWith("px")) {
|
|
403
|
-
return { ...acc, claimedPixels: acc.claimedPixels + Number(w.replace("px", "")) };
|
|
404
|
-
}
|
|
405
|
-
else if (w.endsWith("%")) {
|
|
406
|
-
return { ...acc, claimedPercentages: acc.claimedPercentages + Number(w.replace("%", "")) };
|
|
407
|
-
}
|
|
408
|
-
else {
|
|
409
|
-
throw new Error("Beam Table column width definition only supports px, percentage, or fr units");
|
|
410
|
-
}
|
|
411
|
-
}, { claimedPercentages: 0, claimedPixels: 0, totalFr: 0 });
|
|
412
|
-
// This is our "fake but for some reason it lines up better" fr calc
|
|
413
|
-
function fr(myFr) {
|
|
414
|
-
// If the tableWidth, then return a pixel value
|
|
415
|
-
if (tableWidth) {
|
|
416
|
-
const widthBasis = Math.max(tableWidth, tableMinWidthPx);
|
|
417
|
-
return `(${(widthBasis - (claimedPercentages / 100) * widthBasis - claimedPixels) * (myFr / totalFr)}px)`;
|
|
418
|
-
}
|
|
419
|
-
// Otherwise return the `calc()` value
|
|
420
|
-
return `((100% - ${claimedPercentages}% - ${claimedPixels}px) * (${myFr} / ${totalFr}))`;
|
|
421
|
-
}
|
|
422
|
-
let sizes = columns.map(({ w }) => {
|
|
423
|
-
if (typeof w === "undefined") {
|
|
424
|
-
return fr(1);
|
|
425
|
-
}
|
|
426
|
-
else if (typeof w === "string") {
|
|
427
|
-
if (w.endsWith("%") || w.endsWith("px")) {
|
|
428
|
-
return w;
|
|
429
|
-
}
|
|
430
|
-
else if (w.endsWith("fr")) {
|
|
431
|
-
return fr(Number(w.replace("fr", "")));
|
|
432
|
-
}
|
|
433
|
-
else {
|
|
434
|
-
throw new Error("Beam Table column width definition only supports px, percentage, or fr units");
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
else {
|
|
438
|
-
return fr(w);
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
return sizes;
|
|
442
|
-
}
|
|
443
|
-
exports.calcColumnSizes = calcColumnSizes;
|
|
444
|
-
exports.nonKindGridColumnKeys = [
|
|
445
|
-
"w",
|
|
446
|
-
"mw",
|
|
447
|
-
"align",
|
|
448
|
-
"serverSideSortKey",
|
|
449
|
-
"clientSideSort",
|
|
450
|
-
"sticky",
|
|
451
|
-
"wrapAction",
|
|
452
|
-
"isAction",
|
|
453
|
-
];
|
|
454
|
-
function getIndentationCss(style, rowStyle, columnIndex, maybeContent) {
|
|
455
|
-
// Look for cell-specific indent or row-specific indent (row-specific is only one the first column)
|
|
456
|
-
const indent = (isGridCellContent(maybeContent) && maybeContent.indent) || (columnIndex === 0 && (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.indent));
|
|
457
|
-
if (typeof indent === "number" && style.levels !== undefined) {
|
|
458
|
-
throw new Error("The indent param is deprecated for new beam fixed & flexible styles, use beamNestedFixedStyle or beamNestedFlexibleStyle");
|
|
459
|
-
}
|
|
460
|
-
return indent === 1 ? style.indentOneCss || {} : indent === 2 ? style.indentTwoCss || {} : {};
|
|
461
|
-
}
|
|
462
|
-
function getFirstOrLastCellCss(style, columnIndex, columns) {
|
|
463
|
-
return {
|
|
464
|
-
...(columnIndex === 0 ? style.firstCellCss : {}),
|
|
465
|
-
...(columnIndex === columns.length - 1 ? style.lastCellCss : {}),
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
// We extract GridRow to its own mini-component primarily so we can React.memo'ize it.
|
|
469
|
-
function GridRow(props) {
|
|
470
|
-
var _a;
|
|
471
|
-
const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset, sortOn, sortState, setSortKey, columnSizes, level, getCount, api, cellHighlight, ...others } = props;
|
|
472
|
-
const { rowState } = (0, react_1.useContext)(RowState_1.RowStateContext);
|
|
473
|
-
const rowId = `${row.kind}_${row.id}`;
|
|
474
|
-
const isActive = (0, hooks_1.useComputed)(() => rowState.activeRowId === rowId, [rowId, rowState]);
|
|
475
|
-
// We treat the "header" and "totals" kind as special for "good defaults" styling
|
|
476
|
-
const isHeader = row.kind === "header";
|
|
477
|
-
const isTotals = row.kind === "totals";
|
|
478
|
-
const rowStyle = rowStyles === null || rowStyles === void 0 ? void 0 : rowStyles[row.kind];
|
|
479
|
-
const Row = as === "table" ? "tr" : "div";
|
|
480
|
-
const revealOnRowHoverClass = "revealOnRowHover";
|
|
481
|
-
const rowStyleCellCss = maybeApplyFunction(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.cellCss);
|
|
482
|
-
const rowCss = {
|
|
483
|
-
// For virtual tables use `display: flex` to keep all cells on the same row. For each cell in the row use `flexNone` to ensure they stay their defined widths
|
|
484
|
-
...(as === "table" ? {} : Css_1.Css.relative.df.fg1.fs1.addIn("&>*", Css_1.Css.flexNone.$).$),
|
|
485
|
-
...(((rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowLink) || (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.onClick)) && {
|
|
486
|
-
// Even though backgroundColor is set on the cellCss, the hover target is the row.
|
|
487
|
-
"&:hover > *": Css_1.Css.cursorPointer.bgColor((_a = style.rowHoverColor) !== null && _a !== void 0 ? _a : Css_1.Palette.LightBlue100).$,
|
|
488
|
-
}),
|
|
489
|
-
...maybeApplyFunction(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowCss),
|
|
490
|
-
// Maybe add the sticky header styles
|
|
491
|
-
...((isHeader || isTotals) && stickyHeader ? Css_1.Css.sticky.topPx(stickyOffset).z2.$ : undefined),
|
|
492
|
-
...{
|
|
493
|
-
[` > .${revealOnRowHoverClass} > *`]: Css_1.Css.invisible.$,
|
|
494
|
-
[`:hover > .${revealOnRowHoverClass} > *`]: Css_1.Css.visible.$,
|
|
495
|
-
},
|
|
496
|
-
};
|
|
497
|
-
let currentColspan = 1;
|
|
498
|
-
let firstContentColumnStylesApplied = false;
|
|
499
|
-
return ((0, jsx_runtime_1.jsx)(Row, Object.assign({ css: rowCss }, others, { "data-gridrow": true }, getCount(row.id), { children: columns.map((column, columnIndex) => {
|
|
500
|
-
var _a, _b, _c, _d, _e;
|
|
501
|
-
const { wrapAction = true, isAction = false } = column;
|
|
502
|
-
const applyFirstContentColumnStyles = !isHeader && !isAction && !firstContentColumnStylesApplied;
|
|
503
|
-
firstContentColumnStylesApplied || (firstContentColumnStylesApplied = applyFirstContentColumnStyles);
|
|
504
|
-
if (column.mw) {
|
|
505
|
-
// Validate the column's minWidth definition if set.
|
|
506
|
-
if (!column.mw.endsWith("px") && !column.mw.endsWith("%")) {
|
|
507
|
-
throw new Error("Beam Table column min-width definition only supports px or percentage values");
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
// Decrement colspan count and skip if greater than 1.
|
|
511
|
-
if (currentColspan > 1) {
|
|
512
|
-
currentColspan -= 1;
|
|
513
|
-
return null;
|
|
514
|
-
}
|
|
515
|
-
const maybeContent = applyRowFn(column, row, api, level);
|
|
516
|
-
currentColspan = isGridCellContent(maybeContent) ? (_a = maybeContent.colspan) !== null && _a !== void 0 ? _a : 1 : 1;
|
|
517
|
-
const revealOnRowHover = isGridCellContent(maybeContent) ? maybeContent.revealOnRowHover : false;
|
|
518
|
-
const canSortColumn = (sortOn === "client" && column.clientSideSort !== false) ||
|
|
519
|
-
(sortOn === "server" && !!column.serverSideSortKey);
|
|
520
|
-
const alignment = getAlignment(column, maybeContent);
|
|
521
|
-
const justificationCss = getJustification(column, maybeContent, as, alignment);
|
|
522
|
-
const content = toContent(maybeContent, isHeader, canSortColumn, sortOn === "client", style, as, alignment);
|
|
523
|
-
(0, sortRows_1.ensureClientSideSortValueIsSortable)(sortOn, isHeader, column, columnIndex, maybeContent);
|
|
524
|
-
const maybeSticky = (_b = ((isGridCellContent(maybeContent) && maybeContent.sticky) || column.sticky)) !== null && _b !== void 0 ? _b : undefined;
|
|
525
|
-
const maybeStickyColumnStyles = maybeSticky && columnSizes
|
|
526
|
-
? {
|
|
527
|
-
...Css_1.Css.sticky.z1.bgWhite.$,
|
|
528
|
-
...(maybeSticky === "left"
|
|
529
|
-
? Css_1.Css.left(columnIndex === 0 ? 0 : `calc(${columnSizes.slice(0, columnIndex).join(" + ")})`).$
|
|
530
|
-
: {}),
|
|
531
|
-
...(maybeSticky === "right"
|
|
532
|
-
? Css_1.Css.right(columnIndex + 1 === columnSizes.length
|
|
533
|
-
? 0
|
|
534
|
-
: `calc(${columnSizes.slice(columnIndex + 1 - columnSizes.length).join(" + ")})`).$
|
|
535
|
-
: {}),
|
|
536
|
-
}
|
|
537
|
-
: {};
|
|
538
|
-
const cellId = `${row.kind}_${row.id}_${column.name}`;
|
|
539
|
-
const applyCellHighlight = cellHighlight && !!column.name && !isHeader && !isTotals;
|
|
540
|
-
const isCellActive = rowState.activeCellId === cellId;
|
|
541
|
-
// Note that it seems expensive to calc a per-cell class name/CSS-in-JS output,
|
|
542
|
-
// vs. setting global/table-wide CSS like `style.cellCss` on the root grid div with
|
|
543
|
-
// a few descendent selectors. However, that approach means the root grid-applied
|
|
544
|
-
// CSS has a high-specificity and so its harder for per-page/per-cell business logic
|
|
545
|
-
// to override it. So, we just calc the combined table-wide+per-cell-overridden CSS here,
|
|
546
|
-
// in a very CSS-in-JS idiomatic manner.
|
|
547
|
-
//
|
|
548
|
-
// In practice we've not seen any performance issues with this from our "large but
|
|
549
|
-
// not Google spreadsheets" tables.
|
|
550
|
-
const cellCss = {
|
|
551
|
-
// Adding display flex so we can align content within the cells
|
|
552
|
-
...Css_1.Css.df.$,
|
|
553
|
-
// Apply sticky column/cell styles
|
|
554
|
-
...maybeStickyColumnStyles,
|
|
555
|
-
// Apply any static/all-cell styling
|
|
556
|
-
...style.cellCss,
|
|
557
|
-
// Then override with first/last cell styling
|
|
558
|
-
...getFirstOrLastCellCss(style, columnIndex, columns),
|
|
559
|
-
// Then override with per-cell/per-row justification/indentation
|
|
560
|
-
...justificationCss,
|
|
561
|
-
...getIndentationCss(style, rowStyle, columnIndex, maybeContent),
|
|
562
|
-
// Then apply any header-specific override
|
|
563
|
-
...(isHeader && style.headerCellCss),
|
|
564
|
-
// Then apply any totals-specific override
|
|
565
|
-
...(isTotals && style.totalsCellCss),
|
|
566
|
-
// Or level-specific styling
|
|
567
|
-
...(!isHeader && !isTotals && !!style.levels && ((_c = style.levels[level]) === null || _c === void 0 ? void 0 : _c.cellCss)),
|
|
568
|
-
// Level specific styling for the first content column
|
|
569
|
-
...(applyFirstContentColumnStyles && !!style.levels && ((_d = style.levels[level]) === null || _d === void 0 ? void 0 : _d.firstContentColumn)),
|
|
570
|
-
// The specific cell's css (if any from GridCellContent)
|
|
571
|
-
...rowStyleCellCss,
|
|
572
|
-
// Apply active row styling for non-nested card styles.
|
|
573
|
-
...(isActive ? Css_1.Css.bgColor((_e = style.activeBgColor) !== null && _e !== void 0 ? _e : Css_1.Palette.LightBlue50).$ : {}),
|
|
574
|
-
// Add any cell specific style overrides
|
|
575
|
-
...(isGridCellContent(maybeContent) && maybeContent.typeScale ? Css_1.Css[maybeContent.typeScale].$ : {}),
|
|
576
|
-
// And any cell specific css
|
|
577
|
-
...(isGridCellContent(maybeContent) && maybeContent.css ? maybeContent.css : {}),
|
|
578
|
-
// Apply cell highlight styles to active cell and hover
|
|
579
|
-
...Css_1.Css.if(applyCellHighlight && isCellActive).br4.boxShadow(`inset 0 0 0 1px ${Css_1.Palette.LightBlue700}`).$,
|
|
580
|
-
// Define the width of the column on each cell. Supports col spans.
|
|
581
|
-
width: `calc(${columnSizes.slice(columnIndex, columnIndex + currentColspan).join(" + ")})`,
|
|
582
|
-
...(column.mw ? Css_1.Css.mw(column.mw).$ : {}),
|
|
583
|
-
};
|
|
584
|
-
const cellClassNames = revealOnRowHover ? revealOnRowHoverClass : undefined;
|
|
585
|
-
const cellOnClick = applyCellHighlight ? () => api.setActiveCellId(cellId) : undefined;
|
|
586
|
-
const renderFn = ((rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.renderCell) || (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowLink)) && wrapAction
|
|
587
|
-
? rowLinkRenderFn(as)
|
|
588
|
-
: isHeader
|
|
589
|
-
? headerRenderFn(columns, column, sortState, setSortKey, as)
|
|
590
|
-
: (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.onClick) && wrapAction
|
|
591
|
-
? rowClickRenderFn(as, api)
|
|
592
|
-
: defaultRenderFn(as);
|
|
593
|
-
return renderFn(columnIndex, cellCss, content, row, rowStyle, cellClassNames, cellOnClick);
|
|
594
|
-
}) }), void 0));
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* Memoizes GridRows so that re-rendering the table doesn't re-render every single row.
|
|
598
|
-
*
|
|
599
|
-
* We use a custom `propsAreEqual` for the `GridRowProps.row` property, which we memoize
|
|
600
|
-
* based on the `GridDataRow.data` prop, such that if a table re-renders (i.e. for a cache
|
|
601
|
-
* updated) and technically creates new row instances, but a row's `row.data` points to the
|
|
602
|
-
* same/unchanged Apollo cache fragment, then we won't re-render that row.
|
|
603
|
-
*
|
|
604
|
-
* Note that if you're using virtualization, it can be surprising how unnoticeable broken row
|
|
605
|
-
* memoization is.
|
|
606
|
-
*/
|
|
607
|
-
// Declared as a const + `as typeof GridRow` to work with generics, see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/37087#issuecomment-656596623
|
|
608
|
-
const MemoizedGridRow = react_1.default.memo((0, mobx_react_1.observer)(GridRow), (one, two) => {
|
|
609
|
-
const { row: row1, ...others1 } = one;
|
|
610
|
-
const { row: row2, ...others2 } = two;
|
|
611
|
-
return (0, shallowEqual_1.shallowEqual)(row1, row2) && (0, shallowEqual_1.shallowEqual)(others1, others2);
|
|
612
|
-
});
|
|
613
|
-
/** A heuristic to detect the result of `React.createElement` / i.e. JSX. */
|
|
614
|
-
function isJSX(content) {
|
|
615
|
-
return typeof content === "object" && content && "type" in content && "props" in content;
|
|
616
|
-
}
|
|
617
|
-
/** If a column def return just string text for a given row, apply some default styling. */
|
|
618
|
-
function toContent(maybeContent, isHeader, canSortColumn, isClientSideSorting, style, as, alignment) {
|
|
619
|
-
var _a, _b;
|
|
620
|
-
let content = isGridCellContent(maybeContent) ? maybeContent.content : maybeContent;
|
|
621
|
-
if (typeof content === "function") {
|
|
622
|
-
// Actually create the JSX by calling `content()` here (which should be as late as
|
|
623
|
-
// possible, i.e. only for visible rows if we're in a virtual table).
|
|
624
|
-
content = content();
|
|
625
|
-
}
|
|
626
|
-
else if (as === "virtual" && canSortColumn && isClientSideSorting && isJSX(content)) {
|
|
627
|
-
// When using client-side sorting, we call `applyRowFn` not only during rendering, but
|
|
628
|
-
// up-front against all rows (for the currently sorted column) to determine their
|
|
629
|
-
// sort values.
|
|
630
|
-
//
|
|
631
|
-
// Pedantically this means that any table using client-side sorting should not
|
|
632
|
-
// build JSX directly in its GridColumn functions, but this overhead is especially
|
|
633
|
-
// noticeable for large/virtualized tables, so we only enforce using functions
|
|
634
|
-
// for those tables.
|
|
635
|
-
throw new Error("GridTables with as=virtual & sortable columns should use functions that return JSX, instead of JSX");
|
|
636
|
-
}
|
|
637
|
-
content =
|
|
638
|
-
isGridCellContent(maybeContent) && !!maybeContent.onClick
|
|
639
|
-
? (0, getInteractiveElement_1.getButtonOrLink)(content, maybeContent.onClick, {
|
|
640
|
-
css: Css_1.Css.maxw100.lightBlue700.ta("inherit").if(((_a = style === null || style === void 0 ? void 0 : style.presentationSettings) === null || _a === void 0 ? void 0 : _a.wrap) === false).truncate.$,
|
|
641
|
-
})
|
|
642
|
-
: content;
|
|
643
|
-
if (content && typeof content === "string" && isHeader && canSortColumn) {
|
|
644
|
-
return (0, jsx_runtime_1.jsx)(SortHeader_1.SortHeader, { content: content, iconOnLeft: alignment === "right" }, void 0);
|
|
645
|
-
}
|
|
646
|
-
else if (content && ((_b = style === null || style === void 0 ? void 0 : style.presentationSettings) === null || _b === void 0 ? void 0 : _b.wrap) === false && typeof content === "string") {
|
|
647
|
-
// In order to truncate the text properly, then we need to wrap it in another element
|
|
648
|
-
// as our cell element is a flex container, which don't allow for applying truncation styles directly on it.
|
|
649
|
-
return ((0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.truncate.mw0.$, title: content }, { children: content }), void 0));
|
|
650
|
-
}
|
|
651
|
-
else if (style.emptyCell && isContentEmpty(content)) {
|
|
652
|
-
// If the content is empty and the user specified an `emptyCell` node, return that.
|
|
653
|
-
return style.emptyCell;
|
|
654
|
-
}
|
|
655
|
-
return content;
|
|
656
|
-
}
|
|
657
|
-
function isGridCellContent(content) {
|
|
658
|
-
return typeof content === "object" && !!content && "content" in content;
|
|
659
|
-
}
|
|
660
|
-
const emptyValues = ["", null, undefined];
|
|
661
|
-
function isContentEmpty(content) {
|
|
662
|
-
return emptyValues.includes(content);
|
|
663
|
-
}
|
|
664
|
-
/** Return the content for a given column def applied to a given row. */
|
|
665
|
-
function applyRowFn(column, row, api, level) {
|
|
666
|
-
// Usually this is a function to apply against the row, but sometimes it's a hard-coded value, i.e. for headers
|
|
667
|
-
const maybeContent = column[row.kind];
|
|
668
|
-
if (typeof maybeContent === "function") {
|
|
669
|
-
// Auto-destructure data
|
|
670
|
-
return maybeContent(row["data"], { row: row, api, level });
|
|
671
|
-
}
|
|
672
|
-
else {
|
|
673
|
-
return maybeContent;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
exports.applyRowFn = applyRowFn;
|
|
677
|
-
/** Renders our default cell element, i.e. if no row links and no custom renderCell are used. */
|
|
678
|
-
const defaultRenderFn = (as) => (key, css, content, row, rowStyle, classNames, onClick) => {
|
|
679
|
-
const Cell = as === "table" ? "td" : "div";
|
|
680
|
-
return ((0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...tableRowStyles(as) }, className: classNames, onClick: onClick }, { children: content }), key));
|
|
681
|
-
};
|
|
682
|
-
/** Sets up the `GridContext` so that header cells can access the current sort settings. */
|
|
683
|
-
const headerRenderFn = (columns, column, sortState, setSortKey, as) => (key, css, content, row, rowStyle, classNames) => {
|
|
684
|
-
const [currentKey, direction] = sortState || [];
|
|
685
|
-
// If server-side sorting, use the user's key for this column; client-side sorting, use the index.
|
|
686
|
-
const ourSortKey = column.serverSideSortKey || columns.indexOf(column);
|
|
687
|
-
const context = {
|
|
688
|
-
sorted: ourSortKey === currentKey ? direction : undefined,
|
|
689
|
-
toggleSort: () => setSortKey(ourSortKey),
|
|
690
|
-
};
|
|
691
|
-
const Cell = as === "table" ? "th" : "div";
|
|
692
|
-
return ((0, jsx_runtime_1.jsx)(GridSortContext_1.GridSortContext.Provider, Object.assign({ value: context }, { children: (0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...tableRowStyles(as, column) }, className: classNames }, { children: content }), void 0) }), key));
|
|
693
|
-
};
|
|
694
|
-
/** Renders a cell element when a row link is in play. */
|
|
695
|
-
const rowLinkRenderFn = (as) => (key, css, content, row, rowStyle, classNames) => {
|
|
696
|
-
const to = rowStyle.rowLink(row);
|
|
697
|
-
if (as === "table") {
|
|
698
|
-
return ((0, jsx_runtime_1.jsx)("td", Object.assign({ css: { ...css, ...tableRowStyles(as) }, className: classNames }, { children: (0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({ to: to, css: Css_1.Css.noUnderline.color("unset").db.$, className: CssReset_1.navLink }, { children: content }), void 0) }), key));
|
|
699
|
-
}
|
|
700
|
-
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} ${classNames}` }, { children: content }), key));
|
|
701
|
-
};
|
|
702
|
-
/** Renders a cell that will fire the RowStyle.onClick. */
|
|
703
|
-
const rowClickRenderFn = (as, api) => (key, css, content, row, rowStyle, classNames, onClick) => {
|
|
704
|
-
const Row = as === "table" ? "tr" : "div";
|
|
705
|
-
return ((0, jsx_runtime_1.jsx)(Row, Object.assign({}, { key }, { css: { ...css, ...tableRowStyles(as) }, className: classNames, onClick: (e) => {
|
|
706
|
-
rowStyle.onClick(row, api);
|
|
707
|
-
onClick && onClick();
|
|
708
|
-
} }, { children: content }), void 0));
|
|
709
|
-
};
|
|
710
|
-
const alignmentToJustify = {
|
|
711
|
-
left: "flex-start",
|
|
712
|
-
center: "center",
|
|
713
|
-
right: "flex-end",
|
|
714
|
-
};
|
|
715
|
-
const alignmentToTextAlign = {
|
|
716
|
-
left: "left",
|
|
717
|
-
center: "center",
|
|
718
|
-
right: "right",
|
|
719
|
-
};
|
|
720
|
-
function getAlignment(column, maybeContent) {
|
|
721
|
-
return (isGridCellContent(maybeContent) && maybeContent.alignment) || column.align || "left";
|
|
722
|
-
}
|
|
723
|
-
// For alignment, use: 1) cell def, else 2) column def, else 3) left.
|
|
724
|
-
function getJustification(column, maybeContent, as, alignment) {
|
|
725
|
-
// Always apply text alignment.
|
|
726
|
-
const textAlign = Css_1.Css.add("textAlign", alignmentToTextAlign[alignment]).$;
|
|
727
|
-
if (as === "table") {
|
|
728
|
-
return textAlign;
|
|
729
|
-
}
|
|
730
|
-
return { ...Css_1.Css.jc(alignmentToJustify[alignment]).$, ...textAlign };
|
|
731
|
-
}
|
|
732
|
-
/** Look at a row and get its filter value. */
|
|
733
|
-
function filterValue(value) {
|
|
734
|
-
let maybeFn = value;
|
|
735
|
-
if (value && typeof value === "object") {
|
|
736
|
-
if ("value" in value) {
|
|
737
|
-
maybeFn = value.value;
|
|
738
|
-
}
|
|
739
|
-
else if ("content" in value) {
|
|
740
|
-
maybeFn = value.content;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
// Watch for functions that need to read from a potentially-changing proxy
|
|
744
|
-
if (maybeFn instanceof Function) {
|
|
745
|
-
return maybeFn();
|
|
746
|
-
}
|
|
747
|
-
return maybeFn;
|
|
748
|
-
}
|
|
749
|
-
function maybeApplyFunction(row, maybeFn) {
|
|
750
|
-
return typeof maybeFn === "function" ? maybeFn(row) : maybeFn;
|
|
751
|
-
}
|
|
752
|
-
function matchesFilter(maybeContent, filter) {
|
|
753
|
-
let value = filterValue(maybeContent);
|
|
754
|
-
if (typeof value === "string") {
|
|
755
|
-
return value.toLowerCase().includes(filter.toLowerCase());
|
|
756
|
-
}
|
|
757
|
-
else if (typeof value === "number") {
|
|
758
|
-
return Number(filter) === value;
|
|
759
|
-
}
|
|
760
|
-
return false;
|
|
761
|
-
}
|
|
762
|
-
exports.matchesFilter = matchesFilter;
|
|
763
|
-
/** GridTable as Table utility to apply <tr> element override styles. */
|
|
764
|
-
function tableRowStyles(as, column) {
|
|
765
|
-
const thWidth = column === null || column === void 0 ? void 0 : column.w;
|
|
766
|
-
return as === "table"
|
|
767
|
-
? {
|
|
768
|
-
...Css_1.Css.dtc.$,
|
|
769
|
-
...(thWidth ? Css_1.Css.w(thWidth).$ : {}),
|
|
770
|
-
}
|
|
771
|
-
: {};
|
|
772
|
-
}
|
|
773
|
-
function resolveStyles(style) {
|
|
774
|
-
const defKeys = ["inlineEditing", "grouped", "rowHeight", "cellHighlight"];
|
|
775
|
-
const keys = (0, utils_1.safeKeys)(style);
|
|
776
|
-
if (keys.length === 0 || keys.some((k) => defKeys.includes(k))) {
|
|
777
|
-
return (0, styles_1.getTableStyles)(style);
|
|
778
|
-
}
|
|
779
|
-
return style;
|
|
780
|
-
}
|
|
781
369
|
/**
|
|
782
370
|
* Filters rows given a client-side text `filter.
|
|
783
371
|
*
|
|
@@ -798,7 +386,7 @@ function filterRows(api, columns, rows, filter) {
|
|
|
798
386
|
const matches = row.kind === "header" ||
|
|
799
387
|
row.kind === "totals" ||
|
|
800
388
|
filters.length === 0 ||
|
|
801
|
-
filters.every((f) => columns.map((c) => applyRowFn(c, row, api, 0)).some((maybeContent) => matchesFilter(maybeContent, f)));
|
|
389
|
+
filters.every((f) => columns.map((c) => (0, utils_1.applyRowFn)(c, row, api, 0)).some((maybeContent) => (0, utils_1.matchesFilter)(maybeContent, f)));
|
|
802
390
|
if (matches) {
|
|
803
391
|
return acc.concat([[row, (_b = (_a = row.children) === null || _a === void 0 ? void 0 : _a.reduce(acceptAll, [])) !== null && _b !== void 0 ? _b : []]]);
|
|
804
392
|
}
|
|
@@ -816,3 +404,4 @@ function filterRows(api, columns, rows, filter) {
|
|
|
816
404
|
}
|
|
817
405
|
return rows.reduce(filterFn, []);
|
|
818
406
|
}
|
|
407
|
+
exports.filterRows = filterRows;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { MutableRefObject } from "react";
|
|
2
2
|
import { VirtuosoHandle } from "react-virtuoso";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { GridDataRow } from "./components/Row";
|
|
4
|
+
import { DiscriminateUnion, Kinded } from "./types";
|
|
5
|
+
import { RowState } from "./utils/RowState";
|
|
5
6
|
/**
|
|
6
7
|
* Creates an `api` handle to drive a `GridTable`.
|
|
7
8
|
*
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GridTableApiImpl = exports.useGridTableApi = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
|
-
const RowState_1 = require("./RowState");
|
|
6
|
-
const visitor_1 = require("./visitor");
|
|
5
|
+
const RowState_1 = require("./utils/RowState");
|
|
6
|
+
const visitor_1 = require("./utils/visitor");
|
|
7
7
|
/**
|
|
8
8
|
* Creates an `api` handle to drive a `GridTable`.
|
|
9
9
|
*
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { PresentationContextProps, PresentationFieldProps } from "../PresentationContext";
|
|
3
|
+
import { DiscriminateUnion, GridColumn, GridDataRow, GridTableApi, RenderCellFn } from "./index";
|
|
4
|
+
import { Kinded, RenderAs } from "./types";
|
|
5
|
+
import { Palette, Properties } from "../../Css";
|
|
6
|
+
/** Completely static look & feel, i.e. nothing that is based on row kinds/content. */
|
|
7
|
+
export interface GridStyle {
|
|
8
|
+
/** Applied to the base div element. */
|
|
9
|
+
rootCss?: Properties;
|
|
10
|
+
/** Applied with the owl operator between rows for rendering border lines. */
|
|
11
|
+
betweenRowsCss?: Properties;
|
|
12
|
+
/** Applied to the first non-header row, i.e. if you want to cancel out `betweenRowsCss`. */
|
|
13
|
+
firstNonHeaderRowCss?: Properties;
|
|
14
|
+
/** Applied to all cell divs (via a selector off the base div). */
|
|
15
|
+
cellCss?: Properties;
|
|
16
|
+
/**
|
|
17
|
+
* Applied to the header row divs.
|
|
18
|
+
*
|
|
19
|
+
* NOTE `as=virtual`: When using a virtual table with the goal of adding space
|
|
20
|
+
* between the header and the first row use `firstNonHeaderRowCss` with a
|
|
21
|
+
* margin-top instead. Using `headerCellCss` will not work since the header
|
|
22
|
+
* rows are wrapper with Chrome rows.
|
|
23
|
+
*/
|
|
24
|
+
headerCellCss?: Properties;
|
|
25
|
+
/** Applied to 'kind: "totals"' cells */
|
|
26
|
+
totalsCellCss?: Properties;
|
|
27
|
+
/** Applied to the first cell of all rows, i.e. for table-wide padding or left-side borders. */
|
|
28
|
+
firstCellCss?: Properties;
|
|
29
|
+
/** Applied to the last cell of all rows, i.e. for table-wide padding or right-side borders. */
|
|
30
|
+
lastCellCss?: Properties;
|
|
31
|
+
/** Applied to a cell div when `indent: 1` is used. */
|
|
32
|
+
indentOneCss?: Properties;
|
|
33
|
+
/** Applied to a cell div when `indent: 2` is used. */
|
|
34
|
+
indentTwoCss?: Properties;
|
|
35
|
+
/** Applied if there is a fallback/overflow message showing. */
|
|
36
|
+
firstRowMessageCss?: Properties;
|
|
37
|
+
/** Applied on hover if a row has a rowLink/onClick set. */
|
|
38
|
+
rowHoverColor?: Palette;
|
|
39
|
+
/** Default content to put into an empty cell */
|
|
40
|
+
emptyCell?: ReactNode;
|
|
41
|
+
presentationSettings?: Pick<PresentationFieldProps, "borderless" | "typeScale"> & Pick<PresentationContextProps, "wrap">;
|
|
42
|
+
/** Minimum table width in pixels. Used when calculating columns sizes */
|
|
43
|
+
minWidthPx?: number;
|
|
44
|
+
/** Css to apply at each level of a parent/child nested table. */
|
|
45
|
+
levels?: Record<number, {
|
|
46
|
+
cellCss?: Properties;
|
|
47
|
+
firstContentColumn?: Properties;
|
|
48
|
+
}>;
|
|
49
|
+
/** Allows for customization of the background color used to denote an "active" row */
|
|
50
|
+
activeBgColor?: Palette;
|
|
51
|
+
}
|
|
52
|
+
export interface GridStyleDef {
|
|
53
|
+
inlineEditing?: boolean;
|
|
54
|
+
grouped?: boolean;
|
|
55
|
+
rowHeight?: "fixed" | "flexible";
|
|
56
|
+
/** Enables cells Highlight and hover */
|
|
57
|
+
cellHighlight?: boolean;
|
|
58
|
+
}
|
|
59
|
+
export declare const getTableStyles: (props?: GridStyleDef) => GridStyle;
|
|
60
|
+
/** Defines row-specific styling for each given row `kind` in `R` */
|
|
61
|
+
export declare type RowStyles<R extends Kinded> = {
|
|
62
|
+
[P in R["kind"]]?: RowStyle<DiscriminateUnion<R, "kind", P>>;
|
|
63
|
+
};
|
|
64
|
+
export interface RowStyle<R extends Kinded> {
|
|
65
|
+
/** Applies this css to the wrapper row, i.e. for row-level hovers. */
|
|
66
|
+
rowCss?: Properties | ((row: R) => Properties);
|
|
67
|
+
/** Applies this css to each cell in the row. */
|
|
68
|
+
cellCss?: Properties | ((row: R) => Properties);
|
|
69
|
+
/** Renders the cell element, i.e. a link to get whole-row links. */
|
|
70
|
+
renderCell?: RenderCellFn<R>;
|
|
71
|
+
/** Whether the row should be indented (via a style applied to the 1st cell). */
|
|
72
|
+
indent?: 1 | 2;
|
|
73
|
+
/** Whether the row should be a link. */
|
|
74
|
+
rowLink?: (row: R) => string;
|
|
75
|
+
/** Fired when the row is clicked, similar to rowLink but for actions that aren't 'go to this link'. */
|
|
76
|
+
onClick?: (row: GridDataRow<R>, api: GridTableApi<R>) => void;
|
|
77
|
+
}
|
|
78
|
+
/** Our original table look & feel/style. */
|
|
79
|
+
export declare const defaultStyle: GridStyle;
|
|
80
|
+
/** Tightens up the padding of rows, great for rows that have form elements in them. */
|
|
81
|
+
export declare const condensedStyle: GridStyle;
|
|
82
|
+
/** Renders each row as a card. */
|
|
83
|
+
export declare const cardStyle: GridStyle;
|
|
84
|
+
/** GridTable as Table utility to apply <tr> element override styles. */
|
|
85
|
+
export declare function tableRowStyles(as: RenderAs, column?: GridColumn<any>): {};
|
|
86
|
+
export declare function resolveStyles(style: GridStyle | GridStyleDef): GridStyle;
|