@homebound/beam 2.118.2 → 2.119.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.
@@ -1,6 +1,7 @@
1
1
  import { MutableRefObject, ReactElement, ReactNode } from "react";
2
2
  import { PresentationContextProps, PresentationFieldProps } from "../PresentationContext";
3
3
  import { GridRowLookup } from "./GridRowLookup";
4
+ import { GridTableApi } from "./GridTableApi";
4
5
  import { Margin, Only, Palette, Properties, Typography, Xss } from "../../Css";
5
6
  export declare type Kinded = {
6
7
  kind: string;
@@ -173,8 +174,8 @@ export interface GridTableProps<R extends Kinded, S, X> {
173
174
  */
174
175
  persistCollapse?: string;
175
176
  xss?: X;
176
- /** Experimental API allowing one to scroll to a table index. Primarily intended for stories at the moment */
177
- api?: MutableRefObject<GridTableApi<R> | undefined>;
177
+ /** Accepts the api, from `useGridTableApi`, that the caller wants to use for this table. */
178
+ api?: GridTableApi<R>;
178
179
  /** 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 */
179
180
  resizeTarget?: MutableRefObject<HTMLElement | null>;
180
181
  /**
@@ -184,18 +185,6 @@ export interface GridTableProps<R extends Kinded, S, X> {
184
185
  */
185
186
  activeRowId?: string;
186
187
  }
187
- /** NOTE: This API is experimental and primarily intended for story and testing purposes */
188
- export declare type GridTableApi<R extends Kinded> = {
189
- scrollToIndex: (index: number) => void;
190
- /** Returns the ids of currently-selected rows. */
191
- getSelectedRowIds(): string[];
192
- getSelectedRowIds<K extends R["kind"]>(kind: K): string[];
193
- /** Returns the currently-selected rows. */
194
- getSelectedRows(): GridDataRow<R>[];
195
- getSelectedRows<K extends R["kind"]>(kind: K): GridDataRow<DiscriminateUnion<R, "kind", K>>[];
196
- /** Sets the internal state of 'activeRowId' */
197
- setActiveRowId: (id: string | undefined) => void;
198
- };
199
188
  /**
200
189
  * Renders data in our table layout.
201
190
  *
@@ -327,6 +316,6 @@ export declare type GridDataRow<R extends Kinded> = {
327
316
  } & IfAny<R, {}, DiscriminateUnion<R, "kind", R["kind"]>>;
328
317
  declare type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N;
329
318
  /** Return the content for a given column def applied to a given row. */
330
- export declare function applyRowFn<R extends Kinded>(column: GridColumn<R>, row: GridDataRow<R>, api: MutableRefObject<GridTableApi<R>>): ReactNode | GridCellContent;
319
+ export declare function applyRowFn<R extends Kinded>(column: GridColumn<R>, row: GridDataRow<R>, api: GridTableApi<R>): ReactNode | GridCellContent;
331
320
  export declare function matchesFilter(maybeContent: ReactNode | GridCellContent, filter: string): boolean;
332
321
  export {};
@@ -34,12 +34,12 @@ const PresentationContext_1 = require("../PresentationContext");
34
34
  const columnSizes_1 = require("./columnSizes");
35
35
  const GridRowLookup_1 = require("./GridRowLookup");
36
36
  const GridSortContext_1 = require("./GridSortContext");
37
+ const GridTableApi_1 = require("./GridTableApi");
37
38
  const nestedCards_1 = require("./nestedCards");
38
39
  const RowState_1 = require("./RowState");
39
40
  const SortHeader_1 = require("./SortHeader");
40
41
  const sortRows_1 = require("./sortRows");
41
42
  const useSortState_1 = require("./useSortState");
42
- const visitor_1 = require("./visitor");
43
43
  const Css_1 = require("../../Css");
44
44
  const hooks_1 = require("../../hooks");
45
45
  const useRenderCount_1 = require("../../hooks/useRenderCount");
@@ -85,40 +85,19 @@ 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, filter, filterMaxRows, fallbackMessage = "No rows found.", infoMessage, setRowCount, observeRows, persistCollapse, api: callerApi, resizeTarget, activeRowId, } = props;
89
- // Create a ref that always contains the latest rows, for our effectively-singleton RowState to use
90
- const rowsRef = (0, react_1.useRef)(rows);
91
- rowsRef.current = rows;
92
- const [rowState] = (0, react_1.useState)(() => new RowState_1.RowState(rowsRef, persistCollapse, activeRowId));
88
+ const { id = "gridTable", as = "div", columns, rows, style = defaults.style, rowStyles, stickyHeader = defaults.stickyHeader, stickyOffset = "0", xss, filter, filterMaxRows, fallbackMessage = "No rows found.", infoMessage, setRowCount, observeRows, persistCollapse, resizeTarget, activeRowId, } = props;
93
89
  // We only use this in as=virtual mode, but keep this here for rowLookup to use
