@homebound/beam 2.356.1 → 2.358.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.
@@ -14,7 +14,10 @@ exports.multiFilter = multiFilter;
14
14
  class MultiFilter extends BaseFilter_1.BaseFilter {
15
15
  render(value, setValue, tid, inModal, vertical) {
16
16
  var _a;
17
- if (inModal && this.props.options.length > 0 && this.props.options.length <= 8) {
17
+ if (inModal &&
18
+ Array.isArray(this.props.options) &&
19
+ this.props.options.length > 0 &&
20
+ this.props.options.length <= 8) {
18
21
  const { disabledOptions } = this.props;
19
22
  const disabledOptionsWithReasons = Object.fromEntries((_a = disabledOptions === null || disabledOptions === void 0 ? void 0 : disabledOptions.map(ComboBoxBase_1.disabledOptionToKeyedTuple)) !== null && _a !== void 0 ? _a : []);
20
23
  const disabledKeys = Object.keys(disabledOptionsWithReasons);
@@ -29,7 +32,7 @@ class MultiFilter extends BaseFilter_1.BaseFilter {
29
32
  };
30
33
  }), onChange: (values) => {
31
34
  setValue(values.length === 0 ? undefined : values);
32
- }, values: value || [], hideLabel: true, ...tid[(0, defaultTestId_1.defaultTestId)(this.label)] }));
35
+ }, values: value || [], labelStyle: "hidden", ...tid[(0, defaultTestId_1.defaultTestId)(this.label)] }));
33
36
  }
34
37
  const { defaultValue, nothingSelectedText, ...props } = this.props;
