@homebound/beam 3.1.0-alpha.2 → 3.2.0-alpha.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
@@ -6921,14 +6921,16 @@ type TreeSelectFieldProps<O, V extends Value> = {
6921
6921
  * @default root */
6922
6922
  chipDisplay?: "all" | "leaf" | "root";
6923
6923
  disabledOptions?: V[];
6924
+ groupOptions?: V[];
6924
6925
  } & BeamFocusableProps & PresentationFieldProps;
6925
6926
  declare function TreeSelectField<O, V extends Value>(props: TreeSelectFieldProps<O, V>): JSX.Element;
6926
6927
  declare function TreeSelectField<O extends HasIdAndName<V>, V extends Value>(props: Optional<TreeSelectFieldProps<O, V>, "getOptionValue" | "getOptionLabel">): JSX.Element;
6927
- declare function useTreeSelectFieldProvider<O, V extends Value>(): CollapsedChildrenState<any, any>;
6928
+ declare function useTreeSelectFieldProvider<O, V extends Value>(): CollapsedChildrenState<O, V>;
6928
6929
  type CollapsedChildrenState<O, V extends Value> = {
6929
6930
  collapsedKeys: Key$1[];
6930
6931
  setCollapsedKeys: Dispatch<SetStateAction<Key$1[]>>;
6931
6932
  getOptionValue: (opt: O) => V;
6933
+ groupKeys: Key$1[];
6932
6934
  };
6933
6935
  declare const CollapsedContext: React__default.Context<CollapsedChildrenState<any, any>>;
6934
6936
 
package/dist/index.d.ts CHANGED
@@ -6921,14 +6921,16 @@ type TreeSelectFieldProps<O, V extends Value> = {
6921
6921
  * @default root */
6922
6922
  chipDisplay?: "all" | "leaf" | "root";
6923
6923
  disabledOptions?: V[];
6924
+ groupOptions?: V[];
6924
6925
  } & BeamFocusableProps & PresentationFieldProps;
6925
6926
  declare function TreeSelectField<O, V extends Value>(props: TreeSelectFieldProps<O, V>): JSX.Element;
6926
6927
  declare function TreeSelectField<O extends HasIdAndName<V>, V extends Value>(props: Optional<TreeSelectFieldProps<O, V>, "getOptionValue" | "getOptionLabel">): JSX.Element;
6927
- declare function useTreeSelectFieldProvider<O, V extends Value>(): CollapsedChildrenState<any, any>;
6928
+ declare function useTreeSelectFieldProvider<O, V extends Value>(): CollapsedChildrenState<O, V>;
6928
6929
  type CollapsedChildrenState<O, V extends Value> = {
6929
6930
  collapsedKeys: Key$1[];
6930
6931
  setCollapsedKeys: Dispatch<SetStateAction<Key$1[]>>;
6931
6932
  getOptionValue: (opt: O) => V;
6933
+ groupKeys: Key$1[];
6932
6934
  };
6933
6935
  declare const CollapsedContext: React__default.Context<CollapsedChildrenState<any, any>>;
6934
6936
 
package/dist/index.js CHANGED
@@ -5559,6 +5559,7 @@ function dehydrateFilter(filterImpls, value) {
5559
5559
  const filter = filterImpls[key];
5560
5560
  return [
5561
5561
  key,
5562
+ // Let each filter own serialization so persisted state stays stable for non-plain JSON values like PlainDate.
5562
5563
  filter?.dehydrate ? filter.dehydrate(rawValue) : rawValue
5563
5564
  ];
5564
5565
  })
@@ -10715,7 +10716,8 @@ function TreeOption(props) {
10715
10716
  const {
10716
10717
  collapsedKeys,
10717
10718
  setCollapsedKeys,
10718
- getOptionValue
10719
+ getOptionValue,
10720
+ groupKeys
10719
10721
  } = useTreeSelectFieldProvider();
10720
10722
  const {
10721
10723
  optionProps,
@@ -10727,6 +10729,12 @@ function TreeOption(props) {
10727
10729
  shouldSelectOnPressUp: true,
10728
10730
  shouldFocusOnHover: false
10729
10731
  }, state, ref);
10732
+ const isGroup = groupKeys.includes(item.key);
10733
+ const canCollapse = allowCollapsing && !!option.children?.length;
10734
+ function toggleCollapsed() {
10735
+ if (!canCollapse) return;
10736
+ setCollapsedKeys((prevKeys) => collapsedKeys.includes(item.key) ? prevKeys.filter((k) => k !== item.key) : [...prevKeys, item.key]);
10737
+ }
10730
10738
  const isIndeterminate = !isSelected && option.children?.some((o) => hasSelectedChildren(o, state, getOptionValue));
10731
10739
  const listItemStyles = {
10732
10740
  item: {
@@ -10754,7 +10762,12 @@ function TreeOption(props) {
10754
10762
  }]
10755
10763
  }
10756
10764
  };
