@homebound/beam 3.1.0-alpha.1 → 3.1.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/dist/index.cjs CHANGED
@@ -5890,47 +5890,24 @@ function useHover2(props) {
5890
5890
  var import_react16 = require("react");
5891
5891
  var import_use_query_params2 = require("use-query-params");
5892
5892
  function usePersistedFilter({ storageKey, filterDefs }) {
5893
- const filterImpls = (0, import_react16.useMemo)(
5894
- () => Object.fromEntries(safeEntries(filterDefs).map(([key, def]) => [key, def(key)])),
5895
- [filterDefs]
5896
- );
5897
- const filterKeys = (0, import_react16.useMemo)(() => Object.keys(filterImpls), [filterImpls]);
5893
+ const filterKeys = Object.keys(filterDefs);
5898
5894
  const defaultFilter = (0, import_react16.useMemo)(
5899
5895
  () => Object.fromEntries(
5900
- safeEntries(filterImpls).filter(([, def]) => def.defaultValue !== void 0).map(([key, def]) => [key, def.defaultValue])
5896
+ safeEntries(filterDefs).filter(([key, def]) => def(key).defaultValue !== void 0).map(([key, def]) => [key, def(key).defaultValue])
5901
5897
  ),
5902
- [filterImpls]
5898
+ [filterDefs]
5903
5899
  );
5904
5900
  const [{ filter: queryParamsFilter }, setQueryParams] = (0, import_use_query_params2.useQueryParams)({ filter: import_use_query_params2.JsonParam });
5905
- const [storedFilter, setStoredFilter] = useSessionStorage(
5906
- storageKey,
5907
- dehydrateFilter(filterImpls, defaultFilter) ?? defaultFilter
5908
- );
5901
+ const [storedFilter, setStoredFilter] = useSessionStorage(storageKey, queryParamsFilter ?? defaultFilter);
5909
5902
  const isQueryParamFilterValid = hasValidFilterKeys(queryParamsFilter, filterKeys);
5910
- const serializedQueryParamsFilter = (0, import_react16.useMemo)(() => JSON.stringify(queryParamsFilter), [queryParamsFilter]);
5911
- const serializedStoredFilter = (0, import_react16.useMemo)(() => JSON.stringify(storedFilter), [storedFilter]);
5912
- const queryParamsFilterSnapshot = (0, import_react16.useMemo)(
5913
- () => parseSerializedValue(serializedQueryParamsFilter),
5914
- [serializedQueryParamsFilter]
5915
- );
5916
- const storedFilterSnapshot = (0, import_react16.useMemo)(() => parseSerializedValue(serializedStoredFilter), [serializedStoredFilter]);
5917
- const hydratedQueryParamsFilter = (0, import_react16.useMemo)(
5918
- () => isQueryParamFilterValid ? hydrateFilter(filterImpls, queryParamsFilterSnapshot) : void 0,
5919
- [filterImpls, isQueryParamFilterValid, queryParamsFilterSnapshot]
5920
- );
5921
- const hydratedStoredFilter = (0, import_react16.useMemo)(
5922
- () => hasValidFilterKeys(storedFilterSnapshot, filterKeys) ? hydrateFilter(filterImpls, storedFilterSnapshot) : void 0,
5923
- [filterImpls, filterKeys, storedFilterSnapshot]
5924
- );
5925
- const rawFilter = hydratedQueryParamsFilter ?? hydratedStoredFilter ?? defaultFilter;
5926
- const filter = useStableValue(rawFilter);
5927
- const setFilter = (filter2) => setQueryParams({ filter: dehydrateFilter(filterImpls, filter2) });
5903
+ const filter = isQueryParamFilterValid ? queryParamsFilter : storedFilter ?? defaultFilter;
5904
+ const setFilter = (filter2) => setQueryParams({ filter: filter2 });
5928
5905
  (0, import_react16.useEffect)(
5929
5906
  () => {
5930
5907
  if (queryParamsFilter === void 0) {
5931
5908
  setQueryParams({ filter: storedFilter }, "replaceIn");
5932
5909
  } else if (!isQueryParamFilterValid) {
5933
- setQueryParams({ filter: dehydrateFilter(filterImpls, defaultFilter) }, "replaceIn");
5910
+ setQueryParams({ filter: defaultFilter }, "replaceIn");
5934
5911
  } else if (JSON.stringify(queryParamsFilter) !== JSON.stringify(storedFilter)) {
5935
5912
  setStoredFilter(queryParamsFilter);
5936
5913
  }
@@ -5942,45 +5919,7 @@ function usePersistedFilter({ storageKey, filterDefs }) {
5942
5919
  return { setFilter, filter };
5943
5920
  }
5944
5921
  function hasValidFilterKeys(queryParamsFilter, definedKeys) {
5945
- return !!queryParamsFilter && safeKeys(queryParamsFilter).every((key) => definedKeys.includes(key));
5946
- }
5947
- function hydrateFilter(filterImpls, value) {
5948
- if (typeof value !== "object" || value === null) return void 0;
5949
- const hydratedEntries = [];
5950
- safeEntries(value).forEach(([key, rawValue]) => {
5951
- const filter = filterImpls[key];
5952
- if (!filter) return;
5953
- const hydratedValue = filter.hydrate ? filter.hydrate(rawValue) : rawValue;
5954
- if (hydratedValue !== void 0) {
5955
- hydratedEntries.push([key, hydratedValue]);
5956
- }
5957
- });
5958
- return Object.fromEntries(hydratedEntries);
5959
- }
5960
- function dehydrateFilter(filterImpls, value) {
5961
- if (!value) return value;
5962
- return Object.fromEntries(
5963
- safeEntries(value).map(([key, rawValue]) => {
5964
- const filter = filterImpls[key];
5965
- return [
5966
- key,
5967
- filter?.dehydrate ? filter.dehydrate(rawValue) : rawValue
5968
- ];
5969
- })
5970
- );
5971
- }
5972
- function parseSerializedValue(value) {
5973
- return value === void 0 ? void 0 : JSON.parse(value);
5974
- }
5975
- function useStableValue(value) {
5976
- const stableValue = (0, import_react16.useRef)(value);
5977
- const stableKey = (0, import_react16.useRef)(JSON.stringify(value));
5978
- const nextKey = JSON.stringify(value);
5979
- if (stableKey.current !== nextKey) {
5980
- stableValue.current = value;
5981
- stableKey.current = nextKey;
5982
- }
5983
- return stableValue.current;
5922
+ return queryParamsFilter && safeKeys(queryParamsFilter).every((key) => definedKeys.includes(key));
5984
5923
  }
5985
5924
 
5986
5925
  // src/hooks/useSessionStorage.ts
@@ -6598,61 +6537,6 @@ function WeekHeader() {
6598
6537
  ] }, (0, import_date_fns2.format)(day, "EEEE"))) }) });
