@homebound/beam 2.118.4 → 2.120.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,31 @@ 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
+ // Keeps track of the 'active' row, formatted `${row.kind}_${row.id}`
38
+ this.activeRowId = undefined;
37
39
  // Make ourselves an observable so that mobx will do caching of .collapseIds so
38
40
  // that it'll be a stable identity for GridTable to useMemo against.
39
41
  (0, mobx_1.makeAutoObservable)(this, { rows: false }); // as any b/c rows is private, so the mapped type doesn't see it
40
42
  // Whenever our `visibleRows` change (i.e. via filtering) then we need to re-derive header and parent rows' selected state.
41
43
  (0, mobx_1.reaction)(() => [...this.visibleRows.values()].sort(), () => {
42
44
  const map = new Map();
43
- map.set("header", deriveParentSelected(this.rows.current.flatMap((row) => this.setNestedSelectedStates(row, map))));
45
+ map.set("header", deriveParentSelected(this.rows.flatMap((row) => this.setNestedSelectedStates(row, map))));
44
46
  // Merge the changes back into the selected rows state
45
47
  this.selectedRows.merge(map);
46
48
  }, { equals: mobx_1.comparer.shallow });
47
49
  }
50
+ loadPersistedCollapse(persistCollapse) {
51
+ this.persistCollapse = persistCollapse;
52
+ this.collapsedRows.replace(readLocalCollapseState(persistCollapse));
53
+ }
48
54
  setVisibleRows(rowIds) {
49
55
  // ObservableSet doesn't seem to do a `diff` inside `replace` before firing
50
56
  // observers/reactions that watch it, which can lead to render loops with the
@@ -79,7 +85,7 @@ class RowState {
79
85
  // Just mash the header + all rows + children as selected
80
86
  const map = new Map();
81
87
  map.set("header", "checked");
82
- (0, visitor_1.visit)(this.rows.current, (row) => this.visibleRows.has(row.id) && map.set(row.id, "checked"));
88
+ (0, visitor_1.visit)(this.rows, (row) => this.visibleRows.has(row.id) && map.set(row.id, "checked"));
83
89
  this.selectedRows.replace(map);
84
90
  }
85
91
  else {
@@ -91,7 +97,7 @@ class RowState {
91
97
  // This is the regular/non-header behavior to just add/remove the individual row id,
92
98
  // plus percolate the change down-to-child + up-to-parents.
93
99
  // Find the clicked on row
94
- const curr = findRow(this.rows.current, id);
100
+ const curr = findRow(this.rows, id);
95
101
  if (!curr) {
96
102
  return;
97
103
  }
@@ -105,7 +111,7 @@ class RowState {
105
111
  }
106
112
  }
107
113
  // And do the header + top-level "children" as a final one-off
108
- map.set("header", deriveParentSelected(this.getVisibleChildrenStates(this.rows.current, map)));
114
+ map.set("header", deriveParentSelected(this.getVisibleChildrenStates(this.rows, map)));
109
115
  this.selectedRows.merge(map);
110
116
  }
111
117
  }
@@ -131,7 +137,7 @@ class RowState {
131
137
  // Find all non-leaf rows so that toggling "all collapsed" -> "all not collapsed" opens
132
138
  // the parent rows of any level.
133
139
  const parentIds = new Set();
134
- const todo = [...this.rows.current];
140
+ const todo = [...this.rows];
135
141
  while (todo.length > 0) {
136
142
  const r = todo.pop();
137
143
  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; } });
@@ -10,10 +10,12 @@ export interface DateFieldProps extends Pick<TextFieldBaseProps<{}>, "borderless
10
10
  onBlur?: () => void;
11
11
  /** Called when the component is in focus. */
12
12
  onFocus?: () => void;
13
+ /** Whether the field is disabled. If a ReactNode, it's treated as a "disabled reason" that's shown in a tooltip. */
13
14
  disabled?: boolean | ReactNode;
14
15
  errorMsg?: string;
15
16
  required?: boolean;
