@homebound/beam 2.325.0 → 2.325.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,11 @@
1
1
  import { FieldState } from "@homebound/form-state";
2
2
  import { IconCardGroupProps } from "../inputs/IconCardGroup";
3
- export type BoundIconCardGroupFieldProps = Omit<IconCardGroupProps, "label" | "values" | "onChange"> & {
4
- field: FieldState<string[] | null | undefined>;
3
+ import { Value } from "../inputs";
4
+ export type BoundIconCardGroupFieldProps<V extends Value> = Omit<IconCardGroupProps<V>, "label" | "values" | "onChange"> & {
5
+ field: FieldState<V[] | null | undefined>;
5
6
  /** Make optional so that callers can override if they want to. */
6
- onChange?: (values: string[]) => void;
7
+ onChange?: (values: V[]) => void;
7
8
  label?: string;
8
9
  };
9
10
  /** Wraps `IconCardGroup` and binds it to a form field. */
10
- export declare function BoundIconCardGroupField(props: BoundIconCardGroupFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
11
+ export declare function BoundIconCardGroupField<V extends Value>(props: BoundIconCardGroupFieldProps<V>): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -1,23 +1,26 @@
1
1
  import { ReactNode } from "react";
2
2
  import { IconProps } from "../components/Icon";
3
3
  import { PresentationFieldProps } from "../components/PresentationContext";
4
- export interface IconCardGroupItemOption {
4
+ import { Value } from "./";
5
+ export interface IconCardGroupItemOption<V extends Value> {
5
6
  icon: IconProps["icon"];
6
7
  label: string;
7
8
  disabled?: boolean;
8
9
  /** The value of the IconCardGroup item, stored in value array in state. */
9
- value: string;
10
+ value: V;
11
+ /** Exclusive: if true, this option will override all other options when selected. */
12
+ exclusive?: boolean;
10
13
  }
11
- export interface IconCardGroupProps extends Pick<PresentationFieldProps, "labelStyle"> {
14
+ export interface IconCardGroupProps<V extends Value> extends Pick<PresentationFieldProps, "labelStyle"> {
12
15
  label: string;
13
16
  /** Called when a card is selected */
14
- onChange: (values: string[]) => void;
17
+ onChange: (values: V[]) => void;
15
18
  /** Options for the cards contained within the IconCardGroup. */
16
- options: IconCardGroupItemOption[];
19
+ options: IconCardGroupItemOption<V>[];
17
20
  /** The values currently selected. */
18
- values: string[];
21
+ values: V[];
19
22
  errorMsg?: string;
20
23
  helperText?: string | ReactNode;
21
24
  disabled?: boolean;
22
25
  }
23
- export declare function IconCardGroup(props: IconCardGroupProps): import("@emotion/react/jsx-runtime").JSX.Element;
26
+ export declare function IconCardGroup<V extends Value>(props: IconCardGroupProps<V>): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -2,8 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.IconCardGroup = void 0;
4
4
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
- const react_aria_1 = require("react-aria");
6
- const react_stately_1 = require("react-stately");
5
+ const react_1 = require("react");
7
6
  const Css_1 = require("../Css");
8
7
  const Label_1 = require("../components/Label");
9
8
  const PresentationContext_1 = require("../components/PresentationContext");
@@ -11,18 +10,47 @@ const utils_1 = require("../utils");
11
10
  const IconCard_1 = require("./IconCard");
12
11
  const HelperText_1 = require("../components/HelperText");
13
12
  const ErrorMessage_1 = require("./ErrorMessage");
13
+ const react_aria_1 = require("react-aria");
14
14
  function IconCardGroup(props) {
15
15
  var _a;
16
16
  const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
17
- const { options, label, labelStyle = (_a = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.labelStyle) !== null && _a !== void 0 ? _a : "above", values, errorMsg, helperText, disabled: isDisabled = false, } = props;
18
- const state = (0, react_stately_1.useCheckboxGroupState)({ ...props, isDisabled, value: values });
19
- const { groupProps, labelProps } = (0, react_aria_1.useCheckboxGroup)(props, state);
17
+ const { options, label, labelStyle = (_a = fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.labelStyle) !== null && _a !== void 0 ? _a : "above", values, errorMsg, helperText, disabled: isDisabled = false, onChange, } = props;
18
+ const [selected, setSelected] = (0, react_1.useState)(values);
19
+ const exclusiveOptions = (0, react_1.useMemo)(() => options.filter((o) => o.exclusive), [options]);
20
+ const toggleValue = (0, react_1.useCallback)((value) => {
21
+ if (isDisabled)
22
+ return;
23
+ const option = options.find((o) => o.value === value);
24
+ if (!option)
25
+ return;
26
+ let newSelected = [];
27
+ if (selected.includes(value)) {
28
+ newSelected = selected.filter((v) => v !== value);
29
+ }
30
+ else {
31
+ if (option.exclusive) {
32
+ newSelected = [value];
33
+ }
34
+ else {
35
+ newSelected = [...selected, value];
36
+ // Filter out any exclusive options as a non-exclusive option was selected.
37
+ newSelected = newSelected.filter((v) => !exclusiveOptions.some((o) => o.value === v));
38
+ }
39
+ }
40
+ setSelected(newSelected);
41
+ onChange(newSelected);
42
+ }, [exclusiveOptions, isDisabled, onChange, options, selected]);
20
43
  const tid = (0, utils_1.useTestIds)(props);
21
- return ((0, jsx_runtime_1.jsxs)("div", { ...groupProps, ...tid, children: [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, ...labelProps, ...tid.label }) })), (0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.df.gap2.add({ flexWrap: "wrap" }).$, children: options.map((option) => {
44
+ const { labelProps, fieldProps: fieldPropsAria } = (0, react_aria_1.useField)(props);
45
+ const groupProps = (0, react_aria_1.mergeProps)(tid, {
46
+ role: "group",
47
+ "aria-disabled": isDisabled || undefined,
48
+ ...fieldPropsAria,
49
+ });
50
+ return ((0, jsx_runtime_1.jsxs)("div", { ...groupProps, children: [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, ...labelProps, ...tid.label }) })), (0, jsx_runtime_1.jsx)("div", { css: Css_1.Css.df.gap2.add({ flexWrap: "wrap" }).$, children: options.map((option) => {
22
51
  const { icon, label, disabled } = option;
23
- const isSelected = state.isSelected(option.value);
24
- const isDisabled = disabled || state.isDisabled;
25
- return ((0, jsx_runtime_1.jsx)(IconCard_1.IconCard, { icon: icon, label: label, selected: isSelected, disabled: isDisabled, onChange: () => state.toggleValue(option.value), ...tid[option.value] }, option.value));
52
+ const isSelected = selected.includes(option.value);
53
+ return ((0, jsx_runtime_1.jsx)(IconCard_1.IconCard, { icon: icon, label: label, selected: isSelected, disabled: disabled, onChange: () => toggleValue(option.value), ...tid[option.label] }, option.label));
26
54
  }) }), errorMsg && (0, jsx_runtime_1.jsx)(ErrorMessage_1.ErrorMessage, { errorMsg: errorMsg, ...tid.errorMsg }), helperText && (0, jsx_runtime_1.jsx)(HelperText_1.HelperText, { helperText: helperText, ...tid.helperText })] }));
27
55
  }
28
56
  exports.IconCardGroup = IconCardGroup;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.325.0",
3
+ "version": "2.325.1",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",