6599
6538
  }
6600
6539
 
6601
- // src/utils/plainDate.ts
6602
- var import_temporal_polyfill = require("temporal-polyfill");
6603
- function plainDateToJsDate(date) {
6604
- return new Date(date.year, date.month - 1, date.day, 12);
6605
- }
6606
- function jsDateToPlainDate(date) {
6607
- return new import_temporal_polyfill.Temporal.PlainDate(date.getFullYear(), date.getMonth() + 1, date.getDate());
6608
- }
6609
- function dateRangeToJsDateRange(range) {
6610
- if (!range) return void 0;
6611
- return {
6612
- from: range.from ? plainDateToJsDate(range.from) : void 0,
6613
- to: range.to ? plainDateToJsDate(range.to) : void 0
6614
- };
6615
- }
6616
- function jsDateRangeToDateRange(range) {
6617
- if (!range) return void 0;
6618
- return {
6619
- from: range.from ? jsDateToPlainDate(range.from) : void 0,
6620
- to: range.to ? jsDateToPlainDate(range.to) : void 0
6621
- };
6622
- }
6623
- function dayMatcherToDayPickerMatcher(matcher) {
6624
- return (date) => matcher(jsDateToPlainDate(date));
6625
- }
6626
- function dayMatchersToDayPickerMatchers(matchers) {
6627
- if (matchers === void 0) return void 0;
6628
- return Array.isArray(matchers) ? matchers.map(dayMatcherToDayPickerMatcher) : dayMatcherToDayPickerMatcher(matchers);
6629
- }
6630
- function todayPlainDate() {
6631
- return import_temporal_polyfill.Temporal.Now.plainDateISO();
6632
- }
6633
- function isPlainDate(value) {
6634
- return value instanceof import_temporal_polyfill.Temporal.PlainDate;
6635
- }
6636
- function parsePersistedPlainDate(value) {
6637
- if (isPlainDate(value)) return value;
6638
- if (value instanceof Date && !Number.isNaN(value.getTime())) {
6639
- return jsDateToPlainDate(value);
6640
- }
6641
- if (typeof value !== "string") return void 0;
6642
- try {
6643
- if (/^\d{4}-\d{2}-\d{2}$/.test(value)) {
6644
- return import_temporal_polyfill.Temporal.PlainDate.from(value);
6645
- }
6646
- } catch {
6647
- return void 0;
6648
- }
6649
- const date = new Date(value);
6650
- return Number.isNaN(date.getTime()) ? void 0 : jsDateToPlainDate(date);
6651
- }
6652
- function dehydratePlainDate(value) {
6653
- return value?.toString();
6654
- }
6655
-
6656
6540
  // src/components/internal/DatePicker/DatePicker.tsx
6657
6541
  var import_jsx_runtime19 = require("react/jsx-runtime");
6658
6542
  function DatePicker(props) {
@@ -6672,15 +6556,15 @@ function DatePicker(props) {
6672
6556
  Head: WeekHeader,
6673
6557
  Day
6674
6558
  },
6675
- selected: value ? [plainDateToJsDate(value)] : [],
6676
- defaultMonth: plainDateToJsDate(value ?? todayPlainDate()),
6559
+ selected: value ? [value] : [],
6560
+ defaultMonth: value ?? /* @__PURE__ */ new Date(),
6677
6561
  onDayClick: (day, modifiers) => {
6678
6562
  if (modifiers.disabled) return;
6679
- onSelect(jsDateToPlainDate(day));
6563
+ onSelect(day);
6680
6564
  },
6681
- disabled: dayMatchersToDayPickerMatchers(disabledDays),
6565
+ disabled: disabledDays,
6682
6566
  modifiers: {
6683
- indicatorDot: dayMatchersToDayPickerMatchers(dottedDays) ?? []
6567
+ indicatorDot: dottedDays ?? []
6684
6568
  }
6685
6569
  }
6686
6570
  ) });
@@ -6707,15 +6591,15 @@ function DateRangePicker(props) {
6707
6591
  useYearPicker
6708
6592
  } = props;
6709
6593
  const tid = useTestIds(props, "datePicker");
6710
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "dib bgWhite fw4 fz_12px lh_16px", ...tid, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_day_picker4.DayPicker, { mode: "range", selected: dateRangeToJsDateRange(range), components: {
6594
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "dib bgWhite fw4 fz_12px lh_16px", ...tid, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_day_picker4.DayPicker, { mode: "range", selected: range, components: {
6711
6595
  Caption: useYearPicker ? YearSkipHeader : Header,
6712
6596
  Head: WeekHeader,
6713
6597
  Day
6714
- }, defaultMonth: plainDateToJsDate(range?.to ?? range?.from ?? todayPlainDate()), onSelect: (selection, day, activeModifiers) => {
6598
+ }, defaultMonth: range?.to ?? /* @__PURE__ */ new Date(), onSelect: (selection, day, activeModifiers) => {
6715
6599
  if (activeModifiers.disabled) return;
6716
- onSelect(jsDateRangeToDateRange(selection));
6717
- }, disabled: dayMatchersToDayPickerMatchers(disabledDays), modifiers: {
6718
- indicatorDot: dayMatchersToDayPickerMatchers(dottedDays) ?? []
6600
+ onSelect(selection);
6601
+ }, disabled: disabledDays, modifiers: {
6602
+ indicatorDot: dottedDays ?? []
6719
6603
  } }) });
