@lumx/react 4.18.0-next.1 → 4.18.0-next.3
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/index.d.ts +18 -5
- package/index.js +71 -20
- package/index.js.map +1 -1
- package/package.json +3 -3
package/index.d.ts
CHANGED
|
@@ -815,7 +815,7 @@ interface ButtonProps extends GenericProps$1, ReactToJSX<ButtonProps$1> {
|
|
|
815
815
|
* @param ref Component ref.
|
|
816
816
|
* @return React element.
|
|
817
817
|
*/
|
|
818
|
-
declare const Button: Comp<ButtonProps,
|
|
818
|
+
declare const Button: Comp<ButtonProps, HTMLAnchorElement | HTMLButtonElement>;
|
|
819
819
|
|
|
820
820
|
interface IconButtonProps$1 extends BaseButtonProps {
|
|
821
821
|
/**
|
|
@@ -1890,6 +1890,19 @@ interface ComboboxInputOptions {
|
|
|
1890
1890
|
* @default false (true when filter is 'off')
|
|
1891
1891
|
*/
|
|
1892
1892
|
openOnFocus?: boolean;
|
|
1893
|
+
/**
|
|
1894
|
+
* Controls what happens to the input value when an option is selected.
|
|
1895
|
+
*
|
|
1896
|
+
* - `'fill'` (default) — The input is updated with the selected option value via `onChange`.
|
|
1897
|
+
* - `'keep'` — The input value is left unchanged; `onChange` is not called.
|
|
1898
|
+
* Useful when the component manages the displayed value independently (e.g. showing
|
|
1899
|
+
* an option display name rather than the raw option ID). The filter still resets.
|
|
1900
|
+
* - `'clear'` — The input is cleared (empty string) via `onChange` after selection.
|
|
1901
|
+
* Useful for multi-select patterns where typing starts fresh after each pick.
|
|
1902
|
+
*
|
|
1903
|
+
* @default 'fill'
|
|
1904
|
+
*/
|
|
1905
|
+
selectionMode?: 'fill' | 'keep' | 'clear';
|
|
1893
1906
|
}
|
|
1894
1907
|
|
|
1895
1908
|
/**
|
|
@@ -2197,7 +2210,7 @@ declare const Combobox: {
|
|
|
2197
2210
|
/** Provides shared combobox context (handle, listbox ID, anchor ref) to all sub-components. */
|
|
2198
2211
|
Provider: typeof ComboboxProvider;
|
|
2199
2212
|
/** Button trigger for select-only combobox mode with keyboard navigation and typeahead. */
|
|
2200
|
-
Button: (<E extends React$1.ElementType = Comp<ButtonProps,
|
|
2213
|
+
Button: (<E extends React$1.ElementType = Comp<ButtonProps, HTMLAnchorElement | HTMLButtonElement>>(props: Omit<HasPolymorphicAs$1<E>, "children" | "role" | "aria-activedescendant" | "aria-controls" | "aria-expanded" | "aria-haspopup"> & _lumx_core_js_types.HasRequiredLinkHref<E> & ReactToJSX<ComboboxButtonProps$1> & React$1.ComponentProps<E> & {
|
|
2201
2214
|
ref?: ComponentRef<E> | undefined;
|
|
2202
2215
|
}) => React.JSX.Element) & {
|
|
2203
2216
|
displayName: string;
|
|
@@ -2723,7 +2736,7 @@ declare const GenericBlockGapSize: Pick<{
|
|
|
2723
2736
|
readonly medium: "medium";
|
|
2724
2737
|
readonly big: "big";
|
|
2725
2738
|
readonly huge: "huge";
|
|
2726
|
-
}, "big" | "
|
|
2739
|
+
}, "big" | "tiny" | "medium" | "regular" | "huge">;
|
|
2727
2740
|
type GenericBlockGapSize = ValueOf<typeof GenericBlockGapSize>;
|
|
2728
2741
|
|
|
2729
2742
|
interface GenericBlockProps$1 extends FlexBoxProps$1 {
|
|
@@ -2953,7 +2966,7 @@ interface GridColumnProps extends GenericProps$1, ReactToJSX<GridColumnProps$1>
|
|
|
2953
2966
|
*/
|
|
2954
2967
|
declare const GridColumn: Comp<GridColumnProps, HTMLElement>;
|
|
2955
2968
|
|
|
2956
|
-
declare const ICON_SIZES: ("
|
|
2969
|
+
declare const ICON_SIZES: ("s" | "m" | "xxs" | "xs" | "l" | "xl" | "xxl")[];
|
|
2957
2970
|
|
|
2958
2971
|
type IconSizes = (typeof ICON_SIZES)[number];
|
|
2959
2972
|
/**
|
|
@@ -3454,7 +3467,7 @@ interface LinkProps extends GenericProps$1, ReactToJSX<LinkProps$1> {
|
|
|
3454
3467
|
* @param ref Component ref.
|
|
3455
3468
|
* @return React element.
|
|
3456
3469
|
*/
|
|
3457
|
-
declare const Link: Comp<LinkProps,
|
|
3470
|
+
declare const Link: Comp<LinkProps, HTMLAnchorElement | HTMLButtonElement>;
|
|
3458
3471
|
|
|
3459
3472
|
/**
|
|
3460
3473
|
* Defines the props of the component.
|
package/index.js
CHANGED
|
@@ -6460,6 +6460,12 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6460
6460
|
/** Last notified input value, to re-fire `optionsChange` when the user keeps typing while empty. */
|
|
6461
6461
|
let lastInputValue = '';
|
|
6462
6462
|
|
|
6463
|
+
/** Last notified loading state, used to replay current state to late subscribers. */
|
|
6464
|
+
let lastLoadingState = false;
|
|
6465
|
+
|
|
6466
|
+
/** Number of currently mounted skeleton placeholders. */
|
|
6467
|
+
let skeletonCount = 0;
|
|
6468
|
+
|
|
6463
6469
|
/** Event subscribers managed by the handle. */
|
|
6464
6470
|
const subscribers = {
|
|
6465
6471
|
open: new Set(),
|
|
@@ -6474,6 +6480,20 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6474
6480
|
subscribers[event].forEach(cb => cb(value));
|
|
6475
6481
|
}
|
|
6476
6482
|
|
|
6483
|
+
/** Count visible (non-filtered) options. */
|
|
6484
|
+
function getVisibleOptionCount() {
|
|
6485
|
+
let count = 0;
|
|
6486
|
+
for (const reg of optionRegistrations.values()) {
|
|
6487
|
+
if (!reg.lastFiltered) count += 1;
|
|
6488
|
+
}
|
|
6489
|
+
return count;
|
|
6490
|
+
}
|
|
6491
|
+
|
|
6492
|
+
/** True when the popup has visible content (options or skeletons). */
|
|
6493
|
+
function hasVisibleContent() {
|
|
6494
|
+
return getVisibleOptionCount() > 0 || skeletonCount > 0;
|
|
6495
|
+
}
|
|
6496
|
+
|
|
6477
6497
|
/**
|
|
6478
6498
|
* Notify all registered sections and fire `optionsChange` if the visible option count changed
|
|
6479
6499
|
* or if the input value changed while the list is empty (so `emptyMessage` callbacks get
|
|
@@ -6484,10 +6504,7 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6484
6504
|
for (const [sectionElement] of sectionRegistrations) {
|
|
6485
6505
|
notifySection(sectionElement, sectionRegistrations, optionRegistrations);
|
|
6486
6506
|
}
|
|
6487
|
-
|
|
6488
|
-
for (const reg of optionRegistrations.values()) {
|
|
6489
|
-
if (!reg.lastFiltered) visibleCount += 1;
|
|
6490
|
-
}
|
|
6507
|
+
const visibleCount = getVisibleOptionCount();
|
|
6491
6508
|
const inputValue = trigger?.value ?? '';
|
|
6492
6509
|
const isEmpty = visibleCount === 0;
|
|
6493
6510
|
if (visibleCount !== lastOptionsLength || isEmpty && inputValue !== lastInputValue) {
|
|
@@ -6498,6 +6515,12 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6498
6515
|
inputValue
|
|
6499
6516
|
});
|
|
6500
6517
|
}
|
|
6518
|
+
|
|
6519
|
+
// Re-evaluate aria-expanded when the combobox is open — visible content may have
|
|
6520
|
+
// changed due to filtering, option register/unregister, or skeleton transitions.
|
|
6521
|
+
if (isOpenState) {
|
|
6522
|
+
trigger?.setAttribute('aria-expanded', String(hasVisibleContent()));
|
|
6523
|
+
}
|
|
6501
6524
|
}
|
|
6502
6525
|
|
|
6503
6526
|
// ── Skeleton loading tracking ──────────────────────────────
|
|
@@ -6505,9 +6528,6 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6505
6528
|
/** Delay before announcing loading in the live region (ms). */
|
|
6506
6529
|
const LOADING_ANNOUNCEMENT_DELAY = 500;
|
|
6507
6530
|
|
|
6508
|
-
/** Number of currently mounted skeleton placeholders. */
|
|
6509
|
-
let skeletonCount = 0;
|
|
6510
|
-
|
|
6511
6531
|
/** Timer for debounced loading announcement. */
|
|
6512
6532
|
let loadingTimer;
|
|
6513
6533
|
|
|
@@ -6533,6 +6553,7 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6533
6553
|
*/
|
|
6534
6554
|
function onSkeletonCountChange() {
|
|
6535
6555
|
const isLoading = skeletonCount > 0;
|
|
6556
|
+
lastLoadingState = isLoading;
|
|
6536
6557
|
notify('loadingChange', isLoading);
|
|
6537
6558
|
if (isLoading) {
|
|
6538
6559
|
startLoadingAnnouncementTimer();
|
|
@@ -6735,8 +6756,8 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6735
6756
|
startLoadingAnnouncementTimer();
|
|
6736
6757
|
}
|
|
6737
6758
|
|
|
6738
|
-
// Update aria-expanded on trigger
|
|
6739
|
-
trigger?.setAttribute('aria-expanded', String(isOpen));
|
|
6759
|
+
// Update aria-expanded on trigger (false when no visible options or skeletons)
|
|
6760
|
+
trigger?.setAttribute('aria-expanded', String(isOpen && hasVisibleContent()));
|
|
6740
6761
|
notify('open', isOpen);
|
|
6741
6762
|
},
|
|
6742
6763
|
select(option) {
|
|
@@ -6871,6 +6892,17 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6871
6892
|
},
|
|
6872
6893
|
subscribe(event, callback) {
|
|
6873
6894
|
subscribers[event].add(callback);
|
|
6895
|
+
// Replay current loading state to late subscribers so that framework wrappers
|
|
6896
|
+
// that subscribe after initial mount (e.g. async Vue watchers) don't miss the
|
|
6897
|
+
// initial events fired during mount.
|
|
6898
|
+
if (event === 'open' && isOpenState) {
|
|
6899
|
+
callback(true);
|
|
6900
|
+
}
|
|
6901
|
+
if (event === 'loadingChange' && lastLoadingState) {
|
|
6902
|
+
callback(true);
|
|
6903
|
+
}
|
|
6904
|
+
|
|
6905
|
+
// Cleanup function
|
|
6874
6906
|
return () => {
|
|
6875
6907
|
subscribers[event].delete(callback);
|
|
6876
6908
|
};
|
|
@@ -6882,6 +6914,7 @@ function setupCombobox(callbacks, options, onTriggerAttach) {
|
|
|
6882
6914
|
filterValue = '';
|
|
6883
6915
|
lastOptionsLength = 0;
|
|
6884
6916
|
lastInputValue = '';
|
|
6917
|
+
lastLoadingState = false;
|
|
6885
6918
|
optionRegistrations.clear();
|
|
6886
6919
|
sectionRegistrations.clear();
|
|
6887
6920
|
skeletonCount = 0;
|
|
@@ -7278,6 +7311,10 @@ const ComboboxButton = Object.assign(forwardRefPolymorphic((props, ref) => {
|
|
|
7278
7311
|
setHandle
|
|
7279
7312
|
} = useComboboxContext();
|
|
7280
7313
|
const [isOpen] = useComboboxOpen();
|
|
7314
|
+
const state = useComboboxEvent('optionsChange', {
|
|
7315
|
+
optionsLength: 0
|
|
7316
|
+
});
|
|
7317
|
+
const isLoading = useComboboxEvent('loadingChange', false);
|
|
7281
7318
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7282
7319
|
const {
|
|
7283
7320
|
as,
|
|
@@ -7319,7 +7356,7 @@ const ComboboxButton = Object.assign(forwardRefPolymorphic((props, ref) => {
|
|
|
7319
7356
|
value,
|
|
7320
7357
|
labelDisplayMode,
|
|
7321
7358
|
listboxId,
|
|
7322
|
-
isOpen,
|
|
7359
|
+
isOpen: isOpen && (!!state?.optionsLength || isLoading),
|
|
7323
7360
|
ref: mergedRef
|
|
7324
7361
|
}, {
|
|
7325
7362
|
Button: ButtonComp,
|
|
@@ -7350,8 +7387,10 @@ function setupComboboxInput(input, options) {
|
|
|
7350
7387
|
let handle;
|
|
7351
7388
|
const {
|
|
7352
7389
|
filter = 'auto',
|
|
7390
|
+
selectionMode = 'fill',
|
|
7353
7391
|
onSelect: optionOnSelect,
|
|
7354
|
-
onInput: onInputCallback
|
|
7392
|
+
onInput: onInputCallback,
|
|
7393
|
+
onChange: onChangeCallback
|
|
7355
7394
|
} = options;
|
|
7356
7395
|
const openOnFocus = options.openOnFocus ?? filter === 'off';
|
|
7357
7396
|
const autoFilter = filter === 'auto';
|
|
@@ -7367,15 +7406,20 @@ function setupComboboxInput(input, options) {
|
|
|
7367
7406
|
let userHasTyped = false;
|
|
7368
7407
|
|
|
7369
7408
|
/**
|
|
7370
|
-
* Wraps the consumer's onSelect to perform input-mode side effects after selection
|
|
7371
|
-
*
|
|
7409
|
+
* Wraps the consumer's onSelect to perform input-mode side effects after selection,
|
|
7410
|
+
* and drive `onChange` according to `selectionMode`.
|
|
7411
|
+
* Filter and typing state are always reset on selection.
|
|
7372
7412
|
*/
|
|
7373
7413
|
const onSelect = option => {
|
|
7374
7414
|
optionOnSelect?.(option);
|
|
7375
7415
|
userHasTyped = false;
|
|
7376
|
-
if (autoFilter)
|
|
7377
|
-
|
|
7416
|
+
if (autoFilter) handle.setFilter('');
|
|
7417
|
+
if (selectionMode === 'fill') {
|
|
7418
|
+
onChangeCallback?.(option.value);
|
|
7419
|
+
} else if (selectionMode === 'clear') {
|
|
7420
|
+
onChangeCallback?.('');
|
|
7378
7421
|
}
|
|
7422
|
+
// 'keep': onChange is not called — input value stays as-is.
|
|
7379
7423
|
};
|
|
7380
7424
|
handle = setupCombobox({
|
|
7381
7425
|
onSelect
|
|
@@ -8118,8 +8162,13 @@ const ComboboxInput = forwardRef((props, ref) => {
|
|
|
8118
8162
|
onSelect,
|
|
8119
8163
|
filter,
|
|
8120
8164
|
openOnFocus,
|
|
8165
|
+
selectionMode,
|
|
8121
8166
|
...otherProps
|
|
8122
8167
|
} = props;
|
|
8168
|
+
const state = useComboboxEvent('optionsChange', {
|
|
8169
|
+
optionsLength: 0
|
|
8170
|
+
});
|
|
8171
|
+
const isLoading = useComboboxEvent('loadingChange', false);
|
|
8123
8172
|
const internalInputRef = useRef(null);
|
|
8124
8173
|
const mergedInputRef = useMergeRefs(externalInputRef, internalInputRef);
|
|
8125
8174
|
|
|
@@ -8135,14 +8184,15 @@ const ComboboxInput = forwardRef((props, ref) => {
|
|
|
8135
8184
|
if (!input) return undefined;
|
|
8136
8185
|
const handle = setupComboboxInput(input, {
|
|
8137
8186
|
onSelect(option) {
|
|
8138
|
-
// Update controlled value through React's normal onChange flow.
|
|
8139
|
-
onChangeRef.current?.(option.value);
|
|
8140
8187
|
onSelectRef.current?.(option);
|
|
8141
8188
|
},
|
|
8189
|
+
onChange(value) {
|
|
8190
|
+
onChangeRef.current?.(value);
|
|
8191
|
+
},
|
|
8142
8192
|
onInput(value) {
|
|
8143
|
-
// Keep controlled value in sync.
|
|
8144
8193
|
onChangeRef.current?.(value);
|
|
8145
8194
|
},
|
|
8195
|
+
selectionMode,
|
|
8146
8196
|
filter,
|
|
8147
8197
|
openOnFocus
|
|
8148
8198
|
});
|
|
@@ -8151,7 +8201,7 @@ const ComboboxInput = forwardRef((props, ref) => {
|
|
|
8151
8201
|
handle.destroy();
|
|
8152
8202
|
setHandle(null);
|
|
8153
8203
|
};
|
|
8154
|
-
}, [filter, openOnFocus, setHandle]);
|
|
8204
|
+
}, [filter, openOnFocus, selectionMode, setHandle]);
|
|
8155
8205
|
const handleToggle = useCallback(() => {
|
|
8156
8206
|
setIsOpen(!isOpen);
|
|
8157
8207
|
internalInputRef.current?.focus();
|
|
@@ -8160,7 +8210,7 @@ const ComboboxInput = forwardRef((props, ref) => {
|
|
|
8160
8210
|
...otherProps,
|
|
8161
8211
|
ref,
|
|
8162
8212
|
listboxId,
|
|
8163
|
-
isOpen,
|
|
8213
|
+
isOpen: isOpen && (!!state?.optionsLength || isLoading),
|
|
8164
8214
|
filter,
|
|
8165
8215
|
inputRef: mergedInputRef,
|
|
8166
8216
|
textFieldRef: anchorRef,
|
|
@@ -18217,6 +18267,7 @@ const SelectTextField$2 = (props, {
|
|
|
18217
18267
|
children: [/*#__PURE__*/jsx(Combobox.Input, {
|
|
18218
18268
|
label: label,
|
|
18219
18269
|
...inputProps,
|
|
18270
|
+
selectionMode: "keep",
|
|
18220
18271
|
chips: chips
|
|
18221
18272
|
}), /*#__PURE__*/jsxs(Combobox.Popover, {
|
|
18222
18273
|
fitToAnchorWidth: "minWidth",
|