@homebound/beam 2.91.7 → 2.91.8

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,5 +1,5 @@
1
1
  import { DOMProps } from "@react-types/shared";
2
- import { AriaAttributes } from "react";
2
+ import React, { AriaAttributes } from "react";
3
3
  import { Margin, Palette, Xss } from "../Css";
4
4
  export interface IconProps extends AriaAttributes, DOMProps {
5
5
  /** The name of an icon */
@@ -11,7 +11,7 @@ export interface IconProps extends AriaAttributes, DOMProps {
11
11
  /** Styles overrides */
12
12
  xss?: Xss<Margin>;
13
13
  }
14
- export declare function Icon(props: IconProps): import("@emotion/react/jsx-runtime").JSX.Element;
14
+ export declare const Icon: React.MemoExoticComponent<(props: IconProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
15
15
  /**
16
16
  * Map of icons paths mapped to their respective name.
17
17
  *
@@ -1,14 +1,17 @@
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.Icons = exports.Icon = void 0;
4
7
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
8
+ const react_1 = __importDefault(require("react"));
5
9
  const Css_1 = require("../Css");
6
- function Icon(props) {
10
+ exports.Icon = react_1.default.memo((props) => {
7
11
  const { icon, inc = 3, color = "currentColor", xss, ...other } = props;
8
12
  const size = (0, Css_1.increment)(inc);
9
13
  return ((0, jsx_runtime_1.jsx)("svg", Object.assign({ "aria-hidden": true, width: size, height: size, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", css: { path: Css_1.Css.fill(color).$, ...xss }, "data-icon": icon }, other, { children: exports.Icons[icon] }), void 0));
10
- }
11
- exports.Icon = Icon;
14
+ });
12
15
  /**
13
16
  * Map of icons paths mapped to their respective name.
14
17
  *
@@ -1,4 +1,4 @@
1
- import { LabelHTMLAttributes } from "react";
1
+ import React, { LabelHTMLAttributes } from "react";
2
2
  interface LabelProps {
3
3
  labelProps?: LabelHTMLAttributes<HTMLLabelElement>;
4
4
  label: string;
@@ -7,7 +7,7 @@ interface LabelProps {
7
7
  contrast?: boolean;
8
8
  }
9
9
  /** An internal helper component for rendering form labels. */
10
- export declare function Label(props: LabelProps): import("@emotion/react/jsx-runtime").JSX.Element;
10
+ export declare const Label: React.MemoExoticComponent<(props: LabelProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
11
11
  /** Used for showing labels within text fields. */
12
12
  export declare function InlineLabel({ labelProps, label, contrast, ...others }: LabelProps): import("@emotion/react/jsx-runtime").JSX.Element;
13
13
  export {};
@@ -1,16 +1,19 @@
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.InlineLabel = exports.Label = void 0;
4
7
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
8
+ const react_1 = __importDefault(require("react"));
5
9
  const react_aria_1 = require("react-aria");
6
10
  const Css_1 = require("../Css");
7
11
  /** An internal helper component for rendering form labels. */
8
- function Label(props) {
12
+ exports.Label = react_1.default.memo((props) => {
9
13
  const { labelProps, label, hidden, suffix, contrast = false, ...others } = props;
10
14
  const labelEl = ((0, jsx_runtime_1.jsxs)("label", Object.assign({}, labelProps, others, { css: Css_1.Css.dib.sm.gray700.mbPx(4).if(contrast).white.$ }, { children: [label, suffix && ` ${suffix}`] }), void 0));
11
15
  return hidden ? (0, jsx_runtime_1.jsx)(react_aria_1.VisuallyHidden, { children: labelEl }, void 0) : labelEl;
12
- }
13
- exports.Label = Label;
16
+ });
14
17
  /** Used for showing labels within text fields. */
15
18
  function InlineLabel({ labelProps, label, contrast, ...others }) {
16
19
  return ((0, jsx_runtime_1.jsxs)("label", Object.assign({}, labelProps, others, { css: Css_1.Css.smEm.nowrap.gray900.prPx(4).add("color", "currentColor").$ }, { children: [label, ":"] }), void 0));
@@ -13,19 +13,22 @@ const PresentationContext_1 = require("../components/PresentationContext");
13
13
  const Css_1 = require("../Css");
14
14
  const ChipTextField_1 = require("./ChipTextField");
15
15
  const ListBox_1 = require("./internal/ListBox");
16
+ const ListBoxChip_1 = require("./internal/ListBoxChip");
16
17
  const Value_1 = require("./Value");
17
18
  const utils_1 = require("../utils");
19
+ const options_1 = require("../utils/options");
18
20
  function ChipSelectField(props) {
19
21
  var _a, _b;
22
+ const firstRender = (0, react_1.useRef)(true);
20
23
  const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
21
- const { label, value, disabled = false, placeholder = "Select an option", options, onSelect, getOptionValue = (opt) => opt.id, // if unset, assume O implements HasId
22
- getOptionLabel = (opt) => opt.name, // if unset, assume O implements HasName
24
+ const { label, value, disabled = false, placeholder = "Select an option", options, onSelect, getOptionValue = options_1.defaultOptionValue, // if unset, assume O implements HasId
25
+ getOptionLabel = options_1.defaultOptionLabel, // if unset, assume O implements HasName
23
26
  onFocus, onBlur, clearable = false, onCreateNew, } = props;
24
27
  const tid = (0, utils_1.useTestIds)(props, "chipSelectField");
25
28
  const typeScale = (_a = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.typeScale) !== null && _a !== void 0 ? _a : "sm";
26
29
  const isDisabled = !!disabled;
27
30
  const showClearButton = !disabled && clearable && !!value;
28
- const chipStyles = Css_1.Css[typeScale].tl.bgGray300.gray900.br16.pxPx(10).pyPx(2).$;
31
+ const chipStyles = (0, react_1.useMemo)(() => Css_1.Css[typeScale].tl.bgGray300.gray900.br16.pxPx(10).pyPx(2).$, [typeScale]);
29
32
  // Controls showing the focus border styles.
30
33
  const [visualFocus, setVisualFocus] = (0, react_1.useState)(false);
31
34
  const [isClearFocused, setIsClearFocused] = (0, react_1.useState)(false);
@@ -63,20 +66,34 @@ function ChipSelectField(props) {
63
66
  initialSelectedKeys: [(0, Value_1.valueToKey)(value)],
64
67
  getKey: (item) => (isListBoxSection(item) ? item.title : getOptionValue(item)),
65
68
  });
66
- (0, react_1.useEffect)(() => listData.update("Options", { title: "Options", options }), [options]);
67
- const selectChildren = listData.items.map((s) => {
69
+ (0, react_1.useEffect)(() => {
70
+ // Avoid unnecessary update of `options` on first render. We define the initial set of items based on the options in the `useListData` hook.
71
+ if (!firstRender.current) {
72
+ if (onCreateNew) {
73
+ // if we have the options in a section, update that section
74
+ listData.update("Options", { title: "Options", options });
75
+ }
76
+ else {
77
+ // otherwise, reset the list completely. We could traverse through the list and update/add/remove when needed, though this is simpler for now.
78
+ listData.remove(...state.collection.getKeys());
79
+ listData.append(...options);
80
+ }
81
+ }
82
+ firstRender.current = false;
83
+ }, [options]);
84
+ const selectChildren = (0, react_1.useMemo)(() => listData.items.map((s) => {
68
85
  if (isListBoxSection(s)) {
69
86
  return ((0, jsx_runtime_1.jsx)(react_stately_1.Section, Object.assign({ title: s.title, items: s.options }, { children: (item) => {
70
87
  if (isPersistentItem(item)) {
71
88
  return ((0, jsx_runtime_1.jsx)(react_stately_1.Item, Object.assign({ textValue: item.name }, { children: item.name }), item.id));
72
89
  }
73
90
  const label = getOptionLabel(item);
74
- return ((0, jsx_runtime_1.jsx)(react_stately_1.Item, Object.assign({ textValue: label }, { children: (0, jsx_runtime_1.jsx)("span", Object.assign({ css: { ...Css_1.Css.lineClamp1.breakAll.$, ...chipStyles }, title: label }, { children: label }), void 0) }), getOptionValue(item)));
91
+ return ((0, jsx_runtime_1.jsx)(react_stately_1.Item, Object.assign({ textValue: label }, { children: (0, jsx_runtime_1.jsx)(ListBoxChip_1.ListBoxChip, { label: label }, void 0) }), getOptionValue(item)));
75
92
  } }), (0, change_case_1.camelCase)(s.title)));
76
93
  }
77
94
  const label = getOptionLabel(s);
78
- return ((0, jsx_runtime_1.jsx)(react_stately_1.Item, Object.assign({ textValue: label }, { children: (0, jsx_runtime_1.jsx)("span", Object.assign({ css: { ...Css_1.Css.lineClamp1.breakAll.$, ...chipStyles }, title: label }, { children: label }), void 0) }), getOptionValue(s)));
79
- });
95
+ return ((0, jsx_runtime_1.jsx)(react_stately_1.Item, Object.assign({ textValue: label }, { children: (0, jsx_runtime_1.jsx)(ListBoxChip_1.ListBoxChip, { label: label }, void 0) }), getOptionValue(s)));
96
+ }), [listData.items, getOptionLabel, getOptionValue]);
80
97
  const selectHookProps = {
81
98
  label,
82
99
  isDisabled,
@@ -135,17 +152,15 @@ function ChipSelectField(props) {
135
152
  };
136
153
  // State management for the "Create new" flow with ChipTextField.
137
154
  const [showInput, setShowInput] = (0, react_1.useState)(false);
138
- const [inputValue, setInputValue] = (0, react_1.useState)("Add new");
139
155
  const removeCreateNewField = (0, react_1.useCallback)(() => {
140
156
  setShowInput(false);
141
- setInputValue("Add new");
142
157
  // Trigger onBlur to initiate any auto-saving behavior.
143
158
  (0, utils_1.maybeCall)(onBlur);
144
- }, [setShowInput, setInputValue]);
145
- const field = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showInput && onCreateNew && ((0, jsx_runtime_1.jsx)(ChipTextField_1.ChipTextField, Object.assign({ autoFocus: true, label: "Add new", value: inputValue, onChange: setInputValue, onEnter: async () => {
146
- await onCreateNew(inputValue);
159
+ }, [setShowInput]);
160
+ const field = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showInput && onCreateNew && ((0, jsx_runtime_1.jsx)(CreateNewField, Object.assign({ onBlur: removeCreateNewField, onEnter: async (value) => {
161
+ await onCreateNew(value);
147
162
  removeCreateNewField();
148
- }, onBlur: removeCreateNewField }, tid.createNewField), void 0)), (0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: wrapperRef, css: {
163
+ } }, tid.createNewField), void 0)), (0, jsx_runtime_1.jsxs)("div", Object.assign({ ref: wrapperRef, css: {
149
164
  ...chipStyles,
150
165
  ...Css_1.Css.dif.relative.p0.mwPx(32).if(!value).bgGray200.$,
151
166
  ...(visualFocus ? Css_1.Css.bshFocus.$ : {}),
@@ -184,3 +199,10 @@ function isListBoxSection(obj) {
184
199
  return typeof obj === "object" && "options" in obj;
185
200
  }
186
201
  exports.isListBoxSection = isListBoxSection;
202
+ // Wrapper for the ChipTextField used in the "Create New" flow on ChipSelectField
203
+ function CreateNewField(props) {
204
+ const { onBlur, onEnter } = props;
205
+ const [value, setValue] = (0, react_1.useState)("Add new");
206
+ const tid = (0, utils_1.useTestIds)(props);
207
+ return ((0, jsx_runtime_1.jsx)(ChipTextField_1.ChipTextField, Object.assign({ autoFocus: true, label: "Add new", value: value, onChange: setValue, onEnter: () => onEnter(value), onBlur: onBlur }, tid), void 0));
208
+ }
@@ -4,10 +4,10 @@ exports.ListBox = 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 ToggleChip_1 = require("../../components/ToggleChip");
8
7
  const Css_1 = require("../../Css");
9
8
  const constants_1 = require("./constants");
10
9
  const ListBoxSection_1 = require("./ListBoxSection");
10
+ const ListBoxToggleChip_1 = require("./ListBoxToggleChip");
11
11
  const VirtualizedOptions_1 = require("./VirtualizedOptions");
12
12
  /** A ListBox is an internal component used by SelectField and MultiSelectField to display the list of options */
13
13
  function ListBox(props) {
@@ -33,19 +33,12 @@ function ListBox(props) {
33
33
  return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
34
34
  ...Css_1.Css.bgWhite.br4.w100.bshBasic.if(contrast).bgGray700.$,
35
35
  "&: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)(ListBoxChip, { 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,
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,
37
37
  // Only scroll on focus if using VirtualFocus (used for ComboBoxState (SelectField), but not SelectState (ChipSelectField))
38
38
  scrollOnFocus: props.shouldUseVirtualFocus }, section.key)))) : ((0, jsx_runtime_1.jsx)(VirtualizedOptions_1.VirtualizedOptions, { state: state, items: [...state.collection], onListHeightChange: onListHeightChange, contrast: contrast,
39
39
  // Only scroll on focus if using VirtualFocus (used for ComboBoxState (SelectField), but not SelectState (ChipSelectField))
40
40
  scrollOnFocus: props.shouldUseVirtualFocus }, void 0)) }), void 0)] }), void 0));