94
90
  const virtuosoRef = (0, react_1.useRef)(null);
95
91
  const tableRef = (0, react_1.useRef)(null);
96
- const api = (0, react_1.useRef)({
97
- scrollToIndex: (index) => virtuosoRef.current && virtuosoRef.current.scrollToIndex(index),
98
- getSelectedRowIds(kind) {
99
- if (kind === undefined) {
100
- return rowState.selectedIds;
101
- }
102
- else {
103
- return this.getSelectedRows(kind).map((row) => row.id);
104
- }
105
- },
106
- // The any is not great, but getting the overload to handle the optional kind is annoying
107
- getSelectedRows(kind) {
108
- const ids = rowState.selectedIds;
109
- const selected = [];
110
- (0, visitor_1.visit)(rows, (row) => {
111
- if (ids.includes(row.id) && (!kind || row.kind === kind)) {
112
- selected.push(row);
113
- }
114
- });
115
- return selected;
116
- },
117
- setActiveRowId: (id) => (rowState.activeRowId = id),
118
- });
119
- if (callerApi) {
120
- callerApi.current = api.current;
121
- }
92
+ const api = (0, react_1.useMemo)(() => {
93
+ var _a;
94
+ const api = (_a = props.api) !== null && _a !== void 0 ? _a : new GridTableApi_1.GridTableApiImpl();
95
+ api.init(persistCollapse, virtuosoRef);
96
+ api.setActiveRowId(activeRowId);
97
+ return api;
98
+ }, [props.api]);
99
+ const { rowState } = api;
100
+ rowState.rows = rows;
122
101
  (0, react_1.useEffect)(() => {
123
102
  rowState.activeRowId = activeRowId;
124
103
  }, [rowState, activeRowId]);