35
38
  return ((0, jsx_runtime_1.jsx)(MultiSelectField_1.MultiSelectField, { ...props, compact: !vertical, label: this.label, values: value || [], labelStyle: inModal ? "hidden" : !inModal && !vertical ? "inline" : "above", sizeToContent: !inModal && !vertical, onSelect: (values) => {
@@ -5,6 +5,8 @@ export interface PresentationFieldProps {
5
5
  numberAlignment?: "left" | "right";
6
6
  /** Sets the label position or visibility. Defaults to "above" */
7
7
  labelStyle?: "inline" | "hidden" | "above" | "left";
8
+ /** Defines the width property of the input field wrapper when using `labelStyle="left"`. */
9
+ labelLeftFieldWidth?: number | string;
8
10
  labelSuffix?: LabelSuffixStyle;
9
11
  borderless?: boolean;
10
12
  compact?: boolean;
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from "react";
2
- import { LabelSuffixStyle } from "../components/PresentationContext";
2
+ import { PresentationFieldProps } from "../components/PresentationContext";
3
3
  export type FormWidth =
4
4
  /** 320px. */
5
5
  "sm"
@@ -9,13 +9,12 @@ export type FormWidth =
9
9
  | "lg"
10
10
  /** 100%, works well for showing full width fields, or deferring to the parent width. */
11
11
  | "full";
12
- export interface FormLinesProps {
12
+ export interface FormLinesProps extends Pick<PresentationFieldProps, "labelStyle" | "labelLeftFieldWidth" | "labelSuffix" | "compact"> {
13
13
  /** Let the user interleave group-less lines and grouped lines. */
14
14
  children: ReactNode;
15
- labelSuffix?: LabelSuffixStyle;
16
- labelStyle?: "inline" | "hidden" | "above" | "left";
17
15
  width?: FormWidth;
18
- compact?: boolean;
16
+ /** Increment property (e.g. 1 = 8px). Defines space between form fields */
17
+ gap?: number;
19
18
  }
20
19
  /**
21
20
  * Applies standard Form layout/size/spacing between lines.
@@ -14,20 +14,21 @@ const components_1 = require("../components");
14
14
  */
15
15
  function FormLines(props) {
16
16
  const { inModal } = (0, components_1.useModal)();
17
- const { children, width = inModal ? "full" : "lg", labelSuffix, labelStyle, compact } = props;
17
+ const { children, width = inModal ? "full" : "lg", labelSuffix, labelStyle, compact, gap = 2, labelLeftFieldWidth, } = props;
18
18
  let firstFormHeading = true;
19
19
  // Only overwrite `fieldProps` if new values are explicitly set. Ensures we only set to `undefined` if explicitly set.
20
20
  const newFieldProps = {
21
21
  ...("labelSuffix" in props ? { labelSuffix } : {}),
22
22
  ...("labelStyle" in props ? { labelStyle } : {}),
23
23
  ...("compact" in props ? { compact } : {}),
24
+ ...("labelLeftFieldWidth" in props ? { labelLeftFieldWidth } : {}),
24
25
  ...(width === "full" ? { fullWidth: true } : {}),
25
26
  };
26
27
  return ((0, jsx_runtime_1.jsx)(PresentationContext_1.PresentationProvider, { fieldProps: newFieldProps, children: (0, jsx_runtime_1.jsx)("div", { css: {
27
28
  // Note that we're purposefully not using display:flex so that our children's margins will collapse.
28
29
  ...Css_1.Css.w(sizes[width]).$,
29
30
  // Purposefully use this instead of childGap3 to put margin-bottom on the last line
30
- "& > *": Css_1.Css.mb2.$,
31
+ "& > *": Css_1.Css.mb(gap).$,
31
32
  }, children: react_1.Children.map(children, (child) => {
32
33
  if (child && typeof child === "object" && "type" in child && child.type.isFormHeading) {
33
34
  const clone = (0, react_1.cloneElement)(child, { isFirst: firstFormHeading });
@@ -9,7 +9,6 @@ export interface MultiSelectFieldProps<O, V extends Value> extends Exclude<Combo
9
9
  getOptionLabel: (opt: O) => string;
10
10
  values: V[];
11
11
  onSelect: (values: V[], opts: O[]) => void;
12
- options: O[];
13
12
  }
14
13
  /**
15
14
  * Provides a non-native multiselect/dropdown widget.
@@ -9,7 +9,10 @@ const Label_1 = require("../components/Label");
9
9
  const Css_1 = require("../Css");
10
10
  const Icon_1 = require("../components/Icon");
11
11
  const utils_1 = require("../utils");
12
+ const PresentationContext_1 = require("../components/PresentationContext");
12
13
  function Switch(props) {
14
+ const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
15
+ const { labelLeftFieldWidth = "50%" } = fieldProps !== null && fieldProps !== void 0 ? fieldProps : {};
13
16
  const { selected: isSelected, disabled = false, onChange, withIcon, compact = false, label, labelStyle = "inline", hideLabel = false, ...otherProps } = props;
14
17
  const isDisabled = !!disabled;
15
18
  const ariaProps = { isSelected, isDisabled, ...otherProps };
@@ -23,23 +26,23 @@ function Switch(props) {
23
26
  return ((0, jsx_runtime_1.jsxs)("label", { ...hoverProps, css: {
24
27
  ...Css_1.Css.relative.cursorPointer.df.wmaxc.usn.$,
25
28
  ...(labelStyle === "form" && Css_1.Css.fdc.$),
26
- ...(labelStyle === "left" && Css_1.Css.w100.aic.$),
29
+ ...(labelStyle === "left" && Css_1.Css.w100.aic.jcsb.$),
27
30
  ...(labelStyle === "inline" && Css_1.Css.gap2.aic.$),
28
31
  ...(labelStyle === "filter" && Css_1.Css.jcsb.gap1.aic.wa.sm.$),
29
32
  ...(labelStyle === "centered" && Css_1.Css.fdc.aic.$),
30
33
  ...(isDisabled && Css_1.Css.cursorNotAllowed.gray400.$),
31
- }, children: [labelStyle !== "inline" && labelStyle !== "hidden" && ((0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.if(labelStyle === "left").w50.$, children: (0, jsx_runtime_1.jsx)(Label_1.Label, { label: label, tooltip: tooltip, xss: Css_1.Css.if(labelStyle === "filter").gray900.$, inline: labelStyle === "left" || labelStyle === "filter" }) })), (0, jsx_runtime_1.jsx)("div", { "aria-hidden": "true", css: {
32
- ...Css_1.Css.wPx(40).hPx(toggleHeight(compact)).bgGray200.br12.relative.transition.$,
33
- ...(isHovered && exports.switchHoverStyles),
34
- ...(isKeyboardFocus && exports.switchFocusStyles),
35
- ...(isDisabled && Css_1.Css.bgGray300.$),
36
- ...(isSelected && Css_1.Css.bgBlue700.$),
37
- ...(isSelected && isHovered && exports.switchSelectedHoverStyles),
38
- }, children: (0, jsx_runtime_1.jsx)("div", { css: {
39
- ...switchCircleDefaultStyles(compact),
40
- ...(isDisabled && Css_1.Css.bgGray100.$),
41
- ...(isSelected && switchCircleSelectedStyles(compact)),
42
- }, children: withIcon && ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { icon: isSelected ? "check" : "x", color: isSelected ? Css_1.Palette.Blue700 : Css_1.Palette.Gray400 })) }) }), labelStyle === "inline" && ((0, jsx_runtime_1.jsx)(Label_1.Label, { label: label, tooltip: tooltip, inline: true, xss: Css_1.Css.smMd.gray900.if(compact).add("lineHeight", "1").$ })), (0, jsx_runtime_1.jsx)(react_aria_1.VisuallyHidden, { children: (0, jsx_runtime_1.jsx)("input", { ref: ref, ...inputProps, ...focusProps, ...tid }) })] }));
34
+ }, children: [labelStyle !== "inline" && labelStyle !== "hidden" && ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(Label_1.Label, { label: label, tooltip: tooltip, xss: Css_1.Css.if(labelStyle === "filter").gray900.$, inline: labelStyle === "left" || labelStyle === "filter" }) })), (0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.if(labelStyle === "left").w(labelLeftFieldWidth).$, children: (0, jsx_runtime_1.jsx)("div", { "aria-hidden": "true", css: {
35
+ ...Css_1.Css.wPx(40).hPx(toggleHeight(compact)).bgGray200.br12.relative.transition.$,
36
+ ...(isHovered && exports.switchHoverStyles),
37
+ ...(isKeyboardFocus && exports.switchFocusStyles),
38
+ ...(isDisabled && Css_1.Css.bgGray300.$),
39
+ ...(isSelected && Css_1.Css.bgBlue700.$),
40
+ ...(isSelected && isHovered && exports.switchSelectedHoverStyles),
41
+ }, children: (0, jsx_runtime_1.jsx)("div", { css: {
42
+ ...switchCircleDefaultStyles(compact),
43
+ ...(isDisabled && Css_1.Css.bgGray100.$),
44
+ ...(isSelected && switchCircleSelectedStyles(compact)),
45
+ }, children: withIcon && ((0, jsx_runtime_1.jsx)(Icon_1.Icon, { icon: isSelected ? "check" : "x", color: isSelected ? Css_1.Palette.Blue700 : Css_1.Palette.Gray400 })) }) }) }), labelStyle === "inline" && ((0, jsx_runtime_1.jsx)(Label_1.Label, { label: label, tooltip: tooltip, inline: true, xss: Css_1.Css.smMd.gray900.if(compact).add("lineHeight", "1").$ })), (0, jsx_runtime_1.jsx)(react_aria_1.VisuallyHidden, { children: (0, jsx_runtime_1.jsx)("input", { ref: ref, ...inputProps, ...focusProps, ...tid }) })] }));
43
46
  }
44
47
  exports.Switch = Switch;
45
48
  /** Styles */
@@ -19,6 +19,7 @@ const utils_1 = require("./utils");
19
19
  function TextFieldBase(props) {
20
20
  var _a, _b, _c, _d, _e, _f, _g, _h;
21
21
  const { fieldProps, wrap = false } = (0, PresentationContext_1.usePresentationContext)();
22
+ const { labelLeftFieldWidth = "50%" } = fieldProps !== null && fieldProps !== void 0 ? fieldProps : {};
22
23
  const { label, required, labelProps, inputProps, inputRef, inputWrapRef, groupProps, compact = (_a = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.compact) !== null && _a !== void 0 ? _a : false, errorMsg, helperText, multiline = false, onChange, onBlur, onFocus, xss, endAdornment, startAdornment, labelStyle = (_b = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.labelStyle) !== null && _b !== void 0 ? _b : "above", 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, errorInTooltip = (_e = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.errorInTooltip) !== null && _e !== void 0 ? _e : false, hideErrorMessage = false, alwaysShowHelperText = false, fullWidth = (_f = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.fullWidth) !== null && _f !== void 0 ? _f : false, unfocusedPlaceholder, } = props;
23
24
  const typeScale = (_g = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.typeScale) !== null && _g !== void 0 ? _g : (inputProps.readOnly && labelStyle !== "hidden" ? "smMd" : "sm");
24
25
  const internalProps = props.internalProps || {};
@@ -46,7 +47,8 @@ function TextFieldBase(props) {
46
47
  ...Css_1.Css[typeScale].df.aic.br4.px1.w100
47
48
  .bgColor(bgColor)
48
49
  .gray900.if(contrast)
49
- .white.if(labelStyle === "left").w50.$,
50
+ .white.if(labelStyle === "left")
51
+ .w(labelLeftFieldWidth).$,
50
52
  // When borderless then perceived vertical alignments are misaligned. As there is no longer a border, then the field looks oddly indented.
51
53
  // This typically happens in tables when a column has a mix of static text (i.e. "roll up" rows and table headers) and input fields.
52
54
  // To remedy this perceived misalignment then we increase the width by the horizontal padding applied (16px), and set a negative margin left margin to re-center the field.
@@ -67,7 +69,10 @@ function TextFieldBase(props) {
67
69
  .hPx(compactFieldHeight - maybeSmaller).$),
68
70
  },
69
71
  inputWrapperReadOnly: {
70
- ...Css_1.Css[typeScale].df.aic.w100.gray900.if(contrast).white.if(labelStyle === "left").w50.$,
72
+ ...Css_1.Css[typeScale].df.aic.w100.gray900
73
+ .if(contrast)
74
+ .white.if(labelStyle === "left")
75
+ .w(labelLeftFieldWidth).$,
71
76
  // If we are hiding the label, then we are typically in a table. Keep the `mh` in this case to ensure editable and non-editable fields in a single table row line up properly
72
77
  ...(labelStyle === "hidden" &&
73
78
  Css_1.Css.mhPx(fieldHeight - maybeSmaller)
@@ -1,4 +1,5 @@
1
1
  import { ReactNode } from "react";
2
+ import { PresentationFieldProps } from "../components/PresentationContext";
2
3
  type ToggleChipItemProps = {
3
4
  label: string;
4
5
  value: string;
@@ -9,13 +10,11 @@ type ToggleChipItemProps = {
9
10
  */
10
11
  disabled?: boolean | ReactNode;
11
12
  };
12
- export interface ToggleChipGroupProps {
13
+ export interface ToggleChipGroupProps extends Pick<PresentationFieldProps, "labelStyle"> {
13
14
  label: string;
14
- labelStyle?: "above" | "left";
15
15
  options: ToggleChipItemProps[];
16
16
  values: string[];
17
17
  onChange: (values: string[]) => void;
18
- hideLabel?: boolean;
19
18
  }
20
19
  export declare function ToggleChipGroup(props: ToggleChipGroupProps): import("@emotion/react/jsx-runtime").JSX.Element;
21
20
  export {};
@@ -9,12 +9,19 @@ const components_1 = require("../components");
9
9
  const Label_1 = require("../components/Label");
10
10
  const Css_1 = require("../Css");
11
11
  const useTestIds_1 = require("../utils/useTestIds");
12
+ const PresentationContext_1 = require("../components/PresentationContext");
12
13
  function ToggleChipGroup(props) {
13
- const { values, label, labelStyle, options, hideLabel } = props;
14
+ var _a;
15
+ const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
16
+ const { labelLeftFieldWidth = "50%" } = fieldProps !== null && fieldProps !== void 0 ? fieldProps : {};
17
+ const { values, label, labelStyle = (_a = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.labelStyle) !== null && _a !== void 0 ? _a : "above", options } = props;
14
18
  const state = (0, react_stately_1.useCheckboxGroupState)({ ...props, value: values });
15
19
  const { groupProps, labelProps } = (0, react_aria_1.useCheckboxGroup)(props, state);
16
20
  const tid = (0, useTestIds_1.useTestIds)(props, "toggleChip");
17
- return ((0, jsx_runtime_1.jsxs)("div", { ...groupProps, css: Css_1.Css.relative.df.fdc.if(labelStyle === "left").fdr.maxw100.$, children: [(0, jsx_runtime_1.jsx)(Label_1.Label, { label: label, ...labelProps, hidden: hideLabel, inline: labelStyle === "left" }), (0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.df.gap1.add("flexWrap", "wrap").if(labelStyle === "left").ml2.$, children: options.map((o) => ((0, jsx_runtime_1.jsx)(ToggleChip, { value: o.value, groupState: state, selected: state.value.includes(o.value), label: o.label, disabled: o.disabled, ...tid[o.value] }, o.value))) })] }));
21
+ return ((0, jsx_runtime_1.jsxs)("div", { ...groupProps, css: Css_1.Css.relative.df.fdc.if(labelStyle === "left").fdr.gap2.maxw100.jcsb.$, children: [(0, jsx_runtime_1.jsx)(Label_1.Label, { label: label, ...labelProps, hidden: labelStyle === "hidden", inline: labelStyle !== "above" }), (0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.df.gap1
22
+ .add("flexWrap", "wrap")
23
+ .if(labelStyle === "left")
24
+ .w(labelLeftFieldWidth).$, children: options.map((o) => ((0, jsx_runtime_1.jsx)(ToggleChip, { value: o.value, groupState: state, selected: state.value.includes(o.value), label: o.label, disabled: o.disabled, ...tid[o.value] }, o.value))) })] }));
18
25
  }
19
26
  exports.ToggleChipGroup = ToggleChipGroup;
20
27
  function ToggleChip(props) {
@@ -66,8 +66,8 @@ export interface ComboBoxBaseProps<O, V extends Value> extends BeamFocusableProp
66
66
  export declare function ComboBoxBase<O, V extends Value>(props: ComboBoxBaseProps<O, V>): JSX.Element;
67
67
  /** Allows lazy-loading select fields, which is useful for pages w/lots of fields the user may not actually use. */
68
68
  export type OptionsOrLoad<O> = O[] | {
69
- /** The initial option to show before the user interacts with the dropdown. */
70
- current: O | undefined;
69
+ /** The initial option(s) to show before the user interacts with the dropdown. */
70
+ current: O | O[] | undefined;
71
71
  /** Fired when the user interacts with the dropdown, to load the real options. */
72
72
  load: () => Promise<unknown>;
73
73
  /** The full list of options, after load() has been fired. */
@@ -256,13 +256,16 @@ function initializeOptions(optionsOrLoad, getOptionValue, unsetLabel) {
256
256
  if (options) {
257
257
  opts.push(...options);
258
258
  }
259
- // Even if the SelectField has lazy-loaded options, make sure the current value is really in there
259
+ // Add the `current` to the list of options in the event it is not already there.
260
260
  if (current) {
261
- const value = getOptionValue(current);
262
- const found = options && options.find((o) => getOptionValue(o) === value);
263
- if (!found) {
264
- opts.push(current);
265
- }
261
+ const toCheck = Array.isArray(current) ? current : [current];
262
+ toCheck.forEach((current) => {
263
+ const value = getOptionValue(current);
264
+ const found = options && options.find((o) => getOptionValue(o) === value);
265
+ if (!found) {
266
+ opts.push(current);
267
+ }
268
+ });
266
269
  }
267
270
  }
268
271
  return opts;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.356.1",
3
+ "version": "2.358.0",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",