@homebound/beam 3.62.0 → 3.63.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.
package/dist/index.d.cts CHANGED
@@ -10063,6 +10063,8 @@ type FormSectionLayoutProps = {
10063
10063
  description?: ReactNode;
10064
10064
  /** Rendered top-right of the title row, e.g. a "Save draft" button. */
10065
10065
  actions?: ButtonProps[];
10066
+ /** Rendered before form sections. Useful in forms that only need the main form title, or for form fields that shape the context of a form beforehand. */
10067
+ initialFields?: ReactNode;
10066
10068
  sections: FormSectionProps[];
10067
10069
  };
10068
10070
  /** Centered (720px) width/column shell for a form built out of `FormSection`s — e.g. as a `WorkflowLayoutStep`'s `content`. */
package/dist/index.d.ts CHANGED
@@ -10063,6 +10063,8 @@ type FormSectionLayoutProps = {
10063
10063
  description?: ReactNode;
10064
10064
  /** Rendered top-right of the title row, e.g. a "Save draft" button. */
10065
10065
  actions?: ButtonProps[];
10066
+ /** Rendered before form sections. Useful in forms that only need the main form title, or for form fields that shape the context of a form beforehand. */
10067
+ initialFields?: ReactNode;
10066
10068
  sections: FormSectionProps[];
10067
10069
  };
10068
10070
  /** Centered (720px) width/column shell for a form built out of `FormSection`s — e.g. as a `WorkflowLayoutStep`'s `content`. */
package/dist/index.js CHANGED
@@ -10784,6 +10784,10 @@ function MenuItemImpl(props) {
10784
10784
  isHovered
10785
10785
  } = useHover7({});
10786
10786
  const tid = useTestIds(props);