16
- readOnly?: boolean;
17
+ /** Whether the field is readOnly. If a ReactNode, it's treated as a "readOnly reason" that's shown in a tooltip. */
18
+ readOnly?: boolean | ReactNode;
17
19
  helperText?: string | ReactNode;
18
20
  /** Renders the label inside the input field, i.e. for filters. */
19
21
  inlineLabel?: boolean;
@@ -15,7 +15,7 @@ const TextFieldBase_1 = require("./TextFieldBase");
15
15
  const utils_1 = require("../utils");
16
16
  const defaultTestId_1 = require("../utils/defaultTestId");
17
17
  function DateField(props) {
18
- const { label, disabled, required, value, onChange, onFocus, onBlur, errorMsg, helperText, inlineLabel = false, readOnly = false, format = "short", iconLeft = false, disabledDays, onEnter, defaultOpen, ...others } = props;
18
+ const { label, disabled, required, value, onChange, onFocus, onBlur, errorMsg, helperText, inlineLabel = false, readOnly, format = "short", iconLeft = false, disabledDays, onEnter, defaultOpen, ...others } = props;
19
19
  const inputRef = (0, react_1.useRef)(null);
20
20
  const inputWrapRef = (0, react_1.useRef)(null);
21
21
  const buttonRef = (0, react_1.useRef)(null);
@@ -26,6 +26,7 @@ function DateField(props) {
26
26
  const [inputValue, setInputValue] = (0, react_1.useState)(value ? formatDate(value, dateFormat) : "");
27
27
  const tid = (0, utils_1.useTestIds)(props, (0, defaultTestId_1.defaultTestId)(label));
28
28
  const isDisabled = !!disabled;
29
+ const isReadOnly = !!readOnly;
29
30
  (0, react_1.useEffect)(() => {
30
31
  // Avoid updating any WIP values.
31
32
  if (!isFocused) {
@@ -36,7 +37,7 @@ function DateField(props) {
36
37
  ...others,
37
38
  label,
38
39
  isDisabled,
39
- isReadOnly: readOnly,
40
+ isReadOnly,
40
41
  "aria-haspopup": "dialog",
41
42
  value: inputValue,
42
43
  };
@@ -87,7 +88,7 @@ function DateField(props) {
87
88
  const { triggerProps, overlayProps } = (0, react_aria_1.useOverlayTrigger)({ type: "dialog" }, state, buttonRef);
88
89
  const { buttonProps } = (0, react_aria_1.useButton)({
89
90
  ...triggerProps,
90
- isDisabled: isDisabled || readOnly,
91
+ isDisabled: isDisabled || isReadOnly,
91
92
  // When pressed or focused then move focus the input, which will select the text and trigger the DatePicker to open
92
93
  onPress: () => { var _a; return (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); },
93
94
  onFocus: () => { var _a; return (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); },
@@ -110,7 +111,7 @@ function DateField(props) {
110
111
  // But would also need to allow for the input to be `fullWidth`, which is basically also what we're accomplishing here... so maybe fine?
111
112
  const inputSize = format === "short" ? 8 : format === "medium" ? 10 : undefined;
112
113
  const calendarButton = ((0, jsx_runtime_1.jsx)("button", Object.assign({ ref: buttonRef }, buttonProps, { disabled: isDisabled, css: Css_1.Css.if(isDisabled).cursorNotAllowed.$, tabIndex: -1 }, tid.calendarButton, { children: (0, jsx_runtime_1.jsx)(components_1.Icon, { icon: "calendar", color: Css_1.Palette.Gray700 }, void 0) }), void 0));
113
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, textFieldProps, { readOnly: readOnly, errorMsg: errorMsg, helperText: helperText, required: required, labelProps: labelProps, inputProps: { ...triggerProps, ...inputProps, size: inputSize }, inputRef: inputRef, inputWrapRef: inputWrapRef, inlineLabel: inlineLabel, onChange: (v) => {
114
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, textFieldProps, { errorMsg: errorMsg, helperText: helperText, required: required, labelProps: labelProps, inputProps: { ...triggerProps, ...inputProps, size: inputSize }, inputRef: inputRef, inputWrapRef: inputWrapRef, inlineLabel: inlineLabel, onChange: (v) => {
114
115
  // hide the calendar if the user is manually entering the date
115
116
  state.close();
116
117
  if (v) {
@@ -121,7 +122,7 @@ function DateField(props) {
121
122
  onChange(parsed);
122
123
  }
123
124
  }
124
- }, endAdornment: !iconLeft && calendarButton, startAdornment: iconLeft && calendarButton, tooltip: isDisabled && typeof disabled !== "boolean" ? disabled : undefined }, others), void 0), state.isOpen && ((0, jsx_runtime_1.jsx)(internal_1.Popover, Object.assign({ triggerRef: inputWrapRef, popoverRef: overlayRef, positionProps: positionProps, onClose: state.close, isOpen: state.isOpen }, { children: (0, jsx_runtime_1.jsx)(DatePickerOverlay_1.DatePickerOverlay, Object.assign({ value: value, onSelect: (d) => {
125
+ }, endAdornment: !iconLeft && calendarButton, startAdornment: iconLeft && calendarButton, tooltip: (0, components_1.resolveTooltip)(disabled, undefined, readOnly) }, others), void 0), state.isOpen && ((0, jsx_runtime_1.jsx)(internal_1.Popover, Object.assign({ triggerRef: inputWrapRef, popoverRef: overlayRef, positionProps: positionProps, onClose: state.close, isOpen: state.isOpen }, { children: (0, jsx_runtime_1.jsx)(DatePickerOverlay_1.DatePickerOverlay, Object.assign({ value: value, onSelect: (d) => {
125
126
  setInputValue(formatDate(d, dateFormat));
126
127
  onChange(d);
127
128
  }, state: state, disabledDays: disabledDays, overlayProps: overlayProps }, tid.datePicker), void 0) }), void 0))] }, void 0));
@@ -14,6 +14,6 @@ function DateField(props) {
14
14
  const { value } = e.target;
15
15
  setValue(value);
16
16
  onChange((0, date_fns_1.parse)(value, "MM/dd/yy", new Date()));
17
- }, onBlur: () => (0, utils_1.maybeCall)(onBlur), onFocus: () => (0, utils_1.maybeCall)(onFocus), disabled: !!props.disabled, readOnly: props.readOnly, "data-disabled-days": JSON.stringify(props.disabledDays) }), void 0));
17
+ }, onBlur: () => (0, utils_1.maybeCall)(onBlur), onFocus: () => (0, utils_1.maybeCall)(onFocus), disabled: !!props.disabled, readOnly: !!props.readOnly, "data-disabled-days": JSON.stringify(props.disabledDays) }), void 0));
18
18
  }
