@homebound/beam 2.119.1 → 2.121.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.
@@ -14,8 +14,13 @@ export interface IconButtonProps extends BeamButtonProps, BeamFocusableProps {
14
14
  buttonRef?: RefObject<HTMLButtonElement>;
15
15
  /** Whether to show a 16x16px version of the IconButton */
16
16
  compact?: boolean;
17
+ /** Whether to display the contrast variant */
18
+ contrast?: boolean;
17
19
  }
18
20
  export declare function IconButton(props: IconButtonProps): import("@emotion/react/jsx-runtime").JSX.Element;
19
21
  export declare const iconButtonStylesHover: {
20
22
  backgroundColor: import("csstype").Property.BackgroundColor | undefined;
21
23
  };
24
+ export declare const iconButtonContrastStylesHover: {
25
+ backgroundColor: import("csstype").Property.BackgroundColor | undefined;
26
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.iconButtonStylesHover = exports.IconButton = void 0;
3
+ exports.iconButtonContrastStylesHover = exports.iconButtonStylesHover = exports.IconButton = 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");
@@ -10,7 +10,7 @@ const Css_1 = require("../Css");
10
10
  const utils_1 = require("../utils");
11
11
  const useTestIds_1 = require("../utils/useTestIds");
12
12
  function IconButton(props) {
13
- const { onClick: onPress, disabled, color, icon, autoFocus, inc, buttonRef, tooltip, menuTriggerProps, openInNew, compact = false, } = props;
13
+ const { onClick: onPress, disabled, color, icon, autoFocus, inc, buttonRef, tooltip, menuTriggerProps, openInNew, compact = false, contrast = false, } = props;
14
14
  const isDisabled = !!disabled;
15
15
  const ariaProps = { onPress, isDisabled, autoFocus, ...menuTriggerProps };
16
16
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -26,12 +26,13 @@ function IconButton(props) {
26
26
  const styles = (0, react_1.useMemo)(() => ({
27
27
  ...iconButtonStylesReset,
28
28
  ...(compact ? iconButtonCompact : iconButtonNormal),
29
- ...(isHovered && exports.iconButtonStylesHover),
29
+ ...(isHovered && (contrast ? exports.iconButtonContrastStylesHover : exports.iconButtonStylesHover)),
30
30
  ...(isFocusVisible && iconButtonStylesFocus),
31
31
  ...(isDisabled && iconButtonStylesDisabled),
32
32
  }), [isHovered, isFocusVisible, isDisabled, compact]);
33
+ const iconColor = contrast ? contrastIconColor : defaultIconColor;
33
34
  const buttonAttrs = { ...testIds, ...buttonProps, ...focusProps, ...hoverProps, ref: ref, css: styles };
34
- const buttonContent = ((0, jsx_runtime_1.jsx)(components_1.Icon, { icon: icon, color: color || (isDisabled ? Css_1.Palette.Gray400 : Css_1.Palette.Gray900), inc: compact ? 2 : inc }, void 0));
35
+ const buttonContent = ((0, jsx_runtime_1.jsx)(components_1.Icon, { icon: icon, color: color || (isDisabled ? Css_1.Palette.Gray400 : iconColor), inc: compact ? 2 : inc }, void 0));
35
36
  const button = typeof onPress === "string" ? ((0, utils_1.isAbsoluteUrl)(onPress) || openInNew ? ((0, jsx_runtime_1.jsx)("a", Object.assign({}, buttonAttrs, { href: onPress, className: components_1.navLink, target: "_blank", rel: "noreferrer noopener" }, { children: buttonContent }), void 0)) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Link, Object.assign({}, buttonAttrs, { to: onPress, className: components_1.navLink }, { children: buttonContent }), void 0))) : ((0, jsx_runtime_1.jsx)("button", Object.assign({}, buttonAttrs, { children: buttonContent }), void 0));
36
37
  // If we're disabled b/c of a non-boolean ReactNode, or the caller specified tooltip text, then show it in a tooltip
37
38
  return (0, components_1.maybeTooltip)({
@@ -41,9 +42,12 @@ function IconButton(props) {
41
42
  });
42
43
  }
43
44
  exports.IconButton = IconButton;
45
+ const defaultIconColor = Css_1.Palette.Gray900;
46
+ const contrastIconColor = Css_1.Palette.White;
44
47
  const iconButtonStylesReset = Css_1.Css.bTransparent.bsSolid.bgTransparent.cursorPointer.outline0.dif.aic.jcc.transition.$;
45
48
  const iconButtonNormal = Css_1.Css.hPx(28).wPx(28).br8.bw2.$;
46
49
  const iconButtonCompact = Css_1.Css.hPx(18).wPx(18).br4.bw1.$;
47
50
  exports.iconButtonStylesHover = Css_1.Css.bgGray200.$;
51
+ exports.iconButtonContrastStylesHover = Css_1.Css.bgGray700.$;
48
52
  const iconButtonStylesFocus = Css_1.Css.bLightBlue700.$;
49
53
  const iconButtonStylesDisabled = Css_1.Css.cursorNotAllowed.$;
@@ -5,7 +5,7 @@ import { ButtonProps } from "../Button";
5
5
  import { IconButtonProps } from "../IconButton";
6
6
  interface TextButtonTriggerProps extends Pick<ButtonProps, "label" | "variant" | "size" | "icon"> {
7
7
  }
8
- interface IconButtonTriggerProps extends Pick<IconButtonProps, "icon" | "color"> {
8
+ interface IconButtonTriggerProps extends Pick<IconButtonProps, "icon" | "color" | "compact" | "contrast"> {
9
9
  }
10
10
  export interface OverlayTriggerProps {
11
11
  trigger: TextButtonTriggerProps | IconButtonTriggerProps;
@@ -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;
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MultiSelectField = void 0;
4
4
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
5
  const utils_1 = require("../utils");
6
+ const defaultTestId_1 = require("../utils/defaultTestId");
6
7
  /** Mocks out `MultiSelectField` as a multiple `<select>` field. */
7
8
  function MultiSelectField(props) {
8
9
  const { getOptionValue = (o) => o.id, // if unset, assume O implements HasId
9
10
  getOptionLabel = (o) => o.name, // if unset, assume O implements HasName
10
- values, options, onSelect, readOnly = false, errorMsg, onFocus, onBlur, disabled, } = props;
11
- const tid = (0, utils_1.useTestIds)(props, "multiSelect");
11
+ values, options, onSelect, readOnly = false, errorMsg, onFocus, onBlur, disabled, label, } = props;
12
+ const tid = (0, utils_1.useTestIds)(props, (0, defaultTestId_1.defaultTestId)(label));
12
13
  return ((0, jsx_runtime_1.jsxs)("select", Object.assign({}, tid, {
13
14
  // We're cheating and assume the values are strings...what we should really do is either:
14
15
  // a) use beam's valueToKey mapping to string-encode any Value, or
@@ -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) {
@@ -4,12 +4,13 @@ exports.SelectField = void 0;
4
4
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const utils_1 = require("../utils");
7
+ const defaultTestId_1 = require("../utils/defaultTestId");
7
8
  /** Mocks out `SelectField` as a `<select>` field. */
8
9
  function SelectField(props) {
9
10
  const { getOptionValue = (o) => o.id, // if unset, assume O implements HasId
10
11
  getOptionLabel = (o) => o.name, // if unset, assume O implements HasName
11
- value, options: maybeOptions, onSelect, readOnly = false, errorMsg, onBlur, onFocus, disabled, disabledOptions = [], } = props;
12
- const tid = (0, utils_1.useTestIds)(props, "select");
12
+ value, options: maybeOptions, onSelect, readOnly = false, errorMsg, onBlur, onFocus, disabled, disabledOptions = [], label, } = props;
13
+ const tid = (0, utils_1.useTestIds)(props, (0, defaultTestId_1.defaultTestId)(label));
13
14
  const [options, setOptions] = (0, react_1.useState)(Array.isArray(maybeOptions) ? maybeOptions : maybeOptions.initial);
14
15
  const currentOption = options.find((o) => getOptionValue(o) === value) || options[0];
15
16
  (0, react_1.useEffect)(() => {
@@ -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.119.1",
3
+ "version": "2.121.1",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",