@homebound/beam 2.96.0 → 2.97.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.
package/README.md CHANGED
@@ -23,7 +23,7 @@ _To see the latest designs, check out the [Figma](https://www.figma.com/file/aWU
23
23
 
24
24
  ## Beam's API Design Approach
25
25
 
26
- Beam is specifically "Homebound's design system". Given this extremely narrow purpose, we can lean into the simplicity of:
26
+ Beam is specifically "Homebound's Design System". Given this extremely narrow purpose, we can lean into the simplicity of:
27
27
 
28
28
  - We don't need to support everything for everyone
29
29
  - We can prefer API/UX consistency & simplicity over configuration & complexity
@@ -261,7 +261,7 @@ function renderVirtual(style, id, columns, headerRows, filteredRows, firstRowMes
261
261
  const { paddingBottom, ...otherRootStyles } = (_a = style.rootCss) !== null && _a !== void 0 ? _a : {};
262
262
  return { footerStyle: { paddingBottom }, listStyle: { ...style, rootCss: otherRootStyles } };
263
263
  }, [style]);
264
- return ((0, jsx_runtime_1.jsx)(react_virtuoso_1.Virtuoso, { ref: virtuosoRef, components: {
264
+ return ((0, jsx_runtime_1.jsx)(react_virtuoso_1.Virtuoso, { overscan: 5, ref: virtuosoRef, components: {
265
265
  List: VirtualRoot(listStyle, columns, id, firstLastColumnWidth, xss),
266
266
  Footer: () => (0, jsx_runtime_1.jsx)("div", { css: footerStyle }, void 0),
267
267
  },
@@ -270,11 +270,11 @@ function renderVirtual(style, id, columns, headerRows, filteredRows, firstRowMes
270
270
  const maybeContentsDiv = el.firstElementChild;
271
271
  // If it is a chrome row, then we are not using `display: contents;`, return the height of this element.
272
272
  if ("chrome" in maybeContentsDiv.dataset) {
273
- return maybeContentsDiv.offsetHeight;
273
+ return maybeContentsDiv.getBoundingClientRect().height || 1;
274
274
  }
275
275
  // Both the `Item` and `itemContent` use `display: contents`, so their height is 0,
276
276
  // so instead drill into the 1st real content cell.
277
- return maybeContentsDiv.firstElementChild.offsetHeight;
277
+ return maybeContentsDiv.firstElementChild.getBoundingClientRect().height;
278
278
  }, itemContent: (index) => {
279
279
  // We keep header and filter rows separate, but react-virtuoso is a flat list,
280
280
  // so we pick the right header / first row message / actual row.
@@ -1,6 +1,6 @@
1
1
  import { FieldState } from "@homebound/form-state";
2
2
  import { CheckboxProps } from "../inputs";
3
- export declare type BoundCheckboxFieldProps = Omit<CheckboxProps, "values" | "onChange" | "label" | "onBlur" | "onFocus"> & {
3
+ export declare type BoundCheckboxFieldProps = Omit<CheckboxProps, "values" | "onChange" | "label"> & {
4
4
  field: FieldState<any, boolean | null | undefined>;
5
5
  /** Make optional so that callers can override if they want to. */
6
6
  onChange?: (values: boolean) => void;
@@ -8,7 +8,7 @@ const utils_1 = require("../utils");
8
8
  const defaultLabel_1 = require("../utils/defaultLabel");
9
9
  /** Wraps `Checkbox` and binds it to a form field. */
10
10
  function BoundCheckboxField(props) {
11
- const { field, onChange = (value) => field.set(value), label = (0, defaultLabel_1.defaultLabel)(field.key), ...others } = props;
11
+ const { field, onChange = (value) => field.set(value), label = (0, defaultLabel_1.defaultLabel)(field.key), onFocus, onBlur, ...others } = props;
12
12
  const testId = (0, utils_1.useTestIds)(props, field.key);
13
13
  return ((0, jsx_runtime_1.jsx)(mobx_react_1.Observer, { children: () => {
14
14
  var _a;
@@ -16,7 +16,13 @@ function BoundCheckboxField(props) {
16
16
  // We are triggering blur manually for checkbox fields due to its transactional nature
17
17
  onChange(selected);
18
18
  field.blur();
19
- }, errorMsg: field.touched ? field.errors.join(" ") : undefined }, testId, others), void 0));
19
+ }, errorMsg: field.touched ? field.errors.join(" ") : undefined, onFocus: () => {
20
+ field.focus();
21
+ (0, utils_1.maybeCall)(onFocus);
22
+ }, onBlur: () => {
23
+ field.blur();
24
+ (0, utils_1.maybeCall)(onBlur);
25
+ } }, testId, others), void 0));
20
26
  } }, void 0));
21
27
  }
22
28
  exports.BoundCheckboxField = BoundCheckboxField;
@@ -14,5 +14,9 @@ export interface CheckboxProps {
14
14
  selected?: boolean;
15
15
  errorMsg?: string;
16
16
  helperText?: string | ReactNode;
17
+ /** Callback fired when focus removes from the component */
18
+ onBlur?: () => void;
19
+ /** Callback fired when focus is set to the component */
20
+ onFocus?: () => void;
17
21
  }
18
22
  export declare function Checkbox(props: CheckboxProps): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -23,7 +23,7 @@ function CheckboxBase(props) {
23
23
  .maxw((0, Css_1.px)(320))
24
24
  .if(description !== undefined)
25
25
  .maxw((0, Css_1.px)(344))
26
- .if(isDisabled).cursorNotAllowed.$ }, { children: [(0, jsx_runtime_1.jsx)(react_aria_1.VisuallyHidden, { children: (0, jsx_runtime_1.jsx)("input", Object.assign({ ref: ref }, inputProps, focusProps, tid), void 0) }, void 0), (0, jsx_runtime_1.jsx)("span", Object.assign({}, hoverProps, { css: {
26
+ .if(isDisabled).cursorNotAllowed.$ }, { children: [(0, jsx_runtime_1.jsx)(react_aria_1.VisuallyHidden, { children: (0, jsx_runtime_1.jsx)("input", Object.assign({ ref: ref }, (0, react_aria_1.mergeProps)(inputProps, focusProps), tid), void 0) }, void 0), (0, jsx_runtime_1.jsx)("span", Object.assign({}, hoverProps, { css: {
27
27
  ...baseStyles,
28
28
  ...((isSelected || isIndeterminate) && filledBoxStyles),
29
29
  ...((isSelected || isIndeterminate) && isHovered && filledBoxHoverStyles),
@@ -42,7 +42,7 @@ function ChipSelectField(props) {
42
42
  },
43
43
  onBlur: (e) => {
44
44
  // Do not call onBlur if focus moved to within the Popover
45
- if (popoverRef.current && popoverRef.current.contains(e.relatedTarget)) {
45
+ if ((popoverRef.current && popoverRef.current.contains(e.relatedTarget)) || showInput) {
46
46
  return;
47
47
  }
48
48
  (0, utils_1.maybeCall)(onBlur);
@@ -1,4 +1,5 @@
1
1
  import { ReactNode } from "react";
2
+ import { Modifier } from "react-day-picker";
2
3
  import { TextFieldBaseProps } from "./TextFieldBase";
3
4
  import "./DateField.css";
4
5
  export interface DateFieldProps extends Pick<TextFieldBaseProps<{}>, "borderless" | "visuallyDisabled" | "hideLabel" | "compact"> {
@@ -19,6 +20,11 @@ export interface DateFieldProps extends Pick<TextFieldBaseProps<{}>, "borderless
19
20
  placeholder?: string;
20
21
  format?: keyof typeof dateFormats;
21
22
  iconLeft?: boolean;
23
+ /**
24
+ * Set custom logic for individual dates or date ranges to be disabled in the picker
25
+ * exposed from `react-day-picker`: https://react-day-picker.js.org/api/DayPicker#modifiers
26
+ */
27
+ disabledDays?: Modifier;
22
28
  }
23
29
  export declare function DateField(props: DateFieldProps): import("@emotion/react/jsx-runtime").JSX.Element;
24
30
  declare const dateFormats: {
@@ -16,7 +16,7 @@ const utils_1 = require("../utils");
16
16
  const defaultTestId_1 = require("../utils/defaultTestId");
17
17
  require("./DateField.css");
18
18
  function DateField(props) {
19
- const { label, disabled, required, value, onChange, onFocus, onBlur, errorMsg, helperText, inlineLabel = false, readOnly = false, format = "short", iconLeft = false, ...others } = props;
19
+ const { label, disabled, required, value, onChange, onFocus, onBlur, errorMsg, helperText, inlineLabel = false, readOnly = false, format = "short", iconLeft = false, disabledDays, ...others } = props;
20
20
  const inputRef = (0, react_1.useRef)(null);
21
21
  const inputWrapRef = (0, react_1.useRef)(null);
22
22
  const buttonRef = (0, react_1.useRef)(null);
@@ -123,7 +123,7 @@ function DateField(props) {
123
123
  }, 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: { ...overlayProps, ...positionProps }, onClose: state.close, isOpen: state.isOpen }, { children: (0, jsx_runtime_1.jsx)(DatePickerOverlay_1.DatePickerOverlay, Object.assign({ state: state, value: value, positionProps: positionProps, onChange: (d) => {
124
124
  setInputValue(formatDate(d, dateFormat));
125
125
  onChange(d);
126
- } }, tid.datePicker), void 0) }), void 0))] }, void 0));
126
+ }, disabledDays: disabledDays }, tid.datePicker), void 0) }), void 0))] }, void 0));
127
127
  }