41
41
  }
42
42
  exports.ListBox = ListBox;
43
- /** Chip used to display selections within ListBox when using the MultiSelectField */
44
- function ListBoxChip(props) {
45
- const { state, option, getOptionLabel, getOptionValue, disabled = false } = props;
46
- return ((0, jsx_runtime_1.jsx)("li", Object.assign({ css: Css_1.Css.mr1.mb1.$ }, { children: (0, jsx_runtime_1.jsx)(ToggleChip_1.ToggleChip, { text: getOptionLabel(option), onClick: () => {
47
- state.selectionManager.toggleSelection(String(getOptionValue(option)));
48
- }, disabled: disabled }, void 0) }), void 0));
49
- }
50
43
  // UX specified maximum height for a ListBox (in pixels)
51
44
  const maxPopoverHeight = 512;
@@ -0,0 +1,5 @@
1
+ interface ListBoxChipProps {
2
+ label: string;
3
+ }
4
+ export declare function ListBoxChip({ label }: ListBoxChipProps): import("@emotion/react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ListBoxChip = void 0;
4
+ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const PresentationContext_1 = require("../../components/PresentationContext");
6
+ const Css_1 = require("../../Css");
7
+ function ListBoxChip({ label }) {
8
+ var _a;
9
+ const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
10
+ return ((0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css[(_a = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.typeScale) !== null && _a !== void 0 ? _a : "sm"].tl.bgGray300.gray900.br16.pxPx(10).pyPx(2).lineClamp1.breakAll.$, title: label }, { children: label }), void 0));
11
+ }
12
+ exports.ListBoxChip = ListBoxChip;
@@ -0,0 +1,12 @@
1
+ import { Key } from "react";
2
+ import { SelectState } from "react-stately";
3
+ interface ListBoxToggleChipProps<O, V extends Key> {
4
+ state: SelectState<O>;
5
+ option: O;
6
+ getOptionLabel: (opt: O) => string;
7
+ getOptionValue: (opt: O) => V;
8
+ disabled?: boolean;
9
+ }
10
+ /** Chip used to display selections within ListBox when using the MultiSelectField */
11
+ export declare function ListBoxToggleChip<O, V extends Key>(props: ListBoxToggleChipProps<O, V>): import("@emotion/react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ListBoxToggleChip = void 0;
4
+ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const components_1 = require("../../components");
6
+ const Css_1 = require("../../Css");
7
+ /** Chip used to display selections within ListBox when using the MultiSelectField */
8
+ function ListBoxToggleChip(props) {
9
+ const { state, option, getOptionLabel, getOptionValue, disabled = false } = props;
10
+ return ((0, jsx_runtime_1.jsx)("li", Object.assign({ css: Css_1.Css.mr1.mb1.$ }, { children: (0, jsx_runtime_1.jsx)(components_1.ToggleChip, { text: getOptionLabel(option), onClick: () => {
11
+ state.selectionManager.toggleSelection(String(getOptionValue(option)));
12
+ }, disabled: disabled }, void 0) }), void 0));
13
+ }
14
+ exports.ListBoxToggleChip = ListBoxToggleChip;
@@ -0,0 +1,2 @@
1
+ export declare const defaultOptionValue: <O>(opt: O) => any;
2
+ export declare const defaultOptionLabel: <O>(opt: O) => any;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultOptionLabel = exports.defaultOptionValue = void 0;
4
+ const defaultOptionValue = (opt) => opt.id;
5
+ exports.defaultOptionValue = defaultOptionValue;
6
+ const defaultOptionLabel = (opt) => opt.name;
7
+ exports.defaultOptionLabel = defaultOptionLabel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.91.7",
3
+ "version": "2.91.8",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -119,6 +119,7 @@
119
119
  "react-beautiful-dnd": "^13.1.0",
120
120
  "react-dom": "^16.14.0",
121
121
  "semantic-release": "^17.4.0",
122
+ "storybook-addon-performance": "^0.16.1",
122
123
  "ts-jest": "^26.5.3",
123
124
  "ts-node": "^9.1.1",
124
125
  "tslib": "^2.1.0",