10757
- return /* @__PURE__ */ jsxs33("li", { ...hoverProps, ...trussProps34({
10765
+ return /* @__PURE__ */ jsxs33("li", { ...hoverProps, onClick: (e) => {
10766
+ if (!isGroup) return;
10767
+ e.preventDefault();
10768
+ e.stopPropagation();
10769
+ toggleCollapsed();
10770
+ }, ...trussProps34({
10758
10771
  ...{
10759
10772
  display: "df",
10760
10773
  alignItems: "aic",
@@ -10771,18 +10784,18 @@ function TreeOption(props) {
10771
10784
  lineHeight: "lh_20px"
10772
10785
  },
10773
10786
  ...listItemStyles.item,
10774
- ...isHovered && !isDisabled ? listItemStyles.hover : {},
10775
- ...isFocused ? listItemStyles.focus : {},
10776
- ...isDisabled ? listItemStyles.disabled : {}
10787
+ ...isHovered && (!isDisabled || isGroup) ? listItemStyles.hover : {},
10788
+ ...isFocused && !isGroup ? listItemStyles.focus : {},
10789
+ ...isDisabled && !isGroup ? listItemStyles.disabled : {}
10777
10790
  }), children: [
10778
- allowCollapsing && /* @__PURE__ */ jsx49("span", { className: "w_18px fs0 df aic", children: option.children && option.children?.length > 0 && /* @__PURE__ */ jsx49("button", { onClick: (e) => {
10791
+ allowCollapsing && /* @__PURE__ */ jsx49("span", { className: "w_18px fs0 df aic", children: canCollapse && /* @__PURE__ */ jsx49("button", { onClick: (e) => {
10779
10792
  e.preventDefault();
10780
10793
  e.stopPropagation();
10781
- setCollapsedKeys((prevKeys) => collapsedKeys.includes(item.key) ? prevKeys.filter((k) => k !== item.key) : [...prevKeys, item.key]);
10794
+ toggleCollapsed();
10782
10795
  return false;
10783
10796
  }, className: "br4 h_16px w_16px bgTransparent h_bgGray300", ...tid[`collapseToggle_${item.key}`], children: /* @__PURE__ */ jsx49(Icon, { icon: collapsedKeys.includes(item.key) ? "triangleRight" : "triangleDown", inc: 2 }) }) }),
10784
10797
  /* @__PURE__ */ jsxs33("span", { className: "df aic gap1 h100 fg1 pt1 pb1 pr2", ref, ...optionProps, "data-label": item.textValue, children: [
10785
- /* @__PURE__ */ jsx49(StyledCheckbox, { isDisabled, isSelected, isIndeterminate, ...tid[item.key.toString()] }),
10798
+ !isGroup && /* @__PURE__ */ jsx49(StyledCheckbox, { isDisabled, isSelected, isIndeterminate, ...tid[item.key.toString()] }),
10786
10799
  /* @__PURE__ */ jsx49("div", { className: "pl1", children: item.rendered })
10787
10800
  ] })
10788
10801
  ] });
@@ -10865,9 +10878,14 @@ function VirtualizedOptions(props) {
10865
10878
  totalListHeightChanged: onListHeightChange,
10866
10879
  totalCount: items.length,
10867
10880
  ...process.env.NODE_ENV === "test" ? {
10868
- // We don't really need to set this, but it's handy for tests, which would
10869
- // otherwise render just 1 row. A better way to do this would be to jest.mock
10870
- // out Virtuoso with an impl that just rendered everything, but doing this for now.
10881
+ // In tests, we render all rows so assertions can see expands/async-loaded items. However,
10882
+ // the `initialItemCount` (next prop) is only applied on amount, so we set `key={items.length}`
10883
+ // to force a remount when our list changes -- and we only want/need this in tests, b/c otherwise
10884
+ // in production a Virtuoso remount causes visible flashing.
10885
+ key: items.length,
10886
+ // We don't really need to set this, but it's handy for tests, which would otherwise render
10887
+ // just 1 row. A better way to do this would be to jest.mock out Virtuoso with an impl that
10888
+ // just rendered everything, but doing this for now.
10871
10889
  initialItemCount: items.length
10872
10890
  } : {
10873
10891
  // Ensure the selected item is visible when the list renders
@@ -10907,8 +10925,7 @@ function VirtualizedOptions(props) {
10907
10925
  components: !loading ? {} : {
10908
10926
  Footer: typeof loading === "function" ? loading : () => /* @__PURE__ */ jsx50(LoadingDots, { contrast })
10909
10927
  }
10910
- },
10911
- items.length
10928
+ }
10912
10929
  );
10913
10930
  }
10914
10931
 
@@ -11081,6 +11098,7 @@ function TreeSelectField(props) {
11081
11098
  ...otherProps
11082
11099
  } = props;
11083
11100
  const [collapsedKeys, setCollapsedKeys] = useState17([]);
11101
+ const groupKeys = useMemo15(() => props.groupOptions?.map((option) => valueToKey(option)) ?? [], [props.groupOptions]);
11084
11102
  useEffect13(() => {
11085
11103
  setCollapsedKeys(!Array.isArray(options) ? [] : defaultCollapsed ? options.map((o) => getOptionValue(o)) : options.flatMap(flattenOptions).filter((o) => o.defaultCollapsed).map((o) => getOptionValue(o)));
11086
11104
  }, [options, defaultCollapsed]);
@@ -11088,11 +11106,12 @@ function TreeSelectField(props) {
11088
11106
  () => ({
11089
11107
  collapsedKeys,
11090
11108
  setCollapsedKeys,
11091
- getOptionValue
11109
+ getOptionValue,
11110
+ groupKeys
11092
11111
  }),
11093
11112
  // TODO: validate this eslint-disable. It was automatically ignored as part of https://app.shortcut.com/homebound-team/story/40033/enable-react-hooks-exhaustive-deps-for-react-projects
11094
11113
  // eslint-disable-next-line react-hooks/exhaustive-deps
11095
- [collapsedKeys, setCollapsedKeys]
11114
+ [collapsedKeys, setCollapsedKeys, groupKeys]
11096
11115
  );
11097
11116
  return /* @__PURE__ */ jsx54(CollapsedContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx54(TreeSelectFieldBase, { ...otherProps, options, getOptionLabel, getOptionValue, values, onSelect: ({
11098
11117
  all,
@@ -11113,7 +11132,8 @@ var CollapsedContext = React9.createContext({
11113
11132
  collapsedKeys: [],
11114
11133
  setCollapsedKeys: () => {
11115
11134
  },
11116
- getOptionValue: () => ({})
11135
+ getOptionValue: () => ({}),
11136
+ groupKeys: []
11117
11137
  });
11118
11138
  function TreeSelectFieldBase(props) {
11119
11139
  const {
@@ -11132,13 +11152,15 @@ function TreeSelectFieldBase(props) {
11132
11152
  contrast = false,
11133
11153
  nothingSelectedText = "",
11134
11154
  onSelect,
11135
- defaultCollapsed = false,
11155
+ defaultCollapsed: _defaultCollapsed = false,
11136
11156
  placeholder,
11137
11157
  fullWidth = fieldProps?.fullWidth ?? false,
11138
11158
  chipDisplay = "root",
11139
11159
  disabledOptions,
11160
+ groupOptions: _groupOptions,
11140
11161
  ...otherProps
11141
11162
  } = props;
11163
+ void _defaultCollapsed;
11142
11164
  const isDisabled = !!disabled;
11143
11165
  const isReadOnly = !!readOnly;
11144
11166
  const initialOptions = Array.isArray(options) ? options : options.current;
@@ -11150,7 +11172,10 @@ function TreeSelectFieldBase(props) {
11150
11172
  const {
11151
11173
  collapsedKeys
11152
11174
  } = useTreeSelectFieldProvider();
11175
+ const groupKeys = useMemo15(() => _groupOptions?.map((option) => valueToKey(option)) ?? [], [_groupOptions]);
11176
+ const groupKeySet = useMemo15(() => new Set(groupKeys), [groupKeys]);
11153
11177
  const disabledOptionsWithReasons = Object.fromEntries(disabledOptions?.map(disabledOptionToKeyedTuple) ?? []);
11178
+ const disabledKeys = [.../* @__PURE__ */ new Set([...Object.keys(disabledOptionsWithReasons), ...groupKeys])];
11154
11179
  const initTreeFieldState = useCallback8(() => {
11155
11180
  const selectedKeys = new Set(values?.flatMap((v) => {
11156
11181
  const foundOptions = findOptions(initialOptions, valueToKey(v), getOptionValue);
@@ -11159,14 +11184,16 @@ function TreeSelectFieldBase(props) {
11159
11184
  }) => selectOptionAndAllChildren(option));
11160
11185
  }));
11161
11186
  function selectOptionAndAllChildren(maybeParent) {
11162
- return [valueToKey(getOptionValue(maybeParent)), ...maybeParent.children?.flatMap(selectOptionAndAllChildren) ?? []];
11187
+ const key = valueToKey(getOptionValue(maybeParent));
11188
+ return [...groupKeySet.has(key) ? [] : [key], ...maybeParent.children?.flatMap(selectOptionAndAllChildren) ?? []];
11163
11189
  }
11164
11190
  function areAllChildrenSelected(maybeParent) {
11165
- const isSelected = selectedKeys.has(valueToKey(getOptionValue(maybeParent)));
11191
+ const key = valueToKey(getOptionValue(maybeParent));
11192
+ const isSelected = selectedKeys.has(key);
11166
11193
  if (isSelected || !maybeParent.children || maybeParent.children.length === 0) return isSelected;
11167
11194
  const areAllSelected = maybeParent.children.every(areAllChildrenSelected);
11168
- if (areAllSelected) {
11169
- selectedKeys.add(valueToKey(getOptionValue(maybeParent)));
11195
+ if (areAllSelected && !groupKeySet.has(key)) {
11196
+ selectedKeys.add(key);
11170
11197
  }
11171
11198
  return areAllSelected;
11172
11199
  }
@@ -11177,18 +11204,17 @@ function TreeSelectFieldBase(props) {
11177
11204
  return [maybeOption.option];
11178
11205
  });
11179
11206
  const selectedOptionsLabels = chipDisplay === "root" ? initialOptions.flatMap((o) => getTopLevelSelections(o, selectedKeys, getOptionValue)).map(getOptionLabel) : chipDisplay === "leaf" ? selectedOptions.filter((o) => !o.children || o.children.length === 0).map(getOptionLabel) : selectedOptions.map(getOptionLabel);
11180
- const filteredOptions = initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue));
11181
11207
  return {
11182
11208
  selectedKeys: [...selectedKeys],
11209
+ searchValue: void 0,
11183
11210
  inputValue: selectedOptions.length === 1 ? getOptionLabel([...selectedOptions][0]) : isReadOnly && selectedOptions.length > 0 ? selectedOptionsLabels.join(", ") : selectedOptions.length === 0 ? nothingSelectedText : "",
11184
- filteredOptions,
11185
11211
  selectedOptions,
11186
11212
  allOptions: initialOptions,
11187
11213
  selectedOptionsLabels,
11188
11214
  optionsLoading: false,
11189
11215
  allowCollapsing: true
11190
11216
  };
11191
- }, [initialOptions, values, chipDisplay, getOptionLabel, isReadOnly, nothingSelectedText, getOptionValue, collapsedKeys]);
11217
+ }, [initialOptions, values, chipDisplay, getOptionLabel, isReadOnly, nothingSelectedText, getOptionValue, groupKeySet]);
11192
11218
  const [fieldState, setFieldState] = useState17(() => initTreeFieldState());
11193
11219
  useEffect13(() => {
11194
11220
  if (Array.isArray(options)) {
@@ -11208,75 +11234,54 @@ function TreeSelectFieldBase(props) {
11208
11234
  setFieldState(initTreeFieldState());
11209
11235
  }
11210
11236
  }, [getOptionValue, initTreeFieldState, values]);
11211
- const reactToCollapse = useRef22(false);
11212
- useEffect13(
11213
- () => {
11214
- if (reactToCollapse.current) {
11215
- setFieldState(({
11216
- allOptions,
11217
- inputValue,
11218
- ...others
11219
- }) => ({
11220
- allOptions,
11221
- inputValue,
11222
- ...others,
11223
- filteredOptions: allOptions.flatMap((o) => levelOptions(o, 0, inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), inputValue)))
11224
- }));
11225
- }
11226
- reactToCollapse.current = true;
11227
- },
11228
- // Only react to collapseKey changes. Other deps should be stable (`contains`, `getOptionLabel`, `getOptionValue`).
11229
- // eslint-disable-next-line react-hooks/exhaustive-deps
11230
- [collapsedKeys]
11231
- );
11237
+ const filteredOptions = useMemo15(() => getFilteredOptions(fieldState.allOptions, fieldState.searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue), [fieldState.allOptions, fieldState.searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue]);
11232
11238
  const onInputChange = useCallback8((inputValue) => {
11233
11239
  setFieldState((prevState) => {
11234
11240
  return {
11235
11241
  ...prevState,
11236
11242
  inputValue,
11237
- allowCollapsing: inputValue.length === 0,
11238
- filteredOptions: prevState.allOptions.flatMap((o) => levelOptions(o, 0, inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), inputValue)))
11243
+ searchValue: inputValue.length === 0 ? void 0 : inputValue,
11244
+ allowCollapsing: inputValue.length === 0
11239
11245
  };
11240
11246
  });
11241
- }, [collapsedKeys, contains, getOptionLabel, getOptionValue]);
11242
- const maybeInitLoad = useCallback8(async (options2, fieldState2, setFieldState2) => {
11247
+ }, []);
11248
+ const maybeInitLoad = useCallback8(async (options2, setFieldState2) => {
11243
11249
  if (!Array.isArray(options2)) {
11244
11250
  setFieldState2((prevState) => ({
11245
11251
  ...prevState,
11246
11252
  optionsLoading: true
11247
11253
  }));
11248
11254
  const loadedOptions = (await options2.load()).options;
11249
- const filteredOptions = loadedOptions.flatMap((o) => levelOptions(o, 0, fieldState2.inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), fieldState2.inputValue)));
11250
11255
  setFieldState2((prevState) => ({
11251
11256
  ...prevState,
11252
- filteredOptions,
11253
11257
  allOptions: loadedOptions,
11254
11258
  optionsLoading: false
11255
11259
  }));
11256
11260
  }
11257
- }, [collapsedKeys, contains, getOptionLabel, getOptionValue]);
11261
+ }, []);
11258
11262
  const firstOpen = useRef22(true);
11259
11263
  function onOpenChange(isOpen) {
11260
11264
  if (firstOpen.current && isOpen) {
11261
- maybeInitLoad(options, fieldState, setFieldState);
11265
+ maybeInitLoad(options, setFieldState);
11262
11266
  firstOpen.current = false;
11263
11267
  }
11264
11268
  if (isOpen) {
11265
11269
  setFieldState((prevState) => ({
11266
11270
  ...prevState,
11267
11271
  inputValue: "",
11268
- filteredOptions: prevState.allOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue))
11272
+ searchValue: void 0,
11273
+ allowCollapsing: true
11269
11274
  }));
11270
11275
  }
11271
11276
  }
11272
11277
  const comboBoxChildren = useCallback8(([item]) => /* @__PURE__ */ jsx54(Item3, { textValue: getOptionLabel(item), children: getOptionMenuLabel(item) }, valueToKey(getOptionValue(item))), [getOptionValue, getOptionLabel, getOptionMenuLabel]);
11273
11278
  const comboBoxProps = {
11274
11279
  ...otherProps,
11275
- disabledKeys: Object.keys(disabledOptionsWithReasons),
11280
+ disabledKeys,
11276
11281
  placeholder: !values || values.length === 0 ? placeholder : "",
11277
11282
  label: props.label,
11278
11283
  inputValue: fieldState.inputValue,
11279
- items: fieldState.filteredOptions,
11284
+ items: filteredOptions,
11280
11285
  isDisabled,
11281
11286
  isReadOnly,
11282
11287
  onInputChange,
@@ -11301,6 +11306,8 @@ function TreeSelectFieldBase(props) {
11301
11306
  setFieldState((prevState) => ({
11302
11307
  ...prevState,
11303
11308
  inputValue: nothingSelectedText,
11309
+ searchValue: void 0,
11310
+ allowCollapsing: true,
11304
11311
  selectedKeys: [],
11305
11312
  selectedOptions: []
11306
11313
  }));
@@ -11331,15 +11338,16 @@ function TreeSelectFieldBase(props) {
11331
11338
  const childrenKeys = option.children.flatMap(flattenOptions).map((o) => valueToKey(getOptionValue(o))).filter((childKey) => {
11332
11339
  return !state.disabledKeys.has(childKey);
11333
11340
  });
11334
- [key, ...childrenKeys].forEach(addedKeys.add, addedKeys);
11341
+ [...groupKeySet.has(key) ? [] : [key], ...childrenKeys].forEach(addedKeys.add, addedKeys);
11335
11342
  }
11336
- for (const parent of parents.reverse()) {
11337
- const allChecked = parent.children?.every((child) => {
11338
- const childKey = valueToKey(getOptionValue(child));
11339
- return addedKeys.has(childKey) || existingKeys.has(childKey) || state.disabledKeys.has(childKey);
11340
- });
11341
- if (allChecked) {
11342
- addedKeys.add(valueToKey(getOptionValue(parent)));
11343
+ const selectionKeys = /* @__PURE__ */ new Set([...existingKeys, ...addedKeys]);
11344
+ for (const parent of [...parents].reverse()) {
11345
+ const parentKey = valueToKey(getOptionValue(parent));
11346
+ if (isOptionFullySelected(parent, selectionKeys, state.disabledKeys, groupKeySet, getOptionValue)) {
11347
+ if (!groupKeySet.has(parentKey)) {
11348
+ addedKeys.add(parentKey);
11349
+ selectionKeys.add(parentKey);
11350
+ }
11343
11351
  }
11344
11352
  }
11345
11353
  }
@@ -11372,7 +11380,7 @@ function TreeSelectFieldBase(props) {
11372
11380
  ...prevState,
11373
11381
  // Since we reset the list of options upon selection changes, then set the `inputValue` to empty string to reflect that.
11374
11382
  inputValue: "",
11375
- filteredOptions: initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue)),
11383
+ searchValue: void 0,
11376
11384
  selectedKeys: [...selectedKeys],
11377
11385
  selectedOptions,
11378
11386
  selectedOptionsLabels: chipDisplay === "root" ? rootOptions.map(getOptionLabel) : chipDisplay === "leaf" ? leafOptions.map(getOptionLabel) : selectedOptions.map(getOptionLabel)
@@ -11403,7 +11411,7 @@ function TreeSelectFieldBase(props) {
11403
11411
  setFieldState((prevState) => ({
11404
11412
  ...prevState,
11405
11413
  inputValue: selectedOptions.length === 1 ? getOptionLabel(selectedOptions[0]) : selectedOptions.length === 0 ? nothingSelectedText : "",
11406
- filteredOptions: initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue)),
11414
+ searchValue: void 0,
11407
11415
  allowCollapsing: true
11408
11416
  }));
11409
11417
  }
@@ -11492,6 +11500,18 @@ function getTopLevelSelections(o, selectedKeys, getOptionValue) {
11492
11500
  if (o.children) return [...o.children.flatMap((c) => getTopLevelSelections(c, selectedKeys, getOptionValue))];
11493
11501
  return [];
11494
11502
  }
11503
+ function getFilteredOptions(allOptions, searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue) {
11504
+ return allOptions.flatMap((option) => levelOptions(option, 0, !!searchValue, collapsedKeys, getOptionValue).filter(([nestedOption]) => searchValue ? contains(getOptionLabel(nestedOption), searchValue) : true));
11505
+ }
11506
+ function isOptionFullySelected(option, selectedKeys, disabledKeys, groupKeys, getOptionValue) {
11507
+ const key = valueToKey(getOptionValue(option));
11508
+ if (groupKeys.has(key)) {
11509
+ return option.children?.length ? option.children.every((child) => isOptionFullySelected(child, selectedKeys, disabledKeys, groupKeys, getOptionValue)) : false;
11510
+ }
11511
+ if (selectedKeys.has(key) || disabledKeys.has(key)) return true;
11512
+ if (!option.children || option.children.length === 0) return false;
11513
+ return option.children.every((child) => isOptionFullySelected(child, selectedKeys, disabledKeys, groupKeys, getOptionValue));
11514
+ }
11495
11515
 
11496
11516
  // src/inputs/internal/ComboBoxInput.tsx
11497
11517
  import { jsx as jsx55 } from "react/jsx-runtime";