19
19
  exports.DateField = DateField;
@@ -10,13 +10,14 @@ export interface NumberFieldProps {
10
10
  value: number | undefined;
11
11
  onChange: (value: number | undefined) => void;
12
12
  compact?: boolean;
13
- disabled?: boolean;
13
+ /** Whether the field is disabled. If a ReactNode, it's treated as a "disabled reason" that's shown in a tooltip. */
14
+ disabled?: boolean | ReactNode;
14
15
  required?: boolean;
15
16
  errorMsg?: string;
16
17
  helperText?: string | ReactNode;
17
18
  onBlur?: () => void;
18
19
  onFocus?: () => void;
19
- readOnly?: boolean;
20
+ readOnly?: boolean | ReactNode;
20
21
  /** Styles overrides */
21
22
  xss?: Xss<"textAlign" | "justifyContent">;
22
23
  displayDirection?: boolean;
@@ -6,6 +6,7 @@ const number_1 = require("@internationalized/number");
6
6
  const react_1 = require("react");
7
7
  const react_aria_1 = require("react-aria");
8
8
  const react_stately_1 = require("react-stately");
9
+ const components_1 = require("../components");
9
10
  const PresentationContext_1 = require("../components/PresentationContext");
10
11
  const Css_1 = require("../Css");
11
12
  const utils_1 = require("../utils");
@@ -14,7 +15,9 @@ function NumberField(props) {
14
15
  // Determine default alignment based on presentation context
15
16
  const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
16
17
  const alignment = (fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.numberAlignment) === "right" ? Css_1.Css.tr.jcfe.$ : Css_1.Css.tl.jcfs.$;
17
- const { disabled = false, required, readOnly = false, type, label, onBlur, onFocus, errorMsg, helperText, value, onChange, xss, displayDirection = false, numFractionDigits, truncate = false, onEnter, ...otherProps } = props;
18
+ const { disabled, required, readOnly, type, label, onBlur, onFocus, errorMsg, helperText, value, onChange, xss, displayDirection = false, numFractionDigits, truncate = false, onEnter, ...otherProps } = props;
19
+ const isDisabled = !!disabled;
20
+ const isReadOnly = !!readOnly;
18
21
  const factor = type === "percent" || type === "cents" ? 100 : type === "basisPoints" ? 10000 : 1;
19
22
  const signDisplay = displayDirection ? "exceptZero" : "auto";
20
23
  const fractionFormatOptions = { [truncate ? "maximumFractionDigits" : "minimumFractionDigits"]: numFractionDigits };
@@ -58,8 +61,8 @@ function NumberField(props) {
58
61
  },
59
62
  validationState: errorMsg !== undefined ? "invalid" : "valid",
60
63
  label: label,
61
- isDisabled: disabled,
62
- isReadOnly: readOnly,
64
+ isDisabled,
65
+ isReadOnly,
63
66
  formatOptions,
64
67
  };
65
68
  const state = (0, react_stately_1.useNumberFieldState)(useProps);
@@ -75,7 +78,7 @@ function NumberField(props) {
75
78
  onChange: (rawInputValue) => {
76
79
  const parsedValue = numberParser.parse(rawInputValue || "");
77
80
  onChange(formatValue(parsedValue, factor, numFractionDigits));
78
- }, inputRef: inputRef, onBlur: onBlur, onFocus: onFocus, errorMsg: errorMsg, helperText: helperText, readOnly: readOnly }, otherProps), void 0));
81
+ }, inputRef: inputRef, onBlur: onBlur, onFocus: onFocus, errorMsg: errorMsg, helperText: helperText, tooltip: (0, components_1.resolveTooltip)(disabled, undefined, readOnly) }, otherProps), void 0));
79
82
  }