@@ -664,10 +643,10 @@ function applyRowFn(column, row, api) {
664
643
  if (typeof maybeContent === "function") {
665
644
  if ("data" in row && "id" in row) {
666
645
  // Auto-destructure data
667
- return maybeContent(row["data"], row["id"], api.current);
646
+ return maybeContent(row["data"], row["id"], api);
668
647
  }
669
648
  else {
670
- return maybeContent(row, api.current);
649
+ return maybeContent(row, api);
671
650
  }
672
651
  }
673
652
  else {
@@ -703,7 +682,7 @@ const rowLinkRenderFn = (as) => (key, css, content, row, rowStyle) => {
703
682
  /** Renders a cell that will fire the RowStyle.onClick. */
704
683
  const rowClickRenderFn = (as, api) => (key, css, content, row, rowStyle) => {
705
684
  const Row = as === "table" ? "tr" : "div";
706
- return ((0, jsx_runtime_1.jsx)(Row, Object.assign({}, { key }, { css: { ...css, ...tableRowStyles(as) }, onClick: () => rowStyle.onClick(row, api.current) }, { children: content }), void 0));
685
+ return ((0, jsx_runtime_1.jsx)(Row, Object.assign({}, { key }, { css: { ...css, ...tableRowStyles(as) }, onClick: () => rowStyle.onClick(row, api) }, { children: content }), void 0));
707
686
  };
708
687
  const alignmentToJustify = {
709
688
  left: "flex-start",
@@ -0,0 +1,43 @@
1
+ import { MutableRefObject } from "react";
2
+ import { VirtuosoHandle } from "react-virtuoso";
3
+ import { DiscriminateUnion, GridDataRow, Kinded } from "./GridTable";
4
+ import { RowState } from "./RowState";
5
+ /**
6
+ * Creates an `api` handle to drive a `GridTable`.
7
+ *
8
+ * ```
9
+ * const api = useGridTableApi<Row>();
10
+ * const count = useComputed(() => api.getSelectedRows().length, [api]);
11
+ * ...
12
+ * return <GridTable api={api} />
13
+ * ```
14
+ *
15
+ * This is very similar to a `useRef`, except that the parent function has
16
+ * immediate access to `api` and can use it for `useComputed`, instead of
17
+ * having to wait for `ref.current` to be set after the child `GridTable`
18
+ * has ran.
19
+ */
20
+ export declare function useGridTableApi<R extends Kinded>(): GridTableApi<R>;
21
+ /** Provides an imperative API for an application page to interact with the table. */
22
+ export declare type GridTableApi<R extends Kinded> = {
23
+ /** Scrolls row `index` into view; only supported with `as=virtual` and after a `useEffect`. */
24
+ scrollToIndex: (index: number) => void;
25
+ /** Returns the ids of currently-selected rows. */
26
+ getSelectedRowIds(): string[];
27
+ getSelectedRowIds<K extends R["kind"]>(kind: K): string[];
28
+ /** Returns the currently-selected rows. */
29
+ getSelectedRows(): GridDataRow<R>[];
30
+ getSelectedRows<K extends R["kind"]>(kind: K): GridDataRow<DiscriminateUnion<R, "kind", K>>[];
31
+ /** Sets the internal state of 'activeRowId' */
32
+ setActiveRowId: (id: string | undefined) => void;
33
+ };
34
+ export declare class GridTableApiImpl<R extends Kinded> implements GridTableApi<R> {
35
+ readonly rowState: RowState;
36
+ virtuosoRef: MutableRefObject<VirtuosoHandle | null>;
37
+ /** Called once by the GridTable when it takes ownership of this api instance. */
38
+ init(persistCollapse: string | undefined, virtuosoRef: MutableRefObject<VirtuosoHandle | null>): void;
39
+ scrollToIndex(index: number): void;
40
+ getSelectedRowIds(kind?: string): string[];
41
+ getSelectedRows(kind?: string): any;
42
+ setActiveRowId(id: string | undefined): void;
43
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GridTableApiImpl = exports.useGridTableApi = void 0;
4
+ const react_1 = require("react");
5
+ const RowState_1 = require("./RowState");
6
+ const visitor_1 = require("./visitor");
7
+ /**
8
+ * Creates an `api` handle to drive a `GridTable`.
9
+ *
10
+ * ```
11
+ * const api = useGridTableApi<Row>();
12
+ * const count = useComputed(() => api.getSelectedRows().length, [api]);
13
+ * ...
14
+ * return <GridTable api={api} />
15
+ * ```
16
+ *
17
+ * This is very similar to a `useRef`, except that the parent function has
18
+ * immediate access to `api` and can use it for `useComputed`, instead of
19
+ * having to wait for `ref.current` to be set after the child `GridTable`
20
+ * has ran.
21
+ */
22
+ function useGridTableApi() {
23
+ return (0, react_1.useMemo)(() => new GridTableApiImpl(), []);
24
+ }
25
+ exports.useGridTableApi = useGridTableApi;
26
+ // Using `FooImpl`to keep the public GridTableApi definition separate.
27
+ class GridTableApiImpl {
28
+ constructor() {
29
+ // This is public to GridTable but not exported outside of Beam
30
+ this.rowState = new RowState_1.RowState();
31
+ this.virtuosoRef = { current: null };
32
+ }
33
+ /** Called once by the GridTable when it takes ownership of this api instance. */
34
+ init(persistCollapse, virtuosoRef) {
35
+ if (persistCollapse) {
36
+ this.rowState.loadPersistedCollapse(persistCollapse);
37
+ }
38
+ this.virtuosoRef = virtuosoRef;
39
+ }
40
+ scrollToIndex(index) {
41
+ this.virtuosoRef.current && this.virtuosoRef.current.scrollToIndex(index);
42
+ }
43
+ getSelectedRowIds(kind) {
44
+ if (kind === undefined) {
45
+ return this.rowState.selectedIds;
46
+ }
47
+ else {
48
+ return this.getSelectedRows(kind).map((row) => row.id);
49
+ }
50
+ }
51
+ // The any is not great, but getting the overload to handle the optional kind is annoying
52
+ getSelectedRows(kind) {
53
+ const ids = this.rowState.selectedIds;
54
+ const selected = [];
55
+ (0, visitor_1.visit)(this.rowState.rows, (row) => {
56
+ if (ids.includes(row.id) && (!kind || row.kind === kind)) {
57
+ selected.push(row);
58
+ }
59
+ });
60
+ return selected;
61
+ }
62
+ setActiveRowId(id) {
63
+ this.rowState.activeRowId = id;
64
+ }
65
+ }
66
+ exports.GridTableApiImpl = GridTableApiImpl;
@@ -1,4 +1,4 @@
1
- import React, { MutableRefObject } from "react";
1
+ import React from "react";
2
2
  import { GridDataRow } from "./GridTable";
3
3
  export declare type SelectedState = "checked" | "unchecked" | "partial";
4
4
  /**
@@ -17,16 +17,17 @@ export declare type SelectedState = "checked" | "unchecked" | "partial";
17
17
  * changes.
18
18
  */
19
19
  export declare class RowState {
20
- private rows;
21
- private persistCollapse;
22
20
  private readonly collapsedRows;
21
+ private persistCollapse;
23
22
  private readonly selectedRows;
24
23
  private visibleRows;
24
+ rows: GridDataRow<any>[];
25
25
  activeRowId: string | undefined;
26
26
  /**
27
27
  * Creates the `RowState` for a given `GridTable`.
28
28
  */
29
- constructor(rows: MutableRefObject<GridDataRow<any>[]>, persistCollapse: string | undefined, activeRowId: string | undefined);
29
+ constructor();
30
+ loadPersistedCollapse(persistCollapse: string): void;
30
31
  setVisibleRows(rowIds: string[]): void;
31
32
  get selectedIds(): string[];
32
33
  getSelected(id: string): SelectedState;
@@ -26,25 +26,29 @@ class RowState {
26
26
  /**
27
27
  * Creates the `RowState` for a given `GridTable`.
28
28
  */
29
- constructor(rows, persistCollapse, activeRowId) {
30
- this.rows = rows;
31
- this.persistCollapse = persistCollapse;
29
+ constructor() {
30
+ // A set of just row ids, i.e. not row.kind+row.id
31
+ this.collapsedRows = new mobx_1.ObservableSet();
32
32
  this.selectedRows = new mobx_1.ObservableMap();
33
33
  // Set of just row ids. Keeps track of which rows are visible. Used to filter out non-visible rows from `selectedIds`
34
34
  this.visibleRows = new mobx_1.ObservableSet();
35
- this.collapsedRows = new mobx_1.ObservableSet(persistCollapse ? readLocalCollapseState(persistCollapse) : []);
36
- this.activeRowId = activeRowId;
35
+ // The current list of rows, basically a useRef.current. Not reactive.
36
+ this.rows = [];
37
37
  // Make ourselves an observable so that mobx will do caching of .collapseIds so
38
38
  // that it'll be a stable identity for GridTable to useMemo against.
39
39
  (0, mobx_1.makeAutoObservable)(this, { rows: false }); // as any b/c rows is private, so the mapped type doesn't see it
40
40
  // Whenever our `visibleRows` change (i.e. via filtering) then we need to re-derive header and parent rows' selected state.
41
41
  (0, mobx_1.reaction)(() => [...this.visibleRows.values()].sort(), () => {
42
42
  const map = new Map();
43
- map.set("header", deriveParentSelected(this.rows.current.flatMap((row) => this.setNestedSelectedStates(row, map))));
43
+ map.set("header", deriveParentSelected(this.rows.flatMap((row) => this.setNestedSelectedStates(row, map))));
44
44
  // Merge the changes back into the selected rows state
45
45
  this.selectedRows.merge(map);
46
46
  }, { equals: mobx_1.comparer.shallow });
47
47
  }
48
+ loadPersistedCollapse(persistCollapse) {
49
+ this.persistCollapse = persistCollapse;
50
+ this.collapsedRows.replace(readLocalCollapseState(persistCollapse));
51
+ }
48
52
  setVisibleRows(rowIds) {
49
53
  // ObservableSet doesn't seem to do a `diff` inside `replace` before firing
50
54
  // observers/reactions that watch it, which can lead to render loops with the
@@ -79,7 +83,7 @@ class RowState {
79
83
  // Just mash the header + all rows + children as selected
80
84
  const map = new Map();
81
85
  map.set("header", "checked");
82
- (0, visitor_1.visit)(this.rows.current, (row) => this.visibleRows.has(row.id) && map.set(row.id, "checked"));
86
+ (0, visitor_1.visit)(this.rows, (row) => this.visibleRows.has(row.id) && map.set(row.id, "checked"));
83
87
  this.selectedRows.replace(map);
84
88
  }
85
89
  else {
@@ -91,7 +95,7 @@ class RowState {
91
95
  // This is the regular/non-header behavior to just add/remove the individual row id,
92
96
  // plus percolate the change down-to-child + up-to-parents.
93
97
  // Find the clicked on row
94
- const curr = findRow(this.rows.current, id);
98
+ const curr = findRow(this.rows, id);
95
99
  if (!curr) {
96
100
  return;
97
101
  }
@@ -105,7 +109,7 @@ class RowState {
105
109
  }
106
110
  }
107
111
  // And do the header + top-level "children" as a final one-off
108
- map.set("header", deriveParentSelected(this.getVisibleChildrenStates(this.rows.current, map)));
112
+ map.set("header", deriveParentSelected(this.getVisibleChildrenStates(this.rows, map)));
109
113
  this.selectedRows.merge(map);
110
114
  }
111
115
  }
@@ -131,7 +135,7 @@ class RowState {
131
135
  // Find all non-leaf rows so that toggling "all collapsed" -> "all not collapsed" opens
132
136
  // the parent rows of any level.
133
137
  const parentIds = new Set();
134
- const todo = [...this.rows.current];
138
+ const todo = [...this.rows];
135
139
  while (todo.length > 0) {
136
140
  const r = todo.pop();
137
141
  if (r.children) {
@@ -4,6 +4,8 @@ export type { GridRowLookup } from "./GridRowLookup";
4
4
  export { GridSortContext } from "./GridSortContext";
5
5
  export { ASC, DESC, GridTable, setDefaultStyle, setGridTableDefaults } from "./GridTable";
6
6
  export type { Direction, GridCellAlignment, GridCellContent, GridColumn, GridDataRow, GridRowStyles, GridSortConfig, GridStyle, GridTableDefaults, GridTableProps, GridTableXss, Kinded, RowStyle, setRunningInJest, } from "./GridTable";
7
+ export { useGridTableApi } from "./GridTableApi";
8
+ export type { GridTableApi } from "./GridTableApi";
7
9
  export { RowState, RowStateContext } from "./RowState";
8
10
  export * from "./SelectToggle";
9
11
  export { simpleDataRows, simpleHeader, simpleRows } from "./simpleHelpers";
@@ -10,7 +10,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
10
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.defaultStyle = exports.condensedStyle = exports.cardStyle = exports.beamTotalsFlexibleStyle = exports.beamTotalsFixedStyle = exports.beamNestedFlexibleStyle = exports.beamNestedFixedStyle = exports.beamFlexibleStyle = exports.beamFixedStyle = exports.SortHeader = exports.simpleRows = exports.simpleHeader = exports.simpleDataRows = exports.RowStateContext = exports.RowState = exports.setGridTableDefaults = exports.setDefaultStyle = exports.GridTable = exports.DESC = exports.ASC = exports.GridSortContext = void 0;
13
+ exports.defaultStyle = exports.condensedStyle = exports.cardStyle = exports.beamTotalsFlexibleStyle = exports.beamTotalsFixedStyle = exports.beamNestedFlexibleStyle = exports.beamNestedFixedStyle = exports.beamFlexibleStyle = exports.beamFixedStyle = exports.SortHeader = exports.simpleRows = exports.simpleHeader = exports.simpleDataRows = exports.RowStateContext = exports.RowState = exports.useGridTableApi = exports.setGridTableDefaults = exports.setDefaultStyle = exports.GridTable = exports.DESC = exports.ASC = exports.GridSortContext = void 0;
14
14
  __exportStar(require("./CollapseToggle"), exports);
15
15
  __exportStar(require("./columns"), exports);
16
16
  var GridSortContext_1 = require("./GridSortContext");
@@ -21,6 +21,8 @@ Object.defineProperty(exports, "DESC", { enumerable: true, get: function () { re
21
21
  Object.defineProperty(exports, "GridTable", { enumerable: true, get: function () { return GridTable_1.GridTable; } });
22
22
  Object.defineProperty(exports, "setDefaultStyle", { enumerable: true, get: function () { return GridTable_1.setDefaultStyle; } });
23
23
  Object.defineProperty(exports, "setGridTableDefaults", { enumerable: true, get: function () { return GridTable_1.setGridTableDefaults; } });
24
+ var GridTableApi_1 = require("./GridTableApi");
25
+ Object.defineProperty(exports, "useGridTableApi", { enumerable: true, get: function () { return GridTableApi_1.useGridTableApi; } });
24
26
  var RowState_1 = require("./RowState");
25
27
  Object.defineProperty(exports, "RowState", { enumerable: true, get: function () { return RowState_1.RowState; } });
26
28
  Object.defineProperty(exports, "RowStateContext", { enumerable: true, get: function () { return RowState_1.RowStateContext; } });
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.useComputed = void 0;
4
7
  const mobx_1 = require("mobx");
5
8
  const react_1 = require("react");
9
+ const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
6
10
  /** Evaluates a computed function `fn` to a regular value and triggers a re-render whenever it changes. */
7
11
  function useComputed(fn, deps) {
8
12
  // We always return the useRef value, and use this just to trigger re-renders
@@ -33,7 +37,7 @@ function useComputed(fn, deps) {
33
37
  // Only trigger a re-render if this is not the 1st autorun. Note
34
38
  // that if deps has changed, we're inherently in a re-render so also
35
39
  // don't need to trigger an additional re-render.
36
- if (oldHasRun && newValue !== oldValue) {
40
+ if (oldHasRun && !(0, fast_deep_equal_1.default)(newValue, oldValue)) {
37
41
  setTick((tick) => tick + 1);
38
42
  }
39
43
  });
@@ -25,15 +25,37 @@ function ListBox(props) {
25
25
  const isMultiSelect = state.selectionManager.selectionMode === "multiple";
26
26
  const firstItem = state.collection.at(0);
27
27
  const hasSections = firstItem && firstItem.type === "section";
28
- const onListHeightChange = (height) => {
28
+ // Create a reference for measuring the MultiSelect's selected list's height. Used for re-evaluating `popoverHeight`.
29
+ const selectedList = (0, react_1.useRef)(null);
30
+ const firstRender = (0, react_1.useRef)(true);
31
+ // Keep track of the virtuoso list height to properly update the ListBox's height.
32
+ // Using a ref, this itself should not trigger a rerender, only `popoverHeight` changes will trigger a rerender.
33
+ const virtuosoListHeight = (0, react_1.useRef)(0);
34
+ const onListHeightChange = (listHeight) => {
35
+ var _a;
36
+ virtuosoListHeight.current = listHeight;
37
+ // The "listHeight" is only the list of options.
38
+ // For multiple selects we need to also account for the height of the list of currently selected elements when re-evaluating.
39
+ // Using `offsetHeight` to account for borders
40
+ const height = (((_a = selectedList.current) === null || _a === void 0 ? void 0 : _a.offsetHeight) || 0) + listHeight;
29
41
  // Using Math.min to choose between the smaller height, either the total height of the List (`height` arg), or the maximum height defined by the space allotted on screen or our hard coded max.
30
42
  // If there are ListBoxSections, then we assume it is the persistent section with a single item and account for that height.
31
43
  setPopoverHeight(Math.min(popoverMaxHeight, hasSections ? height + constants_1.persistentItemHeight + constants_1.sectionSeparatorHeight : height));
32
44
  };
45
+ (0, react_1.useEffect)(() => {
46
+ // Reevaluate the list height when introducing or removing the MultiSelect's options list.
47
+ // Do not call `onListHeightChange` on the first render. Only when the selectedKeys size has actually changed between empty and not empty.
48
+ if (!firstRender.current &&
49
+ isMultiSelect &&
50
+ (state.selectionManager.selectedKeys.size === 0 || state.selectionManager.selectedKeys.size === 1)) {
51
+ onListHeightChange(virtuosoListHeight.current);
52
+ }
53
+ firstRender.current = false;
54
+ }, [state.selectionManager.selectedKeys.size]);
33
55
  return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
34
- ...Css_1.Css.bgWhite.br4.w100.bshBasic.if(contrast).bgGray700.$,
56
+ ...Css_1.Css.bgWhite.br4.w100.bshBasic.hPx(popoverHeight).df.fdc.if(contrast).bgGray700.$,
35
57
  "&:hover": Css_1.Css.bshHover.$,
36
- }, ref: listBoxRef }, listBoxProps, { children: [isMultiSelect && state.selectionManager.selectedKeys.size > 0 && ((0, jsx_runtime_1.jsx)("ul", Object.assign({ css: Css_1.Css.listReset.pt2.pl2.pb1.pr1.df.bb.bGray200.add("flexWrap", "wrap").$ }, { children: selectedOptions.map((o) => ((0, jsx_runtime_1.jsx)(ListBoxToggleChip_1.ListBoxToggleChip, { state: state, option: o, getOptionValue: getOptionValue, getOptionLabel: getOptionLabel, disabled: state.disabledKeys.has(getOptionValue(o)) }, getOptionValue(o)))) }), void 0)), (0, jsx_runtime_1.jsx)("ul", Object.assign({ css: Css_1.Css.listReset.hPx(popoverHeight).$ }, { children: hasSections ? ([...state.collection].map((section) => ((0, jsx_runtime_1.jsx)(ListBoxSection_1.ListBoxSection, { section: section, state: state, contrast: contrast, onListHeightChange: onListHeightChange, popoverHeight: popoverHeight,
58
+ }, ref: listBoxRef }, listBoxProps, { children: [isMultiSelect && state.selectionManager.selectedKeys.size > 0 && ((0, jsx_runtime_1.jsx)("ul", Object.assign({ css: Css_1.Css.listReset.pt2.pl2.pb1.pr1.df.bb.bGray200.add("flexWrap", "wrap").$, ref: selectedList }, { children: selectedOptions.map((o) => ((0, jsx_runtime_1.jsx)(ListBoxToggleChip_1.ListBoxToggleChip, { state: state, option: o, getOptionValue: getOptionValue, getOptionLabel: getOptionLabel, disabled: state.disabledKeys.has(getOptionValue(o)) }, getOptionValue(o)))) }), void 0)), (0, jsx_runtime_1.jsx)("ul", Object.assign({ css: Css_1.Css.listReset.fg1.$ }, { children: hasSections ? ([...state.collection].map((section) => ((0, jsx_runtime_1.jsx)(ListBoxSection_1.ListBoxSection, { section: section, state: state, contrast: contrast, onListHeightChange: onListHeightChange, popoverHeight: popoverHeight,
37
59
  // Only scroll on focus if using VirtualFocus (used for ComboBoxState (SelectField), but not SelectState (ChipSelectField))
38
60
  scrollOnFocus: props.shouldUseVirtualFocus }, section.key)))) : ((0, jsx_runtime_1.jsx)(VirtualizedOptions_1.VirtualizedOptions, { state: state, items: [...state.collection], onListHeightChange: onListHeightChange, contrast: contrast,
39
61
  // Only scroll on focus if using VirtualFocus (used for ComboBoxState (SelectField), but not SelectState (ChipSelectField))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.118.2",
3
+ "version": "2.119.0",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -39,6 +39,7 @@
39
39
  "change-case": "^4.1.2",
40
40
  "date-fns": "^2.21.3",
41
41
  "dompurify": "^2.3.0",
42
+ "fast-deep-equal": "^3.1.3",
42
43
  "framer-motion": "^4.1.11",
43
44
  "memoize-one": "^5.2.1",
44
45
  "react-aria": "^3.10.0",
@@ -50,8 +51,8 @@
50
51
  "react-virtuoso": "^2.4.0",
51
52
  "tributejs": "^5.1.3",
52
53
  "trix": "^1.3.1",
53
- "use-query-params": "^1.2.2",
54
- "use-debounce": "^7.0.1"
54
+ "use-debounce": "^7.0.1",
55
+ "use-query-params": "^1.2.2"
55
56
  },
56
57
  "peerDependencies": {
57
58
  "@emotion/react": ">=11",