@homebound/beam 2.416.6 → 2.417.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 +69 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +71 -92
- package/dist/index.js.map +1 -1
- package/package.json +16 -16
package/dist/index.cjs
CHANGED
|
@@ -10601,16 +10601,13 @@ function TreeSelectFieldBase(props) {
|
|
|
10601
10601
|
const state = (0, import_react_stately6.useComboBoxState)({
|
|
10602
10602
|
...comboBoxProps,
|
|
10603
10603
|
allowsEmptyCollection: true,
|
|
10604
|
-
allowsCustomValue: true
|
|
10605
|
-
});
|
|
10606
|
-
state.selectionManager.state = (0, import_react_stately6.useMultipleSelectionState)({
|
|
10607
10604
|
selectionMode: "multiple",
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10605
|
+
// Prevent commitValue from calling onChange with stale displayValue on blur.
|
|
10606
|
+
// Menu close is handled manually in ComboBoxInput's onBlur via state.toggle().
|
|
10607
|
+
shouldCloseOnBlur: false,
|
|
10608
|
+
value: fieldState.selectedKeys,
|
|
10609
|
+
onChange: (newValue) => {
|
|
10610
|
+
const newKeys = new Set(newValue);
|
|
10614
10611
|
const existingKeys = state.selectionManager.selectedKeys;
|
|
10615
10612
|
const addedKeys = new Set([...newKeys].filter((x) => !existingKeys.has(x)));
|
|
10616
10613
|
const removedKeys = new Set([...existingKeys].filter((x) => !newKeys.has(x)));
|
|
@@ -10731,7 +10728,9 @@ function TreeSelectFieldBase(props) {
|
|
|
10731
10728
|
scrollRef: listBoxRef,
|
|
10732
10729
|
shouldFlip: true,
|
|
10733
10730
|
isOpen: state.isOpen,
|
|
10734
|
-
|
|
10731
|
+
// Use toggle() instead of close() to avoid commitValue(), which calls onChange(displayValue)
|
|
10732
|
+
// with a potentially stale controlled value. See ComboBoxBase.tsx for details.
|
|
10733
|
+
onClose: () => state.toggle(),
|
|
10735
10734
|
placement: "bottom left",
|
|
10736
10735
|
offset: borderless ? 8 : 4
|
|
10737
10736
|
});
|
|
@@ -10775,7 +10774,7 @@ function TreeSelectFieldBase(props) {
|
|
|
10775
10774
|
triggerRef,
|
|
10776
10775
|
popoverRef,
|
|
10777
10776
|
positionProps,
|
|
10778
|
-
onClose: () => state.
|
|
10777
|
+
onClose: () => state.toggle(),
|
|
10779
10778
|
isOpen: state.isOpen,
|
|
10780
10779
|
minWidth: 320,
|
|
10781
10780
|
children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
|
|
@@ -10897,46 +10896,31 @@ function ComboBoxInput(props) {
|
|
|
10897
10896
|
// Not merging the following as we want them to overwrite existing events
|
|
10898
10897
|
...{
|
|
10899
10898
|
onKeyDown: (e) => {
|
|
10900
|
-
if (isMultiSelect) {
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
if (item
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
|
|
10909
|
-
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
if (
|
|
10913
|
-
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
setCollapsedKeys((prevKeys) => [...prevKeys, item.key]);
|
|
10917
|
-
}
|
|
10899
|
+
if (isMultiSelect && isTree) {
|
|
10900
|
+
const focusedKey = state.selectionManager.focusedKey;
|
|
10901
|
+
if (focusedKey == null) return;
|
|
10902
|
+
const item = state.collection.getItem(focusedKey);
|
|
10903
|
+
if (item && (e.key === "ArrowRight" || e.key === "ArrowLeft")) {
|
|
10904
|
+
if (!isLeveledNode(item)) return;
|
|
10905
|
+
const leveledOption = item.value;
|
|
10906
|
+
if (!leveledOption) return;
|
|
10907
|
+
const [option] = leveledOption;
|
|
10908
|
+
e.stopPropagation();
|
|
10909
|
+
e.preventDefault();
|
|
10910
|
+
if (option && option.children && option.children.length > 0) {
|
|
10911
|
+
if (collapsedKeys.includes(item.key) && e.key === "ArrowRight") {
|
|
10912
|
+
setCollapsedKeys((prevKeys) => prevKeys.filter((k) => k !== item.key));
|
|
10913
|
+
} else if (!collapsedKeys.includes(item.key) && e.key === "ArrowLeft") {
|
|
10914
|
+
setCollapsedKeys((prevKeys) => [...prevKeys, item.key]);
|
|
10918
10915
|
}
|
|
10919
|
-
return;
|
|
10920
10916
|
}
|
|
10921
|
-
}
|
|
10922
|
-
if (e.key === "Enter") {
|
|
10923
|
-
if (state.isOpen) {
|
|
10924
|
-
e.preventDefault();
|
|
10925
|
-
}
|
|
10926
|
-
const focusedKey = state.selectionManager.focusedKey;
|
|
10927
|
-
if (focusedKey != null) {
|
|
10928
|
-
state.selectionManager.toggleSelection(focusedKey);
|
|
10929
|
-
}
|
|
10930
|
-
return;
|
|
10931
|
-
}
|
|
10932
|
-
if (e.key === "Escape") {
|
|
10933
|
-
state.close();
|
|
10934
10917
|
return;
|
|
10935
10918
|
}
|
|
10936
10919
|
}
|
|
10937
|
-
if (e.key === "
|
|
10938
|
-
|
|
10939
|
-
|
|
10920
|
+
if (e.key === "Enter" && state.isOpen) {
|
|
10921
|
+
e.preventDefault();
|
|
10922
|
+
}
|
|
10923
|
+
if (isMultiSelect && e.key === "Tab") {
|
|
10940
10924
|
return;
|
|
10941
10925
|
}
|
|
10942
10926
|
inputProps.onKeyDown && inputProps.onKeyDown(e);
|
|
@@ -10952,7 +10936,10 @@ function ComboBoxInput(props) {
|
|
|
10952
10936
|
}
|
|
10953
10937
|
setIsFocused(false);
|
|
10954
10938
|
maybeCall(onBlur);
|
|
10955
|
-
state.
|
|
10939
|
+
state.setFocused(false);
|
|
10940
|
+
if (isMultiSelect && state.isOpen) {
|
|
10941
|
+
state.toggle();
|
|
10942
|
+
}
|
|
10956
10943
|
resetField();
|
|
10957
10944
|
},
|
|
10958
10945
|
onFocus: () => {
|
|
@@ -11064,27 +11051,6 @@ function ComboBoxBase(props) {
|
|
|
11064
11051
|
function resetField() {
|
|
11065
11052
|
setFieldState((prevState) => ({ ...prevState, searchValue: void 0 }));
|
|
11066
11053
|
}
|
|
11067
|
-
function onSelectionChange(keys) {
|
|
11068
|
-
if (keys === "all") {
|
|
11069
|
-
return;
|
|
11070
|
-
}
|
|
11071
|
-
const selectionChanged = !(keys.size === state.selectionManager.selectedKeys.size && [...keys].every((value) => state.selectionManager.selectedKeys.has(value)));
|
|
11072
|
-
if (multiselect && keys.size === 0) {
|
|
11073
|
-
selectionChanged && onSelect([], []);
|
|
11074
|
-
return;
|
|
11075
|
-
}
|
|
11076
|
-
const selectedKeys2 = [...keys.values()];
|
|
11077
|
-
const selectedOptions2 = options.filter((o) => selectedKeys2.includes(valueToKey(getOptionValue(o))));
|
|
11078
|
-
if (!multiselect && selectedOptions2[0] === addNewOption && onAddNew) {
|
|
11079
|
-
onAddNew(fieldState.inputValue);
|
|
11080
|
-
state.close();
|
|
11081
|
-
return;
|
|
11082
|
-
}
|
|
11083
|
-
selectionChanged && onSelect(selectedKeys2.map(keyToValue), selectedOptions2);
|
|
11084
|
-
if (!multiselect) {
|
|
11085
|
-
state.close();
|
|
11086
|
-
}
|
|
11087
|
-
}
|
|
11088
11054
|
function onInputChange(value) {
|
|
11089
11055
|
if (value !== fieldState.inputValue) {
|
|
11090
11056
|
setFieldState((prevState) => ({ ...prevState, inputValue: value, searchValue: value }));
|
|
@@ -11118,6 +11084,9 @@ function ComboBoxBase(props) {
|
|
|
11118
11084
|
(item) => /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_stately7.Item, { textValue: getOptionLabel(item), children: getOptionMenuLabel(item) }, valueToKey(getOptionValue(item))),
|
|
11119
11085
|
[getOptionValue, getOptionLabel, getOptionMenuLabel]
|
|
11120
11086
|
);
|
|
11087
|
+
const selectedKeys = (0, import_react49.useMemo)(() => {
|
|
11088
|
+
return selectedOptions.map((o) => valueToKey(getOptionValue(o)));
|
|
11089
|
+
}, [selectedOptions, getOptionValue]);
|
|
11121
11090
|
const comboBoxProps = {
|
|
11122
11091
|
...otherProps,
|
|
11123
11092
|
disabledKeys: Object.keys(disabledOptionsWithReasons),
|
|
@@ -11132,29 +11101,36 @@ function ComboBoxBase(props) {
|
|
|
11132
11101
|
const state = (0, import_react_stately7.useComboBoxState)({
|
|
11133
11102
|
...comboBoxProps,
|
|
11134
11103
|
allowsEmptyCollection: true,
|
|
11135
|
-
|
|
11136
|
-
//
|
|
11137
|
-
|
|
11138
|
-
//
|
|
11139
|
-
|
|
11140
|
-
|
|
11141
|
-
|
|
11142
|
-
|
|
11143
|
-
|
|
11104
|
+
selectionMode: multiselect ? "multiple" : "single",
|
|
11105
|
+
// For multi-select, disable close-on-blur to prevent `commitValue` from calling `onChange`
|
|
11106
|
+
// with a stale `displayValue` (the controlled `value` prop before React re-renders).
|
|
11107
|
+
// We handle menu close manually in ComboBoxInput's onBlur via `state.toggle()`.
|
|
11108
|
+
...multiselect ? { shouldCloseOnBlur: false } : {},
|
|
11109
|
+
// Use the new value/onChange API for native multi-select support
|
|
11110
|
+
value: multiselect ? selectedKeys : selectedKeys[0] ?? null,
|
|
11111
|
+
// Don't call state.close() inside onChange — `state.close` is mapped to `commitValue` which
|
|
11112
|
+
// re-triggers onChange, causing an infinite loop. The native state handles menu close automatically
|
|
11113
|
+
// for single-select (closes on value change) and multi-select (stays open).
|
|
11114
|
+
onChange: (newValue) => {
|
|
11115
|
+
if (multiselect) {
|
|
11116
|
+
const keys = newValue ?? [];
|
|
11117
|
+
const newSelectedOptions = options.filter((o) => keys.includes(valueToKey(getOptionValue(o))));
|
|
11118
|
+
onSelect(keys.map(keyToValue), newSelectedOptions);
|
|
11119
|
+
} else {
|
|
11120
|
+
const key = newValue;
|
|
11121
|
+
if (key === null || key === void 0) {
|
|
11122
|
+
onSelect([], []);
|
|
11123
|
+
return;
|
|
11124
|
+
}
|
|
11125
|
+
const selectedOption = options.find((o) => valueToKey(getOptionValue(o)) === key);
|
|
11126
|
+
if (selectedOption === addNewOption && onAddNew) {
|
|
11127
|
+
onAddNew(fieldState.inputValue);
|
|
11128
|
+
return;
|
|
11129
|
+
}
|
|
11130
|
+
onSelect([keyToValue(key)], selectedOption ? [selectedOption] : []);
|
|
11144
11131
|
}
|
|
11145
11132
|
}
|
|
11146
11133
|
});
|
|
11147
|
-
const selectedKeys = (0, import_react49.useMemo)(() => {
|
|
11148
|
-
return selectedOptions.map((o) => valueToKey(getOptionValue(o)));
|
|
11149
|
-
}, [selectedOptions, getOptionValue]);
|
|
11150
|
-
state.selectionManager.state = (0, import_react_stately7.useMultipleSelectionState)({
|
|
11151
|
-
selectionMode: multiselect ? "multiple" : "single",
|
|
11152
|
-
// Do not allow an empty selection if single select mode
|
|
11153
|
-
disallowEmptySelection: !multiselect,
|
|
11154
|
-
selectedKeys,
|
|
11155
|
-
onSelectionChange,
|
|
11156
|
-
disabledKeys: Object.keys(disabledOptionsWithReasons)
|
|
11157
|
-
});
|
|
11158
11134
|
const [debouncedSearch] = (0, import_use_debounce5.useDebounce)(searchValue, 300);
|
|
11159
11135
|
(0, import_react49.useEffect)(() => {
|
|
11160
11136
|
if (state.isOpen && multiselect && !debouncedSearch) {
|
|
@@ -11196,7 +11172,10 @@ function ComboBoxBase(props) {
|
|
|
11196
11172
|
scrollRef: listBoxRef,
|
|
11197
11173
|
shouldFlip: true,
|
|
11198
11174
|
isOpen: state.isOpen,
|
|
11199
|
-
|
|
11175
|
+
// For multi-select, use toggle() instead of close() to avoid commitValue(), which
|
|
11176
|
+
// calls onChange(displayValue) with a potentially stale controlled value. For single-select,
|
|
11177
|
+
// close() (i.e. commitValue) is correct — it commits the input text to the selected value.
|
|
11178
|
+
onClose: multiselect ? () => state.toggle() : state.close,
|
|
11200
11179
|
placement: "bottom left",
|
|
11201
11180
|
offset: borderless ? 8 : 4
|
|
11202
11181
|
});
|
|
@@ -11238,7 +11217,7 @@ function ComboBoxBase(props) {
|
|
|
11238
11217
|
triggerRef,
|
|
11239
11218
|
popoverRef,
|
|
11240
11219
|
positionProps,
|
|
11241
|
-
onClose: () => state.close(),
|
|
11220
|
+
onClose: () => multiselect ? state.toggle() : state.close(),
|
|
11242
11221
|
isOpen: state.isOpen,
|
|
11243
11222
|
minWidth: 200,
|
|
11244
11223
|
children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
|