6720
6604
  }
6721
6605
 
@@ -11068,7 +10952,8 @@ function TreeOption(props) {
11068
10952
  const {
11069
10953
  collapsedKeys,
11070
10954
  setCollapsedKeys,
11071
- getOptionValue
10955
+ getOptionValue,
10956
+ groupKeys
11072
10957
  } = useTreeSelectFieldProvider();
11073
10958
  const {
11074
10959
  optionProps,
@@ -11080,6 +10965,12 @@ function TreeOption(props) {
11080
10965
  shouldSelectOnPressUp: true,
11081
10966
  shouldFocusOnHover: false
11082
10967
  }, state, ref);
10968
+ const isGroup = groupKeys.includes(item.key);
10969
+ const canCollapse = allowCollapsing && !!option.children?.length;
10970
+ function toggleCollapsed() {
10971
+ if (!canCollapse) return;
10972
+ setCollapsedKeys((prevKeys) => collapsedKeys.includes(item.key) ? prevKeys.filter((k) => k !== item.key) : [...prevKeys, item.key]);
10973
+ }
11083
10974
  const isIndeterminate = !isSelected && option.children?.some((o) => hasSelectedChildren(o, state, getOptionValue));
11084
10975
  const listItemStyles = {
11085
10976
  item: {
@@ -11107,7 +10998,12 @@ function TreeOption(props) {
11107
10998
  }]
11108
10999
  }
11109
11000
  };
11110
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { ...hoverProps, ...(0, import_runtime36.trussProps)({
11001
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("li", { ...hoverProps, onClick: (e) => {
11002
+ if (!isGroup) return;
11003
+ e.preventDefault();
11004
+ e.stopPropagation();
11005
+ toggleCollapsed();
11006
+ }, ...(0, import_runtime36.trussProps)({
11111
11007
  ...{
11112
11008
  display: "df",
11113
11009
  alignItems: "aic",
@@ -11124,18 +11020,18 @@ function TreeOption(props) {
11124
11020
  lineHeight: "lh_20px"
11125
11021
  },
11126
11022
  ...listItemStyles.item,
11127
- ...isHovered && !isDisabled ? listItemStyles.hover : {},
11128
- ...isFocused ? listItemStyles.focus : {},
11129
- ...isDisabled ? listItemStyles.disabled : {}
11023
+ ...isHovered && (!isDisabled || isGroup) ? listItemStyles.hover : {},
11024
+ ...isFocused && !isGroup ? listItemStyles.focus : {},
11025
+ ...isDisabled && !isGroup ? listItemStyles.disabled : {}
11130
11026
  }), children: [
11131
- allowCollapsing && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "w_18px fs0 df aic", children: option.children && option.children?.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("button", { onClick: (e) => {
11027
+ allowCollapsing && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "w_18px fs0 df aic", children: canCollapse && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("button", { onClick: (e) => {
11132
11028
  e.preventDefault();
11133
11029
  e.stopPropagation();
11134
- setCollapsedKeys((prevKeys) => collapsedKeys.includes(item.key) ? prevKeys.filter((k) => k !== item.key) : [...prevKeys, item.key]);
11030
+ toggleCollapsed();
11135
11031
  return false;
11136
11032
  }, className: "br4 h_16px w_16px bgTransparent h_bgGray300", ...tid[`collapseToggle_${item.key}`], children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Icon, { icon: collapsedKeys.includes(item.key) ? "triangleRight" : "triangleDown", inc: 2 }) }) }),
11137
11033
  /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "df aic gap1 h100 fg1 pt1 pb1 pr2", ref, ...optionProps, "data-label": item.textValue, children: [
11138
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(StyledCheckbox, { isDisabled, isSelected, isIndeterminate, ...tid[item.key.toString()] }),
11034
+ !isGroup && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(StyledCheckbox, { isDisabled, isSelected, isIndeterminate, ...tid[item.key.toString()] }),
11139
11035
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "pl1", children: item.rendered })
11140
11036
  ] })
11141
11037
  ] });
@@ -11218,9 +11114,14 @@ function VirtualizedOptions(props) {
11218
11114
  totalListHeightChanged: onListHeightChange,
11219
11115
  totalCount: items.length,
11220
11116
  ...process.env.NODE_ENV === "test" ? {
11221
- // We don't really need to set this, but it's handy for tests, which would
11222
- // otherwise render just 1 row. A better way to do this would be to jest.mock
11223
- // out Virtuoso with an impl that just rendered everything, but doing this for now.
11117
+ // In tests, we render all rows so assertions can see expands/async-loaded items. However,
11118
+ // the `initialItemCount` (next prop) is only applied on amount, so we set `key={items.length}`
11119
+ // to force a remount when our list changes -- and we only want/need this in tests, b/c otherwise
11120
+ // in production a Virtuoso remount causes visible flashing.
11121
+ key: items.length,
11122
+ // We don't really need to set this, but it's handy for tests, which would otherwise render
11123
+ // just 1 row. A better way to do this would be to jest.mock out Virtuoso with an impl that
11124
+ // just rendered everything, but doing this for now.
11224
11125
  initialItemCount: items.length
11225
11126
  } : {
11226
11127
  // Ensure the selected item is visible when the list renders
@@ -11260,8 +11161,7 @@ function VirtualizedOptions(props) {
11260
11161
  components: !loading ? {} : {
11261
11162
  Footer: typeof loading === "function" ? loading : () => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(LoadingDots, { contrast })
11262
11163
  }
11263
- },
11264
- items.length
11164
+ }
11265
11165
  );