128
128
  exports.DateField = DateField;
129
129
  function formatDate(date, format) {
@@ -24,7 +24,7 @@ function SelectField(props) {
24
24
  },
25
25
  // Read Only does not apply to `select` fields, instead we'll add in disabled for tests to verify.
26
26
  disabled: !!(disabled || readOnly), "data-error": !!errorMsg, "data-errormsg": errorMsg, "data-readonly": readOnly }, { children: [(0, jsx_runtime_1.jsx)("option", { disabled: true, value: "" }, void 0), options.map((option, i) => {
27
- return ((0, jsx_runtime_1.jsx)("option", Object.assign({ value: `${getOptionValue(option)}`, disabled: disabledOptions.includes(getOptionValue(option).toString()) }, { children: getOptionLabel(option) }), i));
27
+ return ((0, jsx_runtime_1.jsx)("option", Object.assign({ value: `${getOptionValue(option)}`, disabled: disabledOptions.includes(getOptionValue(option)) }, { children: getOptionLabel(option) }), i));
28
28
  })] }), void 0));
29
29
  }
30
30
  exports.SelectField = SelectField;
@@ -1,10 +1,12 @@
1
1
  import React from "react";
2
+ import { Modifier } from "react-day-picker";
2
3
  import { OverlayTriggerState } from "react-stately";