80
83
  exports.NumberField = NumberField;
81
84
  function formatValue(value, factor, numFractionDigits) {
@@ -5,12 +5,15 @@ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
5
  const utils_1 = require("@react-aria/utils");
6
6
  const react_1 = require("react");
7
7
  const react_aria_1 = require("react-aria");
8
+ const components_1 = require("../components");
8
9
  const TextFieldBase_1 = require("./TextFieldBase");
9
10
  const utils_2 = require("../utils");
10
11
  /** Returns a <textarea /> element that auto-adjusts height based on the field's value */
11
12
  function TextAreaField(props) {
12
13
  const { value = "", disabled = false, readOnly = false, onBlur, onFocus, preventNewLines, onEnter, ...otherProps } = props;
13
- const textFieldProps = { ...otherProps, value, isDisabled: disabled, isReadOnly: readOnly };
14
+ const isDisabled = !!disabled;
15
+ const isReadOnly = !!readOnly;
16
+ const textFieldProps = { ...otherProps, value, isDisabled, isReadOnly };
14
17
  const inputRef = (0, react_1.useRef)(null);
15
18
  const inputWrapRef = (0, react_1.useRef)(null);
16
19
  // not in stately because this is so we know when to re-measure, which is a spectrum design
@@ -60,6 +63,6 @@ function TextAreaField(props) {
60
63
  }
61
64
  : {}),
62
65
  }, inputRef);
63
- return ((0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, (0, react_aria_1.mergeProps)(otherProps, { onBlur, onFocus }), { multiline: true, labelProps: labelProps, inputProps: inputProps, inputRef: inputRef, readOnly: readOnly, inputWrapRef: inputWrapRef, textAreaMinHeight: preventNewLines ? 0 : undefined }), void 0));
66
+ return ((0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, (0, react_aria_1.mergeProps)(otherProps, { onBlur, onFocus }), { multiline: true, labelProps: labelProps, inputProps: inputProps, inputRef: inputRef, inputWrapRef: inputWrapRef, textAreaMinHeight: preventNewLines ? 0 : undefined, tooltip: (0, components_1.resolveTooltip)(disabled, undefined, readOnly) }), void 0));
64
67
  }