11266
11166
  }
11267
11167
 
@@ -11434,6 +11334,7 @@ function TreeSelectField(props) {
11434
11334
  ...otherProps
11435
11335
  } = props;
11436
11336
  const [collapsedKeys, setCollapsedKeys] = (0, import_react44.useState)([]);
11337
+ const groupKeys = (0, import_react44.useMemo)(() => props.groupOptions?.map((option) => valueToKey(option)) ?? [], [props.groupOptions]);
11437
11338
  (0, import_react44.useEffect)(() => {
11438
11339
  setCollapsedKeys(!Array.isArray(options) ? [] : defaultCollapsed ? options.map((o) => getOptionValue(o)) : options.flatMap(flattenOptions).filter((o) => o.defaultCollapsed).map((o) => getOptionValue(o)));
11439
11340
  }, [options, defaultCollapsed]);
@@ -11441,11 +11342,12 @@ function TreeSelectField(props) {
11441
11342
  () => ({
11442
11343
  collapsedKeys,
11443
11344
  setCollapsedKeys,
11444
- getOptionValue
11345
+ getOptionValue,
11346
+ groupKeys
11445
11347
  }),
11446
11348
  // 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
11447
11349
  // eslint-disable-next-line react-hooks/exhaustive-deps
11448
- [collapsedKeys, setCollapsedKeys]
11350
+ [collapsedKeys, setCollapsedKeys, groupKeys]
11449
11351
  );
11450
11352
  return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(CollapsedContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(TreeSelectFieldBase, { ...otherProps, options, getOptionLabel, getOptionValue, values, onSelect: ({
11451
11353
  all,
@@ -11466,7 +11368,8 @@ var CollapsedContext = import_react44.default.createContext({
11466
11368
  collapsedKeys: [],
11467
11369
  setCollapsedKeys: () => {
11468
11370
  },
11469
- getOptionValue: () => ({})
11371
+ getOptionValue: () => ({}),
11372
+ groupKeys: []
11470
11373
  });
11471
11374
  function TreeSelectFieldBase(props) {
11472
11375
  const {
@@ -11485,13 +11388,15 @@ function TreeSelectFieldBase(props) {
11485
11388
  contrast = false,
11486
11389
  nothingSelectedText = "",
11487
11390
  onSelect,
11488
- defaultCollapsed = false,
11391
+ defaultCollapsed: _defaultCollapsed = false,
11489
11392
  placeholder,
11490
11393
  fullWidth = fieldProps?.fullWidth ?? false,
11491
11394
  chipDisplay = "root",
11492
11395
  disabledOptions,
11396
+ groupOptions: _groupOptions,
11493
11397
  ...otherProps
11494
11398
  } = props;
11399
+ void _defaultCollapsed;
11495
11400
  const isDisabled = !!disabled;
11496
11401
  const isReadOnly = !!readOnly;
11497
11402
  const initialOptions = Array.isArray(options) ? options : options.current;
@@ -11503,7 +11408,10 @@ function TreeSelectFieldBase(props) {
11503
11408
  const {
11504
11409
  collapsedKeys
11505
11410
  } = useTreeSelectFieldProvider();
11411
+ const groupKeys = (0, import_react44.useMemo)(() => _groupOptions?.map((option) => valueToKey(option)) ?? [], [_groupOptions]);
11412
+ const groupKeySet = (0, import_react44.useMemo)(() => new Set(groupKeys), [groupKeys]);
11506
11413
  const disabledOptionsWithReasons = Object.fromEntries(disabledOptions?.map(disabledOptionToKeyedTuple) ?? []);
11414
+ const disabledKeys = [.../* @__PURE__ */ new Set([...Object.keys(disabledOptionsWithReasons), ...groupKeys])];
11507
11415
  const initTreeFieldState = (0, import_react44.useCallback)(() => {
11508
11416
  const selectedKeys = new Set(values?.flatMap((v) => {
11509
11417
  const foundOptions = findOptions(initialOptions, valueToKey(v), getOptionValue);
@@ -11512,14 +11420,16 @@ function TreeSelectFieldBase(props) {
11512
11420
  }) => selectOptionAndAllChildren(option));
11513
11421
  }));
11514
11422
  function selectOptionAndAllChildren(maybeParent) {
11515
- return [valueToKey(getOptionValue(maybeParent)), ...maybeParent.children?.flatMap(selectOptionAndAllChildren) ?? []];
11423
+ const key = valueToKey(getOptionValue(maybeParent));
11424
+ return [...groupKeySet.has(key) ? [] : [key], ...maybeParent.children?.flatMap(selectOptionAndAllChildren) ?? []];
11516
11425
  }
11517
11426
  function areAllChildrenSelected(maybeParent) {
11518
- const isSelected = selectedKeys.has(valueToKey(getOptionValue(maybeParent)));
11427
+ const key = valueToKey(getOptionValue(maybeParent));
11428
+ const isSelected = selectedKeys.has(key);
11519
11429
  if (isSelected || !maybeParent.children || maybeParent.children.length === 0) return isSelected;
11520
11430
  const areAllSelected = maybeParent.children.every(areAllChildrenSelected);
11521
- if (areAllSelected) {
11522
- selectedKeys.add(valueToKey(getOptionValue(maybeParent)));
11431
+ if (areAllSelected && !groupKeySet.has(key)) {
11432
+ selectedKeys.add(key);
11523
11433
  }
11524
11434
  return areAllSelected;
11525
11435
  }
@@ -11530,18 +11440,17 @@ function TreeSelectFieldBase(props) {
11530
11440
  return [maybeOption.option];
11531
11441
  });
11532
11442
  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);
11533
- const filteredOptions = initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue));
11534
11443
  return {
11535
11444
  selectedKeys: [...selectedKeys],
11445
+ searchValue: void 0,
11536
11446
  inputValue: selectedOptions.length === 1 ? getOptionLabel([...selectedOptions][0]) : isReadOnly && selectedOptions.length > 0 ? selectedOptionsLabels.join(", ") : selectedOptions.length === 0 ? nothingSelectedText : "",
11537
- filteredOptions,
11538
11447
  selectedOptions,
11539
11448
  allOptions: initialOptions,
11540
11449
  selectedOptionsLabels,
11541
11450
  optionsLoading: false,
11542
11451
  allowCollapsing: true
11543
11452
  };
11544
- }, [initialOptions, values, chipDisplay, getOptionLabel, isReadOnly, nothingSelectedText, getOptionValue, collapsedKeys]);
11453
+ }, [initialOptions, values, chipDisplay, getOptionLabel, isReadOnly, nothingSelectedText, getOptionValue, groupKeySet]);
11545
11454
  const [fieldState, setFieldState] = (0, import_react44.useState)(() => initTreeFieldState());
11546
11455
  (0, import_react44.useEffect)(() => {
11547
11456
  if (Array.isArray(options)) {
@@ -11561,75 +11470,54 @@ function TreeSelectFieldBase(props) {
11561
11470
  setFieldState(initTreeFieldState());
11562
11471
  }
11563
11472
  }, [getOptionValue, initTreeFieldState, values]);
11564
- const reactToCollapse = (0, import_react44.useRef)(false);
11565
- (0, import_react44.useEffect)(
11566
- () => {
11567
- if (reactToCollapse.current) {
11568
- setFieldState(({
11569
- allOptions,
11570
- inputValue,
11571
- ...others
11572
- }) => ({
11573
- allOptions,
11574
- inputValue,
11575
- ...others,
11576
- filteredOptions: allOptions.flatMap((o) => levelOptions(o, 0, inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), inputValue)))
11577
- }));
11578
- }
11579
- reactToCollapse.current = true;
11580
- },
11581
- // Only react to collapseKey changes. Other deps should be stable (`contains`, `getOptionLabel`, `getOptionValue`).
11582
- // eslint-disable-next-line react-hooks/exhaustive-deps
11583
- [collapsedKeys]
11584
- );
11473
+ const filteredOptions = (0, import_react44.useMemo)(() => getFilteredOptions(fieldState.allOptions, fieldState.searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue), [fieldState.allOptions, fieldState.searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue]);
11585
11474
  const onInputChange = (0, import_react44.useCallback)((inputValue) => {
11586
11475
  setFieldState((prevState) => {
11587
11476
  return {
11588
11477
  ...prevState,
11589
11478
  inputValue,
11590
- allowCollapsing: inputValue.length === 0,
11591
- filteredOptions: prevState.allOptions.flatMap((o) => levelOptions(o, 0, inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), inputValue)))
11479
+ searchValue: inputValue.length === 0 ? void 0 : inputValue,
11480
+ allowCollapsing: inputValue.length === 0
11592
11481
  };
11593
11482
  });
