@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.
Files changed (49) hide show
  1. package/dist/components/SuperDrawer/ConfirmCloseModal.js +1 -1
  2. package/dist/components/SuperDrawer/SuperDrawer.js +4 -10
  3. package/dist/components/Table/GridTable.d.ts +11 -218
  4. package/dist/components/Table/GridTable.js +15 -426
  5. package/dist/components/Table/GridTableApi.d.ts +3 -2
  6. package/dist/components/Table/GridTableApi.js +2 -2
  7. package/dist/components/Table/TableStyles.d.ts +86 -0
  8. package/dist/components/Table/{styles.js → TableStyles.js} +55 -34
  9. package/dist/components/Table/{CollapseToggle.d.ts → components/CollapseToggle.d.ts} +1 -1
  10. package/dist/components/Table/{CollapseToggle.js → components/CollapseToggle.js} +4 -4
  11. package/dist/components/Table/{EditColumnsButton.d.ts → components/EditColumnsButton.d.ts} +2 -2
  12. package/dist/components/Table/{EditColumnsButton.js → components/EditColumnsButton.js} +5 -5
  13. package/dist/components/Table/components/Row.d.ts +71 -0
  14. package/dist/components/Table/components/Row.js +177 -0
  15. package/dist/components/Table/{SelectToggle.d.ts → components/SelectToggle.d.ts} +0 -0
  16. package/dist/components/Table/{SelectToggle.js → components/SelectToggle.js} +5 -5
  17. package/dist/components/Table/{SortHeader.d.ts → components/SortHeader.d.ts} +1 -1
  18. package/dist/components/Table/{SortHeader.js → components/SortHeader.js} +5 -5
  19. package/dist/components/Table/components/cell.d.ts +41 -0
  20. package/dist/components/Table/components/cell.js +46 -0
  21. package/dist/components/Table/{useColumns.d.ts → hooks/useColumns.d.ts} +1 -1
  22. package/dist/components/Table/{useColumns.js → hooks/useColumns.js} +1 -1
  23. package/dist/components/Table/{columnSizes.d.ts → hooks/useSetupColumnSizes.d.ts} +2 -1
  24. package/dist/components/Table/{columnSizes.js → hooks/useSetupColumnSizes.js} +3 -3
  25. package/dist/components/Table/{useSortState.d.ts → hooks/useSortState.d.ts} +2 -1
  26. package/dist/components/Table/{useSortState.js → hooks/useSortState.js} +6 -6
  27. package/dist/components/Table/index.d.ts +30 -14
  28. package/dist/components/Table/index.js +38 -24
  29. package/dist/components/Table/types.d.ts +83 -0
  30. package/dist/components/Table/types.js +16 -0
  31. package/dist/components/Table/{GridRowLookup.d.ts → utils/GridRowLookup.d.ts} +2 -1
  32. package/dist/components/Table/{GridRowLookup.js → utils/GridRowLookup.js} +2 -2
  33. package/dist/components/Table/{GridSortContext.d.ts → utils/GridSortContext.d.ts} +0 -0
  34. package/dist/components/Table/{GridSortContext.js → utils/GridSortContext.js} +0 -0
  35. package/dist/components/Table/{RowState.d.ts → utils/RowState.d.ts} +1 -1
  36. package/dist/components/Table/{RowState.js → utils/RowState.js} +0 -0
  37. package/dist/components/Table/{columns.d.ts → utils/columns.d.ts} +6 -1
  38. package/dist/components/Table/utils/columns.js +149 -0
  39. package/dist/components/Table/{simpleHelpers.d.ts → utils/simpleHelpers.d.ts} +1 -1
  40. package/dist/components/Table/{simpleHelpers.js → utils/simpleHelpers.js} +0 -0
  41. package/dist/components/Table/{sortRows.d.ts → utils/sortRows.d.ts} +4 -2
  42. package/dist/components/Table/{sortRows.js → utils/sortRows.js} +3 -3
  43. package/dist/components/Table/utils/utils.d.ts +23 -0
  44. package/dist/components/Table/utils/utils.js +148 -0
  45. package/dist/components/Table/{visitor.d.ts → utils/visitor.d.ts} +1 -1
  46. package/dist/components/Table/{visitor.js → utils/visitor.js} +0 -0
  47. package/package.json +1 -1
  48. package/dist/components/Table/columns.js +0 -84
  49. 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.matchesFilter = exports.applyRowFn = exports.nonKindGridColumnKeys = exports.calcColumnSizes = exports.GridTable = exports.setGridTableDefaults = exports.setDefaultStyle = exports.setRunningInJest = exports.emptyCell = exports.DESC = exports.ASC = void 0;
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 RowState_1 = require("./RowState");
39
- const SortHeader_1 = require("./SortHeader");
40
- const sortRows_1 = require("./sortRows");
41
- const styles_1 = require("./styles");
42
- const useSortState_1 = require("./useSortState");
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 utils_1 = require("../../utils");
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: _1.defaultStyle,
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, columnSizes_1.useSetupColumnSizes)(style, columns, resizeTarget !== null && resizeTarget !== void 0 ? resizeTarget : resizeRef);
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)(MemoizedGridRow, Object.assign({}, {
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 { DiscriminateUnion, GridDataRow, Kinded } from "./GridTable";
4
- import { RowState } from "./RowState";
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;