@homebound/beam 2.320.0 → 2.320.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.
|
@@ -72,7 +72,8 @@ export type OptionsOrLoad<O> = O[] | {
|
|
|
72
72
|
/** The full list of options, after load() has been fired. */
|
|
73
73
|
options: O[] | undefined;
|
|
74
74
|
};
|
|
75
|
-
|
|
75
|
+
/** Transforms/simplifies `optionsOrLoad` into just options, with unsetLabel maybe added. */
|
|
76
|
+
export declare function initializeOptions<O, V extends Value>(optionsOrLoad: OptionsOrLoad<O>, getOptionValue: (opt: O) => V, unsetLabel: string | undefined): O[];
|
|
76
77
|
/** A marker option to automatically add an "Unset" option to the start of options. */
|
|
77
78
|
export declare const unsetOption: {};
|
|
78
79
|
export declare function disabledOptionToKeyedTuple(disabledOption: Value | {
|
|
@@ -25,27 +25,31 @@ const utils_1 = require("../../utils");
|
|
|
25
25
|
function ComboBoxBase(props) {
|
|
26
26
|
var _a, _b, _c, _d;
|
|
27
27
|
const { fieldProps } = (0, PresentationContext_1.usePresentationContext)();
|
|
28
|
-
const { disabled, readOnly, onSelect, options, multiselect = false, values = [], nothingSelectedText = "", contrast, disabledOptions, borderless, unsetLabel, getOptionLabel: propOptionLabel, getOptionValue: propOptionValue, getOptionMenuLabel: propOptionMenuLabel, ...otherProps } = props;
|
|
28
|
+
const { disabled, readOnly, onSelect, options: propOptions, multiselect = false, values = [], nothingSelectedText = "", contrast, disabledOptions, borderless, unsetLabel, getOptionLabel: propOptionLabel, getOptionValue: propOptionValue, getOptionMenuLabel: propOptionMenuLabel, ...otherProps } = props;
|
|
29
29
|
const labelStyle = (_b = (_a = otherProps.labelStyle) !== null && _a !== void 0 ? _a : fieldProps === null || fieldProps === void 0 ? void 0 : fieldProps.labelStyle) !== null && _b !== void 0 ? _b : "above";
|
|
30
|
-
// Call `initializeOptions` to prepend the `unset` option if the `unsetLabel` was provided.
|
|
31
|
-
const maybeOptions = (0, react_1.useMemo)(() => initializeOptions(options, unsetLabel), [options, unsetLabel]);
|
|
32
30
|
// Memoize the callback functions and handle the `unset` option if provided.
|
|
33
31
|
const getOptionLabel = (0, react_1.useCallback)((o) => (unsetLabel && o === exports.unsetOption ? unsetLabel : propOptionLabel(o)), [propOptionLabel, unsetLabel]);
|
|
34
32
|
const getOptionValue = (0, react_1.useCallback)((o) => (unsetLabel && o === exports.unsetOption ? undefined : propOptionValue(o)), [propOptionValue, unsetLabel]);
|
|
35
33
|
const getOptionMenuLabel = (0, react_1.useCallback)((o) => propOptionMenuLabel ? propOptionMenuLabel(o, Boolean(unsetLabel) && o === exports.unsetOption) : getOptionLabel(o), [propOptionMenuLabel, unsetLabel, getOptionLabel]);
|
|
34
|
+
// Call `initializeOptions` to prepend the `unset` option if the `unsetLabel` was provided.
|
|
35
|
+
const options = (0, react_1.useMemo)(() => initializeOptions(propOptions, getOptionValue, unsetLabel),
|
|
36
|
+
// If the caller is using { current, load, options }, memoize on only `current` and `options` values.
|
|
37
|
+
// ...and don't bother on memoizing on getOptionValue b/c it's basically always a lambda
|
|
38
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
39
|
+
Array.isArray(propOptions) ? [propOptions, unsetLabel] : [propOptions.current, propOptions.options, unsetLabel]);
|
|
36
40
|
const { contains } = (0, react_aria_1.useFilter)({ sensitivity: "base" });
|
|
37
41
|
const isDisabled = !!disabled;
|
|
38
42
|
const isReadOnly = !!readOnly;
|
|
43
|
+
// Do a one-time initialize of fieldState
|
|
39
44
|
const [fieldState, setFieldState] = (0, react_1.useState)(() => {
|
|
40
45
|
var _a;
|
|
41
|
-
const
|
|
42
|
-
const selectedOptions = initOptions.filter((o) => values.includes(getOptionValue(o)));
|
|
46
|
+
const selectedOptions = options.filter((o) => values.includes(getOptionValue(o)));
|
|
43
47
|
return {
|
|
44
48
|
selectedKeys: (_a = selectedOptions === null || selectedOptions === void 0 ? void 0 : selectedOptions.map((o) => (0, Value_1.valueToKey)(getOptionValue(o)))) !== null && _a !== void 0 ? _a : [],
|
|
45
|
-
inputValue: getInputValue(
|
|
46
|
-
filteredOptions:
|
|
47
|
-
allOptions:
|
|
48
|
-
selectedOptions
|
|
49
|
+
inputValue: getInputValue(options.filter((o) => values === null || values === void 0 ? void 0 : values.includes(getOptionValue(o))), getOptionLabel, multiselect, nothingSelectedText),
|
|
50
|
+
filteredOptions: options,
|
|
51
|
+
allOptions: options,
|
|
52
|
+
selectedOptions,
|
|
49
53
|
optionsLoading: false,
|
|
50
54
|
};
|
|
51
55
|
});
|
|
@@ -112,9 +116,9 @@ function ComboBoxBase(props) {
|
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
async function maybeInitLoad() {
|
|
115
|
-
if (!Array.isArray(
|
|
119
|
+
if (!Array.isArray(propOptions)) {
|
|
116
120
|
setFieldState((prevState) => ({ ...prevState, optionsLoading: true }));
|
|
117
|
-
await
|
|
121
|
+
await propOptions.load();
|
|
118
122
|
setFieldState((prevState) => ({ ...prevState, optionsLoading: false }));
|
|
119
123
|
}
|
|
120
124
|
}
|
|
@@ -198,41 +202,29 @@ function ComboBoxBase(props) {
|
|
|
198
202
|
// 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
|
|
199
203
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
200
204
|
[values]);
|
|
201
|
-
//
|
|
202
|
-
// If options are an object, then use the `initial` array if the menu has not been opened
|
|
203
|
-
// Otherwise, use the current fieldState array options.
|
|
204
|
-
const maybeUpdatedOptions = Array.isArray(maybeOptions)
|
|
205
|
-
? maybeOptions
|
|
206
|
-
: firstOpen.current === false && !fieldState.optionsLoading
|
|
207
|
-
? maybeOptions.options
|
|
208
|
-
: maybeOptions.current;
|
|
205
|
+
// Re-sync fieldState.allOptions
|
|
209
206
|
(0, react_1.useEffect)(() => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
filteredOptions: maybeUpdatedArray,
|
|
227
|
-
allOptions: maybeUpdatedArray,
|
|
228
|
-
};
|
|
229
|
-
});
|
|
230
|
-
}
|
|
207
|
+
setFieldState((prevState) => {
|
|
208
|
+
var _a;
|
|
209
|
+
const selectedOptions = options.filter((o) => values === null || values === void 0 ? void 0 : values.includes(getOptionValue(o)));
|
|
210
|
+
return {
|
|
211
|
+
...prevState,
|
|
212
|
+
selectedKeys: (_a = selectedOptions === null || selectedOptions === void 0 ? void 0 : selectedOptions.map((o) => (0, Value_1.valueToKey)(getOptionValue(o)))) !== null && _a !== void 0 ? _a : [],
|
|
213
|
+
inputValue: selectedOptions.length === 1
|
|
214
|
+
? getOptionLabel(selectedOptions[0])
|
|
215
|
+
: multiselect && selectedOptions.length === 0
|
|
216
|
+
? nothingSelectedText
|
|
217
|
+
: "",
|
|
218
|
+
selectedOptions: selectedOptions,
|
|
219
|
+
filteredOptions: options,
|
|
220
|
+
allOptions: options,
|
|
221
|
+
};
|
|
222
|
+
});
|
|
231
223
|
},
|
|
232
|
-
//
|
|
233
|
-
//
|
|
224
|
+
// We're primarily only re-setting `allOptions`, and so recalc selected as well, but we don't
|
|
225
|
+
// want to depend on values/etc., b/c we'll defer to their useEffects to update their state
|
|
234
226
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
235
|
-
[
|
|
227
|
+
[options]);
|
|
236
228
|
// For the most part, the returned props contain `aria-*` and `id` attributes for accessibility purposes.
|
|
237
229
|
const { buttonProps: triggerProps, inputProps, listBoxProps, labelProps, } = (0, react_aria_1.useComboBox)({
|
|
238
230
|
...comboBoxProps,
|
|
@@ -269,19 +261,32 @@ function getInputValue(selectedOptions, getOptionLabel, multiselect, nothingSele
|
|
|
269
261
|
? nothingSelectedText
|
|
270
262
|
: "";
|
|
271
263
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
264
|
+
/** Transforms/simplifies `optionsOrLoad` into just options, with unsetLabel maybe added. */
|
|
265
|
+
function initializeOptions(optionsOrLoad, getOptionValue, unsetLabel) {
|
|
266
|
+
const opts = [];
|
|
267
|
+
if (unsetLabel) {
|
|
268
|
+
opts.push(exports.unsetOption);
|
|
275
269
|
}
|
|
276
|
-
if (Array.isArray(
|
|
277
|
-
|
|
270
|
+
if (Array.isArray(optionsOrLoad)) {
|
|
271
|
+
opts.push(...optionsOrLoad);
|
|
278
272
|
}
|
|
279
|
-
|
|
273
|
+
else {
|
|
274
|
+
const { options, current } = optionsOrLoad;
|
|
275
|
+
if (options) {
|
|
276
|
+
opts.push(...options);
|
|
277
|
+
}
|
|
278
|
+
// Even if the SelectField has lazy-loaded options, make sure the current value is really in there
|
|
279
|
+
if (current) {
|
|
280
|
+
const value = getOptionValue(current);
|
|
281
|
+
const found = options && options.find((o) => getOptionValue(o) === value);
|
|
282
|
+
if (!found) {
|
|
283
|
+
opts.push(current);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return opts;
|
|
280
288
|
}
|
|
281
289
|
exports.initializeOptions = initializeOptions;
|
|
282
|
-
function getOptionsWithUnset(unsetLabel, options) {
|
|
283
|
-
return [exports.unsetOption, ...(options ? options : [])];
|
|
284
|
-
}
|
|
285
290
|
/** A marker option to automatically add an "Unset" option to the start of options. */
|
|
286
291
|
exports.unsetOption = {};
|
|
287
292
|
function disabledOptionToKeyedTuple(disabledOption) {
|