11594
- }, [collapsedKeys, contains, getOptionLabel, getOptionValue]);
11595
- const maybeInitLoad = (0, import_react44.useCallback)(async (options2, fieldState2, setFieldState2) => {
11483
+ }, []);
11484
+ const maybeInitLoad = (0, import_react44.useCallback)(async (options2, setFieldState2) => {
11596
11485
  if (!Array.isArray(options2)) {
11597
11486
  setFieldState2((prevState) => ({
11598
11487
  ...prevState,
11599
11488
  optionsLoading: true
11600
11489
  }));
11601
11490
  const loadedOptions = (await options2.load()).options;
11602
- const filteredOptions = loadedOptions.flatMap((o) => levelOptions(o, 0, fieldState2.inputValue.length > 0, collapsedKeys, getOptionValue).filter(([option]) => contains(getOptionLabel(option), fieldState2.inputValue)));
11603
11491
  setFieldState2((prevState) => ({
11604
11492
  ...prevState,
11605
- filteredOptions,
11606
11493
  allOptions: loadedOptions,
11607
11494
  optionsLoading: false
11608
11495
  }));
11609
11496
  }
11610
- }, [collapsedKeys, contains, getOptionLabel, getOptionValue]);
11497
+ }, []);
11611
11498
  const firstOpen = (0, import_react44.useRef)(true);
11612
11499
  function onOpenChange(isOpen) {
11613
11500
  if (firstOpen.current && isOpen) {
11614
- maybeInitLoad(options, fieldState, setFieldState);
11501
+ maybeInitLoad(options, setFieldState);
11615
11502
  firstOpen.current = false;
11616
11503
  }
11617
11504
  if (isOpen) {
11618
11505
  setFieldState((prevState) => ({
11619
11506
  ...prevState,
11620
11507
  inputValue: "",
11621
- filteredOptions: prevState.allOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue))
11508
+ searchValue: void 0,
11509
+ allowCollapsing: true
11622
11510
  }));
11623
11511
  }
11624
11512
  }
11625
11513
  const comboBoxChildren = (0, import_react44.useCallback)(([item]) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_react_stately5.Item, { textValue: getOptionLabel(item), children: getOptionMenuLabel(item) }, valueToKey(getOptionValue(item))), [getOptionValue, getOptionLabel, getOptionMenuLabel]);