65
68
  exports.TextAreaField = TextAreaField;
@@ -4,14 +4,17 @@ exports.TextField = void 0;
4
4
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const react_aria_1 = require("react-aria");
7
+ const components_1 = require("../components");
7
8
  const TextFieldBase_1 = require("./TextFieldBase");
8
9
  const utils_1 = require("../utils");
9
10
  function TextField(props) {
10
- const { disabled: isDisabled = false, readOnly = false, required, errorMsg, value = "", onBlur, onFocus, api, onEnter, ...otherProps } = props;
11
+ const { disabled = false, readOnly = false, required, errorMsg, value = "", onBlur, onFocus, api, onEnter, ...otherProps } = props;
12
+ const isDisabled = !!disabled;
13
+ const isReadOnly = !!readOnly;
11
14
  const textFieldProps = {
12
15
  ...otherProps,
13
16
  isDisabled,
14
- isReadOnly: readOnly,
17
+ isReadOnly,
15
18
  isRequired: required,
16
19
  validationState: errorMsg ? "invalid" : "valid",
17
20
  value,
@@ -33,6 +36,6 @@ function TextField(props) {
33
36
  focus: () => inputRef.current && inputRef.current.focus(),
34
37
  };
35
38
  }
36
- return ((0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, (0, react_aria_1.mergeProps)(textFieldProps, { onBlur, onFocus }), { readOnly: readOnly, errorMsg: errorMsg, required: required, labelProps: labelProps, inputProps: inputProps, inputRef: inputRef }), void 0));
39
+ return ((0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, (0, react_aria_1.mergeProps)(textFieldProps, { onBlur, onFocus }), { errorMsg: errorMsg, required: required, labelProps: labelProps, inputProps: inputProps, inputRef: inputRef, tooltip: (0, components_1.resolveTooltip)(disabled, undefined, readOnly) }), void 0));
37
40
  }
38
41
  exports.TextField = TextField;
@@ -2,7 +2,7 @@ import type { NumberFieldAria } from "@react-aria/numberfield";
2
2
  import { InputHTMLAttributes, LabelHTMLAttributes, MutableRefObject, ReactNode, TextareaHTMLAttributes } from "react";
3
3
  import { Only } from "../Css";
4
4
  import { BeamTextFieldProps, TextFieldXss } from "../interfaces";