3
4
  interface DatePickerOverlayProps {
4
5
  value: Date | undefined;
5
6
  state: OverlayTriggerState;
6
7
  positionProps: React.HTMLAttributes<Element>;
7
8
  onChange: (value: Date) => void;
9
+ disabledDays: Modifier;
8
10
  }
9
11
  export declare function DatePickerOverlay(props: DatePickerOverlayProps): import("@emotion/react/jsx-runtime").JSX.Element;
10
12
  export {};
@@ -11,7 +11,7 @@ const Css_1 = require("../../Css");
11
11
  const utils_1 = require("../../utils");
12
12
  function DatePickerOverlay(props) {
13
13
  var _a;
14
- const { value, state, positionProps, onChange } = props;
14
+ const { value, state, positionProps, onChange, disabledDays } = props;
15
15
  // We define some spacing between the Calendar overlay and the trigger element, and depending on where the overlay renders (above or below) we need to adjust the spacing.
16
16
  // We can determine if the position was flipped based on what style is defined, `top` (for positioned below the trigger), and `bottom` (for above the trigger).
17
17
  // The above assumption regarding `top` and `bottom` is true as long as we use `bottom` as our default `OverlayPosition.placement` (set in DateField).
@@ -35,11 +35,17 @@ function DatePickerOverlay(props) {
35
35
  "& .DayPicker-Day:active": Css_1.Css.bgGray400.$,
36
36
  // Make the month title, i.e. "May 2021", match figma; pyPx nudge matches the NavbarElement nudging
37
37
  "& .DayPicker-Caption > div": Css_1.Css.base.pyPx(2).$,
38
- } }, tid, { children: (0, jsx_runtime_1.jsx)(react_day_picker_1.default, { navbarElement: NavbarElement, weekdayElement: Weekday, selectedDays: [value], initialMonth: value !== null && value !== void 0 ? value : new Date(), onDayClick: (day) => {
38
+ // For days that are disabled via `disabledDays`,
39
+ "& .DayPicker-Day--disabled": Css_1.Css.cursorNotAllowed.$,
40
+ // Override `.DayPicker-Day:active` background when the day is disabled
41
+ "& .DayPicker-Day--disabled:active": Css_1.Css.bgWhite.$,
42
+ } }, tid, { children: (0, jsx_runtime_1.jsx)(react_day_picker_1.default, { navbarElement: NavbarElement, weekdayElement: Weekday, selectedDays: [value], initialMonth: value !== null && value !== void 0 ? value : new Date(), onDayClick: (day, modifiers) => {
43
+ if (modifiers.disabled)
44
+ return;
39
45
  // Set the day value, and close the picker.
40
46
  onChange(day);
41
47
  state.close();
42
- } }, void 0) }), void 0));
48
+ }, disabledDays: disabledDays }, void 0) }), void 0));
43
49
  }
44
50
  exports.DatePickerOverlay = DatePickerOverlay;
45
51
  /** Customize the prev/next button to be our SVG icons. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.96.0",
3
+ "version": "2.97.0",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -48,7 +48,7 @@
48
48
  "react-router": "^5.2.0",
49
49
  "react-router-dom": "^5.2.0",
50
50
  "react-stately": "^3.9.0",
51
- "react-virtuoso": "^1.9.0",
51
+ "react-virtuoso": "^2.3.1",
52
52
  "tinycolor2": "^1.4.2",
53
53
  "tributejs": "^5.1.3",
54
54
  "trix": "^1.3.1",