11626
11514
  const comboBoxProps = {
11627
11515
  ...otherProps,
11628
- disabledKeys: Object.keys(disabledOptionsWithReasons),
11516
+ disabledKeys,
11629
11517
  placeholder: !values || values.length === 0 ? placeholder : "",
11630
11518
  label: props.label,
11631
11519
  inputValue: fieldState.inputValue,
11632
- items: fieldState.filteredOptions,
11520
+ items: filteredOptions,
11633
11521
  isDisabled,
11634
11522
  isReadOnly,
11635
11523
  onInputChange,
@@ -11654,6 +11542,8 @@ function TreeSelectFieldBase(props) {
11654
11542
  setFieldState((prevState) => ({
11655
11543
  ...prevState,
11656
11544
  inputValue: nothingSelectedText,
11545
+ searchValue: void 0,
11546
+ allowCollapsing: true,
11657
11547
  selectedKeys: [],
11658
11548
  selectedOptions: []
11659
11549
  }));
@@ -11684,15 +11574,16 @@ function TreeSelectFieldBase(props) {
11684
11574
  const childrenKeys = option.children.flatMap(flattenOptions).map((o) => valueToKey(getOptionValue(o))).filter((childKey) => {
11685
11575
  return !state.disabledKeys.has(childKey);
11686
11576
  });
11687
- [key, ...childrenKeys].forEach(addedKeys.add, addedKeys);
11577
+ [...groupKeySet.has(key) ? [] : [key], ...childrenKeys].forEach(addedKeys.add, addedKeys);
11688
11578
  }
11689
- for (const parent of parents.reverse()) {
11690
- const allChecked = parent.children?.every((child) => {
11691
- const childKey = valueToKey(getOptionValue(child));
11692
- return addedKeys.has(childKey) || existingKeys.has(childKey) || state.disabledKeys.has(childKey);
11693
- });
11694
- if (allChecked) {
11695
- addedKeys.add(valueToKey(getOptionValue(parent)));
11579
+ const selectionKeys = /* @__PURE__ */ new Set([...existingKeys, ...addedKeys]);
11580
+ for (const parent of [...parents].reverse()) {
11581
+ const parentKey = valueToKey(getOptionValue(parent));
11582
+ if (isOptionFullySelected(parent, selectionKeys, state.disabledKeys, groupKeySet, getOptionValue)) {
11583
+ if (!groupKeySet.has(parentKey)) {
11584
+ addedKeys.add(parentKey);
11585
+ selectionKeys.add(parentKey);
11586
+ }
11696
11587
  }
11697
11588
  }
11698
11589
  }
@@ -11725,7 +11616,7 @@ function TreeSelectFieldBase(props) {
11725
11616
  ...prevState,
11726
11617
  // Since we reset the list of options upon selection changes, then set the `inputValue` to empty string to reflect that.
11727
11618
  inputValue: "",
11728
- filteredOptions: initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue)),
11619
+ searchValue: void 0,
11729
11620
  selectedKeys: [...selectedKeys],
11730
11621
  selectedOptions,
11731
11622
  selectedOptionsLabels: chipDisplay === "root" ? rootOptions.map(getOptionLabel) : chipDisplay === "leaf" ? leafOptions.map(getOptionLabel) : selectedOptions.map(getOptionLabel)
@@ -11756,7 +11647,7 @@ function TreeSelectFieldBase(props) {
11756
11647
  setFieldState((prevState) => ({
11757
11648
  ...prevState,
11758
11649
  inputValue: selectedOptions.length === 1 ? getOptionLabel(selectedOptions[0]) : selectedOptions.length === 0 ? nothingSelectedText : "",
11759
- filteredOptions: initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue)),
11650
+ searchValue: void 0,
11760
11651
  allowCollapsing: true
11761
11652
  }));
11762
11653
  }
@@ -11845,6 +11736,18 @@ function getTopLevelSelections(o, selectedKeys, getOptionValue) {
11845
11736
  if (o.children) return [...o.children.flatMap((c) => getTopLevelSelections(c, selectedKeys, getOptionValue))];
11846
11737
  return [];
11847
11738
  }
11739
+ function getFilteredOptions(allOptions, searchValue, collapsedKeys, contains, getOptionLabel, getOptionValue) {
11740
+ return allOptions.flatMap((option) => levelOptions(option, 0, !!searchValue, collapsedKeys, getOptionValue).filter(([nestedOption]) => searchValue ? contains(getOptionLabel(nestedOption), searchValue) : true));
11741
+ }
11742
+ function isOptionFullySelected(option, selectedKeys, disabledKeys, groupKeys, getOptionValue) {
11743
+ const key = valueToKey(getOptionValue(option));
11744
+ if (groupKeys.has(key)) {
11745
+ return option.children?.length ? option.children.every((child) => isOptionFullySelected(child, selectedKeys, disabledKeys, groupKeys, getOptionValue)) : false;
11746
+ }
11747
+ if (selectedKeys.has(key) || disabledKeys.has(key)) return true;
11748
+ if (!option.children || option.children.length === 0) return false;
11749
+ return option.children.every((child) => isOptionFullySelected(child, selectedKeys, disabledKeys, groupKeys, getOptionValue));
11750
+ }
11848
11751
 
11849
11752
  // src/inputs/internal/ComboBoxInput.tsx
11850
11753
  var import_jsx_runtime55 = require("react/jsx-runtime");