10787
+ const openInNewTabRef = useRef15(false);
10788
+ function captureModifiers(e) {
10789
+ openInNewTabRef.current = wantsNewTab(e);
10790
+ }
10787
10791
  const {
10788
10792
  menuItemProps
10789
10793
  } = useMenuItem({
@@ -10797,7 +10801,7 @@ function MenuItemImpl(props) {
10797
10801
  onClick
10798
10802
  } = menuItem;
10799
10803
  if (typeof onClick === "string") {
10800
- if (isAbsoluteUrl(onClick)) {
10804
+ if (isAbsoluteUrl(onClick) || openInNewTabRef.current) {
10801
10805
  window.open(onClick, "_blank").opener = null;
10802
10806
  return;
10803
10807
  }
@@ -10819,55 +10823,68 @@ function MenuItemImpl(props) {
10819
10823
  const isDisabled = Boolean(disabled);
10820
10824
  const isSelected = state.selectionManager.selectedKeys.has(label);
10821
10825
  const isFocused = state.selectionManager.focusedKey === item.key;
10822
- return /* @__PURE__ */ jsx43("li", { ...menuItemProps, ...hoverProps, ref, ...trussProps27({
10823
- ...{
10824
- display: "df",
10825
- alignItems: "aic",
10826
- paddingTop: "pt1",
10827
- paddingBottom: "pb1",
10828
- paddingLeft: "pl2",
10829
- paddingRight: "pr2",
10830
- cursor: "cursorPointer",
10831
- outline: "outline0",
10832
- minHeight: "mh_42px",
10833
- fontWeight: "fw4",
10834
- fontSize: "fz_14px",
10835
- lineHeight: "lh_20px"
10836
- },
10837
- ...menuItem.hasDivider ? {
10838
- borderBottomStyle: "bbs_solid",
10839
- borderBottomWidth: "bbw_1px",
10840
- borderColor: "bcGray700"
10841
- } : {},
10842
- ...!isDisabled && isHovered ? {
10843
- backgroundColor: ["bgColor_var", {
10844
- "--backgroundColor": "var(--b-menu-item-bg-hover)"
10845
- }]
10846
- } : {},
10847
- ...isFocused ? {
10848
- boxShadow: ["boxShadow_var", {
10849
- "--boxShadow": maybeCssVar18(`inset 0 0 0 1px var(${"--b-focus-ring-inset" /* FocusRingInset */})`)
10850
- }]
10851
- } : {},
10852
- ...isDisabled ? {
10853
- color: ["color_var", {
10854
- "--color": "var(--b-text-disabled)"
10855
- }],
10856
- cursor: "cursorNotAllowed"
10857
- } : {},
10858
- ...destructive ? {
10859
- color: ["color_var", {
10860
- "--color": "var(--b-danger)"
10861
- }]
10862
- } : {},
10863
- ...isSelected ? {
10864
- fontWeight: "fw5"
10865
- } : {}
10866
- }), ...tid[defaultTestId(menuItem.label)], children: maybeTooltip({
10867
- title: resolveTooltip(disabled),
10868
- placement: "right",
10869
- children: renderMenuItem(menuItem, isSelected, isDisabled)
10870
- }) });
10826
+ return /* @__PURE__ */ jsx43(
10827
+ "li",
10828
+ {
10829
+ ...menuItemProps,
10830
+ ...hoverProps,
10831
+ onPointerDownCapture: captureModifiers,
10832
+ onKeyDownCapture: captureModifiers,
10833
+ onClickCapture: captureModifiers,
10834
+ ref,
10835
+ ...trussProps27({
10836
+ ...{
10837
+ display: "df",
10838
+ alignItems: "aic",
10839
+ paddingTop: "pt1",
10840
+ paddingBottom: "pb1",
10841
+ paddingLeft: "pl2",
10842
+ paddingRight: "pr2",
10843
+ cursor: "cursorPointer",
10844
+ outline: "outline0",
10845
+ minHeight: "mh_42px",
10846
+ fontWeight: "fw4",
10847
+ fontSize: "fz_14px",
10848
+ lineHeight: "lh_20px"
10849
+ },
10850
+ ...menuItem.hasDivider ? {
10851
+ borderBottomStyle: "bbs_solid",
10852
+ borderBottomWidth: "bbw_1px",
10853
+ borderColor: "bcGray700"
10854
+ } : {},
10855
+ ...!isDisabled && isHovered ? {
10856
+ backgroundColor: ["bgColor_var", {
10857
+ "--backgroundColor": "var(--b-menu-item-bg-hover)"
10858
+ }]
10859
+ } : {},
10860
+ ...isFocused ? {
10861
+ boxShadow: ["boxShadow_var", {
10862
+ "--boxShadow": maybeCssVar18(`inset 0 0 0 1px var(${"--b-focus-ring-inset" /* FocusRingInset */})`)
10863
+ }]
10864
+ } : {},
10865
+ ...isDisabled ? {
10866
+ color: ["color_var", {
10867
+ "--color": "var(--b-text-disabled)"
10868
+ }],
10869
+ cursor: "cursorNotAllowed"
10870
+ } : {},
10871
+ ...destructive ? {
10872
+ color: ["color_var", {
10873
+ "--color": "var(--b-danger)"
10874
+ }]
10875
+ } : {},
10876
+ ...isSelected ? {
10877
+ fontWeight: "fw5"
10878
+ } : {}
10879
+ }),
10880
+ ...tid[defaultTestId(menuItem.label)],
10881
+ children: maybeTooltip({
10882
+ title: resolveTooltip(disabled),
10883
+ placement: "right",
10884
+ children: renderMenuItem(menuItem, isSelected, isDisabled)
10885
+ })
10886
+ }
10887
+ );
10871
10888
  }
10872
10889
  function renderMenuItem(menuItem, isSelected, isDisabled) {
10873
10890
  return /* @__PURE__ */ jsxs27("div", { className: "df w100 aic jcsb gap2", children: [
@@ -10911,6 +10928,9 @@ function maybeWrapInLink(onClick, content, disabled) {
10911
10928
  /* @__PURE__ */ jsx43("span", { className: "fs0 ml2", children: /* @__PURE__ */ jsx43(Icon, { icon: "linkExternal" }) })
10912
10929
  ] }) : /* @__PURE__ */ jsx43(Link3, { className: "navLink", to: onClick, children: content });
10913
10930
  }
10931
+ function wantsNewTab(e) {
10932
+ return e.metaKey || e.ctrlKey || e.shiftKey;
10933
+ }
10914
10934
  function isIconMenuItem(item) {
10915
10935
  return item && typeof item === "object" && "icon" in item;
10916
10936
  }
@@ -11762,7 +11782,6 @@ function TreeOption(props) {
11762
11782
  const {
11763
11783
  item,
11764
11784
  state,
11765
- allowCollapsing = true,
11766
11785
  disabledReason
11767
11786
  } = props;
11768
11787
  const leveledOption = item.value;
@@ -11791,7 +11810,7 @@ function TreeOption(props) {
11791
11810
  shouldFocusOnHover: false
11792
11811
  }, state, ref);
11793
11812
  const isGroup = groupKeys.includes(item.key);
11794
- const canCollapse = allowCollapsing && !!option.children?.length;
11813
+ const canCollapse = !!option.children?.length;
11795
11814
  function toggleCollapsed() {
11796
11815
  if (!canCollapse) return;
11797
11816
  setCollapsedKeys((prevKeys) => collapsedKeys.includes(item.key) ? prevKeys.filter((k) => k !== item.key) : [...prevKeys, item.key]);
@@ -11849,7 +11868,7 @@ function TreeOption(props) {
11849
11868
  ...isFocused && !isGroup ? listItemStyles.focus : {},
11850
11869
  ...isDisabled && !isGroup ? listItemStyles.disabled : {}
11851
11870
  }), children: [
11852
- allowCollapsing && /* @__PURE__ */ jsx52("span", { className: "w_18px fs0 df aic", children: canCollapse && /* @__PURE__ */ jsx52("button", { onClick: (e) => {
11871
+ /* @__PURE__ */ jsx52("span", { className: "w_18px fs0 df aic", children: canCollapse && /* @__PURE__ */ jsx52("button", { onClick: (e) => {
11853
11872
  e.preventDefault();
11854
11873
  e.stopPropagation();
11855
11874
  toggleCollapsed();
@@ -11908,16 +11927,7 @@ function isLeveledNode(node) {
11908
11927
  // src/inputs/internal/VirtualizedOptions.tsx
11909
11928
  import { jsx as jsx53 } from "react/jsx-runtime";
11910
11929
  function VirtualizedOptions(props) {
11911
- const {
11912
- state,
11913
- items,
11914
- onListHeightChange,
11915
- scrollOnFocus,
11916
- loading,
11917
- disabledOptionsWithReasons,
11918
- isTree,
11919
- allowCollapsing
11920
- } = props;
11930
+ const { state, items, onListHeightChange, scrollOnFocus, loading, disabledOptionsWithReasons, isTree } = props;
11921
11931
  const virtuosoRef = useRef21(null);
11922
11932
  const focusedKey = state.selectionManager.focusedKey;
11923
11933
  const focusedItem = focusedKey != null ? state.collection.getItem(focusedKey) : null;
@@ -11958,7 +11968,6 @@ function VirtualizedOptions(props) {
11958
11968
  {
11959
11969
  item,
11960
11970
  state,
11961
- allowCollapsing,
11962
11971
  disabledReason: disabledOptionsWithReasons[item.key]
11963
11972
  },
11964
11973
  item.key
@@ -12057,8 +12066,7 @@ function ListBox(props) {
12057
12066
  horizontalLayout = false,
12058
12067
  loading,
12059
12068
  disabledOptionsWithReasons = {},
12060
- isTree,
12061
- allowCollapsing
12069
+ isTree
12062
12070
  } = props;
12063
12071
  const {
12064
12072
  listBoxProps
@@ -12136,8 +12144,7 @@ function ListBox(props) {
12136
12144
  scrollOnFocus: props.shouldUseVirtualFocus,
12137
12145
  loading,
12138
12146
  disabledOptionsWithReasons,
12139
- isTree,
12140
- allowCollapsing
12147
+ isTree
12141
12148
  }
12142
12149
  ) })
12143
12150
  ] });
@@ -12230,7 +12237,8 @@ function TreeSelectFieldBase(props) {
12230
12237
  sensitivity: "base"
12231
12238
  });
12232
12239
  const {
12233
- collapsedKeys
12240
+ collapsedKeys,
12241
+ setCollapsedKeys
12234
12242
  } = useTreeSelectFieldProvider();
12235
12243
  const groupKeys = useMemo16(() => _groupOptions?.map((option) => valueToKey(option)) ?? [], [_groupOptions]);
12236
12244
  const groupKeySet = useMemo16(() => new Set(groupKeys), [groupKeys]);
@@ -12272,8 +12280,7 @@ function TreeSelectFieldBase(props) {
12272
12280
  selectedChipOptions: selectedChipState.options,
12273
12281
  allOptions: initialOptions,
12274
12282
  selectedOptionsLabels: selectedChipState.labels,
12275
- optionsLoading: false,
12276
- allowCollapsing: true
12283
+ optionsLoading: false
12277
12284
  };
12278
12285
  }, [initialOptions, values, chipDisplay, getOptionLabel, isReadOnly, nothingSelectedText, getOptionValue, groupKeySet]);
12279
12286
  const [fieldState, setFieldState] = useState18(() => initTreeFieldState());
@@ -12295,14 +12302,26 @@ function TreeSelectFieldBase(props) {
12295
12302
  setFieldState(initTreeFieldState());
12296
12303
  }
12297
12304
  }, [getOptionValue, initTreeFieldState, values]);
12305
+ const preSearchCollapsedKeys = useRef23(void 0);
12306
+ useEffect13(() => {
12307
+ if (fieldState.searchValue) {
12308
+ if (preSearchCollapsedKeys.current === void 0) {
12309
+ preSearchCollapsedKeys.current = collapsedKeys;
12310
+ if (collapsedKeys.length > 0) setCollapsedKeys([]);
12311
+ }
12312
+ } else if (preSearchCollapsedKeys.current !== void 0) {
12313
+ const keys = preSearchCollapsedKeys.current;
12314
+ preSearchCollapsedKeys.current = void 0;
12315
+ setCollapsedKeys(keys);
12316
+ }
12317
+ }, [fieldState.searchValue, collapsedKeys, setCollapsedKeys]);
12298
12318
  const filteredOptions = useMemo16(() => getFilteredOptions(fieldState.allOptions, fieldState.searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue), [fieldState.allOptions, fieldState.searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue]);
12299
12319
  const onInputChange = useCallback9((inputValue) => {
12300
12320
  setFieldState((prevState) => {
12301
12321
  return {
12302
12322
  ...prevState,
12303
12323
  inputValue,
12304
- searchValue: inputValue.length === 0 ? void 0 : inputValue,
12305
- allowCollapsing: inputValue.length === 0
12324
+ searchValue: inputValue.length === 0 ? void 0 : inputValue
12306
12325
  };
12307
12326
  });
12308
12327
  }, []);
@@ -12330,8 +12349,7 @@ function TreeSelectFieldBase(props) {
12330
12349
  setFieldState((prevState) => ({
12331
12350
  ...prevState,
12332
12351
  inputValue: "",
12333
- searchValue: void 0,
12334
- allowCollapsing: true
12352
+ searchValue: void 0
12335
12353
  }));
12336
12354
  }
12337
12355
  }
@@ -12366,9 +12384,8 @@ function TreeSelectFieldBase(props) {
12366
12384
  if (newKeys.size === 0) {
12367
12385
  setFieldState((prevState) => ({
12368
12386
  ...prevState,
12369
- inputValue: nothingSelectedText,
12370
- searchValue: void 0,
12371
- allowCollapsing: true,
12387
+ // Unselecting the last option shouldn't drop the search either
12388
+ inputValue: prevState.searchValue ?? nothingSelectedText,
12372
12389
  selectedKeys: [],
12373
12390
  selectedOptions: [],
12374
12391
  selectedChipOptions: [],
@@ -12442,9 +12459,9 @@ function TreeSelectFieldBase(props) {
12442
12459
  const selectedChipState = getSelectedChipState(fieldState.allOptions, selectedOptions, selectedKeys, chipDisplay, getOptionLabel, getOptionValue);
12443
12460
  setFieldState((prevState) => ({
12444
12461
  ...prevState,
12445
- // Since we reset the list of options upon selection changes, then set the `inputValue` to empty string to reflect that.
12446
- inputValue: "",
12447
- searchValue: void 0,
12462
+ // Keep any search in place, so picking several options out of the same filtered list doesn't
12463
+ // make the user retype it; when they're not searching the input stays empty as before.
12464
+ inputValue: prevState.searchValue ?? "",
12448
12465
  selectedKeys: [...selectedKeys],
12449
12466
  selectedOptions,
12450
12467
  selectedChipOptions: selectedChipState.options,
@@ -12476,8 +12493,7 @@ function TreeSelectFieldBase(props) {
12476
12493
  setFieldState((prevState) => ({
12477
12494
  ...prevState,
12478
12495
  inputValue: selectedOptions.length === 1 ? getOptionLabel(selectedOptions[0]) : selectedOptions.length === 0 ? nothingSelectedText : "",
12479
- searchValue: void 0,
12480
- allowCollapsing: true
12496
+ searchValue: void 0
12481
12497
  }));
12482
12498
  }
12483
12499
  }
@@ -12547,17 +12563,16 @@ function TreeSelectFieldBase(props) {
12547
12563
  onClose: () => state.toggle(),
12548
12564
  isOpen: state.isOpen,
12549
12565
  minWidth: 320,
12550
- children: /* @__PURE__ */ jsx57(ListBox, { ...listBoxProps, positionProps, state, listBoxRef, selectedOptions: fieldState.selectedChipOptions, getOptionLabel, getOptionValue: (o) => valueToKey(getOptionValue(o)), horizontalLayout: labelStyle === "left", loading: fieldState.optionsLoading, allowCollapsing: fieldState.allowCollapsing, disabledOptionsWithReasons, isTree: true })
12566
+ children: /* @__PURE__ */ jsx57(ListBox, { ...listBoxProps, positionProps, state, listBoxRef, selectedOptions: fieldState.selectedChipOptions, getOptionLabel, getOptionValue: (o) => valueToKey(getOptionValue(o)), horizontalLayout: labelStyle === "left", loading: fieldState.optionsLoading, disabledOptionsWithReasons, isTree: true })
12551
12567
  }
12552
12568
  )
12553
12569
  ] });
12554
12570
  }
12555
- function levelOptions(o, level, filtering, collapsedKeys, getOptionValue) {
12556
- const actualLevel = filtering ? 0 : level;
12571
+ function levelOptions(o, level, collapsedKeys, getOptionValue) {
12557
12572
  return [
12558
- [o, actualLevel],
12559
- // Flat map the children if the parent is not collapsed or if we are filtering (for the search results)
12560
- ...o.children?.length && (!collapsedKeys.includes(valueToKey(getOptionValue(o))) || filtering) ? o.children.flatMap((oc) => levelOptions(oc, actualLevel + 1, filtering, collapsedKeys, getOptionValue)) : []
12573
+ [o, level],
12574
+ // Flat map the children if the parent is not collapsed
12575
+ ...o.children?.length && !collapsedKeys.includes(valueToKey(getOptionValue(o))) ? o.children.flatMap((oc) => levelOptions(oc, level + 1, collapsedKeys, getOptionValue)) : []
12561
12576
  ];
12562
12577
  }
12563
12578
  function getTopLevelSelections(o, selectedKeys, getOptionValue) {
@@ -12566,7 +12581,16 @@ function getTopLevelSelections(o, selectedKeys, getOptionValue) {
12566
12581
  return [];
12567
12582
  }
12568
12583
  function getFilteredOptions(allOptions, searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue) {
12569
- return allOptions.flatMap((option) => levelOptions(option, 0, !!searchValue, collapsedKeys, getOptionValue).filter(([nestedOption]) => searchValue ? contains(getOptionLabel(nestedOption), searchValue) : true));
12584
+ if (!searchValue) return allOptions.flatMap((option) => levelOptions(option, 0, collapsedKeys, getOptionValue));
12585
+ const search = searchValue;
12586
+ return allOptions.flatMap((option) => matchedOptions(option, 0, false));
12587
+ function matchedOptions(o, level, hasMatchedParent) {
12588
+ const isDirectlyMatched = contains(getOptionLabel(o), search);
12589
+ const children = o.children?.flatMap((oc) => matchedOptions(oc, level + 1, hasMatchedParent || isDirectlyMatched));
12590
+ if (!isDirectlyMatched && !hasMatchedParent && !children?.length) return [];
12591
+ const isCollapsed = collapsedKeys.includes(valueToKey(getOptionValue(o)));
12592
+ return isCollapsed ? [[o, level]] : [[o, level], ...children ?? []];
12593
+ }
12570
12594
  }
12571
12595
  function isOptionFullySelected(option, selectedKeys, disabledKeys, groupKeys, getOptionValue) {
12572
12596
  const key = valueToKey(getOptionValue(option));
@@ -25315,6 +25339,7 @@ function FormSectionLayout(props) {
25315
25339
  title,
25316
25340
  description,
25317
25341
  actions,
25342
+ initialFields,
25318
25343
  sections
25319
25344
  } = props;
25320
25345
  const tid = useTestIds(props, "formSectionLayout");
@@ -25333,6 +25358,7 @@ function FormSectionLayout(props) {
25333
25358
  ] }),
25334
25359
  actions && /* @__PURE__ */ jsx207("div", { className: "df gap1 fs0", ...tid.actions, children: actions.map((action) => /* @__PURE__ */ jsx207(Button, { ...action }, `${action.label}`)) })
25335
25360
  ] }),
25361
+ initialFields,
25336
25362
  /* @__PURE__ */ jsx207("div", { className: "df fdc gap6", children: sections.map((section, i) => /* @__PURE__ */ jsx207(FormSection, { ...section }, defaultTestId(section.title) || i)) })
25337
25363
  ] });
25338
25364
  }