5
- export interface TextFieldBaseProps<X> extends Pick<BeamTextFieldProps<X>, "label" | "required" | "readOnly" | "errorMsg" | "onBlur" | "onFocus" | "helperText" | "hideLabel" | "placeholder" | "compact" | "borderless" | "visuallyDisabled" | "xss">, Partial<Pick<BeamTextFieldProps<X>, "onChange">> {
5
+ export interface TextFieldBaseProps<X> extends Pick<BeamTextFieldProps<X>, "label" | "required" | "errorMsg" | "onBlur" | "onFocus" | "helperText" | "hideLabel" | "placeholder" | "compact" | "borderless" | "visuallyDisabled" | "xss">, Partial<Pick<BeamTextFieldProps<X>, "onChange">> {
6
6
  labelProps?: LabelHTMLAttributes<HTMLLabelElement>;
7
7
  inputProps: InputHTMLAttributes<HTMLInputElement> | TextareaHTMLAttributes<HTMLTextAreaElement>;
8
8
  inputRef?: MutableRefObject<HTMLInputElement | HTMLTextAreaElement | null>;
@@ -17,7 +17,7 @@ const useTestIds_1 = require("../utils/useTestIds");
17
17
  function TextFieldBase(props) {
18
18
  var _a, _b, _c, _d, _e, _f;
19
19
  const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
20
- const { label, required, labelProps, hideLabel = (_a = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.hideLabel) !== null && _a !== void 0 ? _a : false, inputProps, inputRef, inputWrapRef, groupProps, compact = (_b = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.compact) !== null && _b !== void 0 ? _b : false, errorMsg, helperText, multiline = false, readOnly, onChange, onBlur, onFocus, xss, endAdornment, startAdornment, inlineLabel, contrast = false, borderless = (_c = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.borderless) !== null && _c !== void 0 ? _c : false, textAreaMinHeight = 96, clearable = false, tooltip, visuallyDisabled = (_d = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.visuallyDisabled) !== null && _d !== void 0 ? _d : true, } = props;
20
+ const { label, required, labelProps, hideLabel = (_a = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.hideLabel) !== null && _a !== void 0 ? _a : false, inputProps, inputRef, inputWrapRef, groupProps, compact = (_b = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.compact) !== null && _b !== void 0 ? _b : false, errorMsg, helperText, multiline = false, onChange, onBlur, onFocus, xss, endAdornment, startAdornment, inlineLabel, contrast = false, borderless = (_c = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.borderless) !== null && _c !== void 0 ? _c : false, textAreaMinHeight = 96, clearable = false, tooltip, visuallyDisabled = (_d = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.visuallyDisabled) !== null && _d !== void 0 ? _d : true, } = props;
21
21
  const typeScale = (_e = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.typeScale) !== null && _e !== void 0 ? _e : "sm";
22
22
  const internalProps = props.internalProps || {};
23
23
  const { compound = false } = internalProps;
@@ -80,7 +80,7 @@ function TextFieldBase(props) {
80
80
  (0, jsx_runtime_1.jsx)(Label_1.Label, Object.assign({ labelProps: labelProps, hidden: hideLabel || compound, label: label, suffix: labelSuffix, contrast: contrast }, tid.label), void 0)), (0, components_1.maybeTooltip)({
81
81
  title: tooltip,
82
82
  placement: "top",
83
- children: readOnly ? ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
83
+ children: inputProps.readOnly ? ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
84
84
  // Use input wrapper to get common styles, but then we need to override some
85
85
  ...fieldStyles.inputWrapperReadOnly,
86
86
  ...(multiline ? Css_1.Css.fdc.aifs.childGap2.$ : Css_1.Css.truncate.$),
@@ -90,14 +90,14 @@ function TextFieldBase(props) {
90
90
  : inputProps.value] }), void 0)) : ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
91
91
  ...fieldStyles.inputWrapper,
92
92
  ...(inputProps.disabled ? fieldStyles.disabled : {}),
93
- ...(isFocused && !readOnly ? fieldStyles.focus : {}),
94
- ...(isHovered && !inputProps.disabled && !readOnly && !isFocused ? fieldStyles.hover : {}),
93
+ ...(isFocused && !inputProps.readOnly ? fieldStyles.focus : {}),
94
+ ...(isHovered && !inputProps.disabled && !inputProps.readOnly && !isFocused ? fieldStyles.hover : {}),
95
95
  ...(errorMsg ? fieldStyles.error : {}),
96
96
  ...Css_1.Css.if(multiline).aifs.px0.mhPx(textAreaMinHeight).$,
97
97
  } }, hoverProps, { ref: inputWrapRef }, { children: [!multiline && inlineLabel && label && !hideLabel && ((0, jsx_runtime_1.jsx)(Label_1.InlineLabel, Object.assign({ labelProps: labelProps, label: label }, tid.label), void 0)), !multiline && startAdornment && (0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.df.aic.fs0.br4.pr1.$ }, { children: startAdornment }), void 0), (0, jsx_runtime_1.jsx)(ElementType, Object.assign({}, (0, react_aria_1.mergeProps)(inputProps, { onBlur, onFocus: onFocusChained, onChange: onDomChange }, { "aria-invalid": Boolean(errorMsg), ...(hideLabel ? { "aria-label": label } : {}) }), (errorMsg ? { "aria-errormessage": errorMessageId } : {}), { ref: fieldRef, rows: multiline ? 1 : undefined, css: {
98
98
  ...fieldStyles.input,
99
99
  ...(inputProps.disabled ? fieldStyles.disabled : {}),
100
- ...(isHovered && !inputProps.disabled && !readOnly && !isFocused ? fieldStyles.hover : {}),
100
+ ...(isHovered && !inputProps.disabled && !inputProps.readOnly && !isFocused ? fieldStyles.hover : {}),
101
101
  ...(multiline ? Css_1.Css.h100.p1.add("resize", "none").if(borderless).pPx(4).$ : Css_1.Css.truncate.$),
102
102
  ...xss,
103
103
  } }, tid), void 0), isFocused && clearable && onChange && inputProps.value && ((0, jsx_runtime_1.jsx)(components_1.IconButton, { icon: "xCircle", color: Css_1.Palette.Gray700, onClick: () => {
@@ -15,7 +15,7 @@ function SelectFieldInput(props) {
15
15
  const showNumSelection = isMultiSelect && state.selectionManager.selectedKeys.size > 1;
16
16
  // For MultiSelect only show the `fieldDecoration` when input is not in focus.
17
17
  const showFieldDecoration = (!isMultiSelect || (isMultiSelect && !isFocused)) && fieldDecoration && selectedOptions.length === 1;
18
- return ((0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, otherProps, { readOnly: inputProps.readOnly, inlineLabel: inlineLabel, errorMsg: errorMsg, contrast: contrast, xss: !inlineLabel && !inputProps.readOnly ? Css_1.Css.fw5.$ : {}, startAdornment: (showNumSelection && ((0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.wPx(16).hPx(16).fs0.br100.bgLightBlue700.white.tinyEm.df.aic.jcc.$ }, { children: state.selectionManager.selectedKeys.size }), void 0))) ||
18
+ return ((0, jsx_runtime_1.jsx)(TextFieldBase_1.TextFieldBase, Object.assign({}, otherProps, { inlineLabel: inlineLabel, errorMsg: errorMsg, contrast: contrast, xss: !inlineLabel && !inputProps.readOnly ? Css_1.Css.fw5.$ : {}, startAdornment: (showNumSelection && ((0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.wPx(16).hPx(16).fs0.br100.bgLightBlue700.white.tinyEm.df.aic.jcc.$ }, { children: state.selectionManager.selectedKeys.size }), void 0))) ||
19
19
  (showFieldDecoration && fieldDecoration(selectedOptions[0])), endAdornment: !inputProps.readOnly && ((0, jsx_runtime_1.jsx)("button", Object.assign({}, buttonProps, { disabled: inputProps.disabled, ref: buttonRef, css: {
20
20
  ...Css_1.Css.br4.outline0.gray700.if(contrast).gray400.$,
21
21
  ...(inputProps.disabled ? Css_1.Css.cursorNotAllowed.gray400.if(contrast).gray600.$ : {}),
@@ -24,8 +24,8 @@ export interface BeamButtonProps {
24
24
  }
25
25
  export declare type TextFieldXss = Xss<"textAlign" | "justifyContent" | "fontWeight" | "fontSize" | "lineHeight">;
26
26
  export interface BeamTextFieldProps<X> extends BeamFocusableProps, PresentationFieldProps {
27
- /** Whether the interactive element is disabled. */
28
- disabled?: boolean;
27
+ /** Whether the field is disabled. If a ReactNode, it's treated as a "disabled reason" that's shown in a tooltip. */
28
+ disabled?: boolean | ReactNode;
29
29
  errorMsg?: string;
30
30
  helperText?: string | ReactNode;
31
31
  /** Input label */
@@ -39,7 +39,8 @@ export interface BeamTextFieldProps<X> extends BeamFocusableProps, PresentationF
39
39
  onBlur?: Callback;
40
40
  onFocus?: Callback;
41
41
  onEnter?: Callback;
42
- readOnly?: boolean;
42
+ /** Whether the field is readOnly. If a ReactNode, it's treated as a "readOnly reason" that's shown in a tooltip. */
43
+ readOnly?: boolean | ReactNode;
43
44
  placeholder?: string;
44
45
  /** Styles overrides */
45
46
  xss?: X;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.118.4",
3
+ "version": "2.120.0",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",