@@ -12545,7 +12448,7 @@ var import_jsx_runtime60 = require("react/jsx-runtime");
12545
12448
  function DateFieldMock(props) {
12546
12449
  const { onChange = () => {
12547
12450
  }, errorMsg, onBlur, onFocus } = props;
12548
- const [value, setValue] = (0, import_react50.useState)(props.value ? (0, import_date_fns3.format)(plainDateToJsDate(props.value), "MM/dd/yy") : "");
12451
+ const [value, setValue] = (0, import_react50.useState)(props.value ? (0, import_date_fns3.format)(props.value, "MM/dd/yy") : "");
12549
12452
  const tid = useTestIds(props, "date");
12550
12453
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
12551
12454
  "input",
@@ -12556,8 +12459,7 @@ function DateFieldMock(props) {
12556
12459
  onChange: (e) => {
12557
12460
  const { value: value2 } = e.target;
12558
12461
  setValue(value2);
12559
- const parsed = (0, import_date_fns3.parse)(value2, "MM/dd/yy", plainDateToJsDate(todayPlainDate()));
12560
- onChange(Number.isNaN(parsed.getTime()) ? void 0 : jsDateToPlainDate(parsed));
12462
+ onChange((0, import_date_fns3.parse)(value2, "MM/dd/yy", /* @__PURE__ */ new Date()));
12561
12463
  },
12562
12464
  onBlur: () => maybeCall(onBlur),
12563
12465
  onFocus: () => maybeCall(onFocus),
@@ -12571,11 +12473,11 @@ function DateFieldMock(props) {
12571
12473
  // src/inputs/DateFields/DateFieldBase.tsx
12572
12474
  var import_react51 = require("react");
12573
12475
  var import_react_aria31 = require("react-aria");
12476
+ var import_react_day_picker5 = require("react-day-picker");
12574
12477
  var import_react_stately10 = require("react-stately");
12575
12478
 
12576
12479
  // src/inputs/DateFields/utils.ts
12577
12480
  var import_date_fns4 = require("date-fns");
12578
- var import_temporal_polyfill2 = require("temporal-polyfill");
12579
12481
  var dateFormats = {
12580
12482
  short: "MM/dd/yy",
12581
12483
  medium: "EEE, MMM d",
@@ -12586,13 +12488,13 @@ function getDateFormat(format4) {
12586
12488
  }
12587
12489
  function formatDate(date, format4) {
12588
12490
  if (!date) return "";
12589
- return (0, import_date_fns4.format)(plainDateToJsDate(date), format4);
12491
+ return (0, import_date_fns4.format)(date, format4);
12590
12492
  }
12591
12493
  function formatDateRange(date, format4) {
12592
12494
  if (!date) return "";
12593
12495
  const { from, to } = date;
12594
- const fromFormatted = from ? (0, import_date_fns4.format)(plainDateToJsDate(from), format4) : "";
12595
- const toFormatted = to ? (0, import_date_fns4.format)(plainDateToJsDate(to), format4) : "";
12496
+ const fromFormatted = from ? (0, import_date_fns4.format)(from, format4) : "";
12497
+ const toFormatted = to ? (0, import_date_fns4.format)(to, format4) : "";
12596
12498
  return !fromFormatted && !toFormatted ? void 0 : `${fromFormatted} - ${toFormatted}`;
12597
12499
  }
12598
12500
  function parseDate(str, format4) {
@@ -12602,7 +12504,7 @@ function parseDateRange(str, format4) {
12602
12504
  const [from = "", to = ""] = str.split("-");
12603
12505
  const fromDate = parseDateString(from.trim(), format4);
12604
12506
  const toDate = parseDateString(to.trim(), format4);
12605
- if (toDate && fromDate && import_temporal_polyfill2.Temporal.PlainDate.compare(toDate, fromDate) < 0) {
12507
+ if (toDate && fromDate && toDate < fromDate) {
12606
12508
  return { from: toDate, to: fromDate };
12607
12509
  }
12608
12510
  if (toDate === void 0 && fromDate === void 0) {
@@ -12624,16 +12526,13 @@ function parseDateString(str, format4) {
12624
12526
  if (isNaN(year) || String(year).length > 4 || isNaN(month) || isNaN(day) || day <= 0 || day > 31 || month < 0 || month >= 12) {
12625
12527
  return void 0;
12626
12528
  }
12627
- const parsed = (0, import_date_fns4.parse)(str, format4, plainDateToJsDate(todayPlainDate()));
12628
- if (!isValidJsDate(parsed)) {
12529
+ const parsed = (0, import_date_fns4.parse)(str, format4, /* @__PURE__ */ new Date());
12530
+ if (!isValidDate(parsed)) {
12629
12531
  return void 0;
12630
12532
  }
12631
- return jsDateToPlainDate(parsed);
12533
+ return parsed;
12632
12534
  }
12633
12535
  function isValidDate(d) {
12634
- return d !== void 0 && isPlainDate(d);
12635
- }
12636
- function isValidJsDate(d) {
12637
12536
  return d !== void 0 && (0, import_date_fns4.isDate)(d) && d.toString() !== "Invalid Date";
12638
12537
  }
12639
12538
 
@@ -12759,11 +12658,11 @@ function DateFieldBase(props) {
12759
12658
  (d) => {
12760
12659
  setWipValue(d);
12761
12660
  if (d && isParsedDateValid(d)) {
12762
- if (isRangeMode && isDateRangeValue(d)) {
12661
+ if (isRangeMode && (0, import_react_day_picker5.isDateRange)(d)) {
12763
12662
  props.onChange(d);
12764
12663
  return;
12765
12664
  }
12766
- if (!isRangeMode && !isDateRangeValue(d)) {
12665
+ if (!isRangeMode && !(0, import_react_day_picker5.isDateRange)(d)) {
12767
12666
  props.onChange(d);
12768
12667
  return;
12769
12668
  }
@@ -12838,10 +12737,7 @@ function DateFieldBase(props) {
12838
12737
  ] });
12839
12738
  }
12840
12739
  function isParsedDateValid(d) {
12841
- return d !== void 0 && (!isDateRangeValue(d) || isValidDate(d.from) && isValidDate(d.to));
12842
- }
12843
- function isDateRangeValue(value) {
12844
- return typeof value === "object" && value !== null && ("from" in value || "to" in value);
12740
+ return d !== void 0 && (!(0, import_react_day_picker5.isDateRange)(d) || (0, import_react_day_picker5.isDateRange)(d) && isValidDate(d.from) && isValidDate(d.to));
12845
12741
  }
12846
12742
 
12847
12743
  // src/utils/withTestMock.tsx
@@ -18875,14 +18771,6 @@ function dateFilter(props) {
18875
18771
  }
18876
18772
  var anyOption = {};
18877
18773
  var DateFilter = class extends BaseFilter {
18878
- hydrate(value) {
18879
- if (!isDateFilterValue(value)) return void 0;
18880
- const hydratedValue = parsePersistedPlainDate(value.value);
18881
- return hydratedValue ? { op: value.op, value: hydratedValue } : void 0;
18882
- }
18883
- dehydrate(value) {
18884
- return value ? { op: value.op, value: dehydratePlainDate(value.value) } : void 0;
18885
- }
18886
18774
  render(value, setValue, tid, inModal, vertical) {
18887
18775
  const { label, operations, getOperationValue, getOperationLabel } = this.props;
18888
18776
  return /* @__PURE__ */ (0, import_jsx_runtime127.jsxs)(import_jsx_runtime127.Fragment, { children: [
@@ -18902,7 +18790,7 @@ var DateFilter = class extends BaseFilter {
18902
18790
  value: value?.op,
18903
18791
  onSelect: (op) => (
18904
18792
  // default the selected date to today if it doesn't exist in the filter's value
18905
- setValue(op ? { op, value: value?.value ?? todayPlainDate() } : void 0)
18793
+ setValue(op ? { op, value: value?.value ? new Date(value.value) : /* @__PURE__ */ new Date() } : void 0)
18906
18794
  ),
18907
18795
  label: inModal ? `${label} date filter operation` : label,
18908
18796
  labelStyle: !inModal && !vertical ? "inline" : inModal || vertical ? "hidden" : "above",
@@ -18914,13 +18802,9 @@ var DateFilter = class extends BaseFilter {
18914
18802
  DateField,
18915
18803
  {
18916
18804
  labelStyle: "inline",
18917
- value: value?.value ?? todayPlainDate(),
18805
+ value: value?.value ? new Date(value.value) : /* @__PURE__ */ new Date(),
18918
18806
  label: "Date",
18919
- onChange: (d) => {
18920
- if (d && value) {
18921
- setValue({ ...value, value: d });
18922
- }
18923
- },
18807
+ onChange: (d) => setValue({ ...value, value: d }),
18924
18808
  disabled: !value,
18925
18809
  ...tid[`${defaultTestId(this.label)}_dateField`]
18926
18810
  }
@@ -18929,9 +18813,6 @@ var DateFilter = class extends BaseFilter {
18929
18813
  ] });
18930
18814
  }
18931
18815
  };
18932
- function isDateFilterValue(value) {
18933
- return typeof value === "object" && value !== null && "op" in value && "value" in value;
18934
- }
18935
18816
 
18936
18817
  // src/components/Filters/DateRangeFilter.tsx
18937
18818
  var import_jsx_runtime128 = require("react/jsx-runtime");
@@ -18939,17 +18820,6 @@ function dateRangeFilter(props) {
18939
18820
  return (key) => new DateRangeFilter(key, props);
18940
18821
  }
18941
18822
  var DateRangeFilter = class extends BaseFilter {
18942
- hydrate(value) {
18943
- if (!isDateRangeFilterValue(value)) return void 0;
18944
- const hydratedValue = hydrateDateRange(value.value);
18945
- return hydratedValue ? { op: value.op, value: hydratedValue } : void 0;
18946
- }
18947
- dehydrate(value) {
18948
- return value ? {
18949
- op: value.op,
18950
- value: value.value ? { from: dehydratePlainDate(value.value.from), to: dehydratePlainDate(value.value.to) } : void 0
18951
- } : void 0;
18952
- }
18953
18823
  render(value, setValue, tid, inModal, vertical) {
18954
18824
  const { label, placeholderText, disabledDays, testFieldLabel, defaultValue } = this.props;
18955
18825
  return /* @__PURE__ */ (0, import_jsx_runtime128.jsxs)(import_jsx_runtime128.Fragment, { children: [
@@ -18961,17 +18831,8 @@ var DateRangeFilter = class extends BaseFilter {
18961
18831
  isRangeFilterField: true,
18962
18832
  placeholder: placeholderText,
18963
18833
  label: testFieldLabel ?? "Date",
18964
- value: value?.value,
18965
- onChange: (d) => {
18966
- if (!d) {
18967
- setValue(void 0);
18968
- return;
18969
- }
18970
- const op = value?.op ?? defaultValue?.op;
18971
- if (op !== void 0) {
18972
- setValue({ op, value: d });
18973
- }
18974
- },
18834
+ value: value?.value ? { from: new Date(value.value.from), to: new Date(value.value.to) } : void 0,
18835
+ onChange: (d) => d ? setValue({ op: defaultValue?.op, value: d }) : setValue(void 0),
18975
18836
  disabledDays,
18976
18837
  ...tid[`${defaultTestId(this.label)}_dateField`]
18977
18838
  }
@@ -18979,17 +18840,6 @@ var DateRangeFilter = class extends BaseFilter {
18979
18840
  ] });
18980
18841
  }
18981
18842
  };
18982
- function isDateRangeFilterValue(value) {
18983
- return typeof value === "object" && value !== null && "op" in value && "value" in value;
18984
- }
18985
- function hydrateDateRange(value) {
18986
- if (typeof value !== "object" || value === null) return void 0;
18987
- const { from, to } = value;
18988
- const hydratedFrom = parsePersistedPlainDate(from);
18989
- const hydratedTo = parsePersistedPlainDate(to);
18990
- if (hydratedFrom === void 0 && hydratedTo === void 0) return void 0;
18991
- return { from: hydratedFrom, to: hydratedTo };
18992
- }
18993
18843
 
18994
18844
  // src/components/Filters/MultiFilter.tsx
18995
18845
  var import_jsx_runtime129 = require("react/jsx-runtime");
@@ -19795,10 +19645,10 @@ function useGridTableLayoutState({
19795
19645
  });
19796
19646
  (0, import_react99.useEffect)(() => {
19797
19647
  if (page.limit !== persistedPageSize) setPersistedPageSize(page.limit);
19798
- setPage((prev) => prev.offset === 0 ? prev : {
19648
+ setPage((prev) => ({
19799
19649
  ...prev,
19800
19650
  offset: 0
19801
- });
19651
+ }));
19802
19652
  }, [page.limit, persistedPageSize, setPersistedPageSize, filter, searchString]);
19803
19653
  return {
19804
19654
  filter,