@lumx/core 4.12.0-next.0 → 4.12.0-next.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/components-and-utils.css +2 -0
- package/js/components/Combobox/ComboboxState.d.ts +14 -5
- package/js/components/Combobox/types.d.ts +11 -4
- package/js/utils/select/getOptionDisplayName.d.ts +8 -0
- package/js/utils/select/types.d.ts +197 -0
- package/lumx.css +2 -0
- package/package.json +2 -2
- package/scss/components/text-field/_mixins.scss +1 -0
package/components-and-utils.css
CHANGED
|
@@ -9572,6 +9572,7 @@ table {
|
|
|
9572
9572
|
align-items: center;
|
|
9573
9573
|
margin: calc((var(--lumx-text-field-input-min-height) - var(--lumx-size-s) - 6px) / 2 + 3px) 0;
|
|
9574
9574
|
gap: 6px;
|
|
9575
|
+
min-width: 0;
|
|
9575
9576
|
}
|
|
9576
9577
|
.lumx-select--theme-light .lumx-select__input-native {
|
|
9577
9578
|
display: block;
|
|
@@ -11655,6 +11656,7 @@ table {
|
|
|
11655
11656
|
align-items: center;
|
|
11656
11657
|
margin: calc((var(--lumx-text-field-input-min-height) - var(--lumx-size-s) - 6px) / 2 + 3px) 0;
|
|
11657
11658
|
gap: 6px;
|
|
11659
|
+
min-width: 0;
|
|
11658
11660
|
}
|
|
11659
11661
|
.lumx-text-field__helper {
|
|
11660
11662
|
margin-top: 8px;
|
|
@@ -18,6 +18,14 @@ export interface ComboboxStateProps {
|
|
|
18
18
|
* When omitted, the empty state is not shown.
|
|
19
19
|
*/
|
|
20
20
|
emptyMessage?: string | ((inputValue: string) => string);
|
|
21
|
+
/**
|
|
22
|
+
* Message callback to display the number of available options.
|
|
23
|
+
* Called with the current visible option count and should return a human-readable string
|
|
24
|
+
* (e.g. `(n) => \`${n} result(s) available\``).
|
|
25
|
+
* Displayed when the combobox is open, not empty, not loading, and not in error.
|
|
26
|
+
* When omitted, no option count message is shown.
|
|
27
|
+
*/
|
|
28
|
+
nbOptionMessage?: (optionsLength: number) => string;
|
|
21
29
|
/**
|
|
22
30
|
* Error state title message.
|
|
23
31
|
* When provided, the error state is active (takes priority over the empty state).
|
|
@@ -39,10 +47,10 @@ export interface ComboboxStateProps {
|
|
|
39
47
|
*/
|
|
40
48
|
state?: {
|
|
41
49
|
/**
|
|
42
|
-
*
|
|
43
|
-
* Driven by the framework wrapper via the combobox handle's `
|
|
50
|
+
* The number of currently visible options.
|
|
51
|
+
* Driven by the framework wrapper via the combobox handle's `optionsChange` event.
|
|
44
52
|
*/
|
|
45
|
-
|
|
53
|
+
optionsLength?: number;
|
|
46
54
|
/**
|
|
47
55
|
* The current value of the combobox input.
|
|
48
56
|
* Passed to `emptyMessage` when it is a function.
|
|
@@ -76,12 +84,13 @@ export interface ComboboxStateComponents {
|
|
|
76
84
|
}
|
|
77
85
|
/**
|
|
78
86
|
* ComboboxState core template.
|
|
79
|
-
* Renders empty/error state messages inside the combobox popover.
|
|
87
|
+
* Renders empty/error/option-count state messages inside the combobox popover.
|
|
80
88
|
* The block itself acts as a screen reader live region (`role="status" aria-live="polite"`).
|
|
81
89
|
*
|
|
82
90
|
* Activation rules:
|
|
83
91
|
* - Error state: active when `errorMessage` is provided (presence-based).
|
|
84
|
-
* - Empty state: active when `
|
|
92
|
+
* - Empty state: active when `optionsLength` is 0 and `emptyMessage` is provided, and there is no error.
|
|
93
|
+
* - Option count: active when `nbOptionMessage` is provided, the list is not empty, not loading, and not in error.
|
|
85
94
|
*
|
|
86
95
|
* @param props Component props.
|
|
87
96
|
* @param components Injected framework-specific components.
|
|
@@ -21,11 +21,11 @@ export interface ComboboxEventMap {
|
|
|
21
21
|
/** Fired when the active descendant changes (visual focus). Payload: the option id or null. */
|
|
22
22
|
activeDescendantChange: string | null;
|
|
23
23
|
/**
|
|
24
|
-
* Fired when the visible option count
|
|
25
|
-
* Payload:
|
|
24
|
+
* Fired when the visible option count changes.
|
|
25
|
+
* Payload: the number of visible options plus the current input value.
|
|
26
26
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
optionsChange: {
|
|
28
|
+
optionsLength: number;
|
|
29
29
|
inputValue?: string;
|
|
30
30
|
} | undefined;
|
|
31
31
|
/**
|
|
@@ -86,6 +86,13 @@ export interface ComboboxHandle {
|
|
|
86
86
|
* An empty filter value clears filtering (all options become visible).
|
|
87
87
|
*/
|
|
88
88
|
setFilter(filterValue: string): void;
|
|
89
|
+
/**
|
|
90
|
+
* Re-evaluate the filter state of a single registered option.
|
|
91
|
+
* Call this after the option's `data-value` or textContent has been updated
|
|
92
|
+
* (e.g. after a framework re-render) to ensure its filtered/visible state
|
|
93
|
+
* is consistent with the current filter value.
|
|
94
|
+
*/
|
|
95
|
+
refilterOption(element: HTMLElement): void;
|
|
89
96
|
/**
|
|
90
97
|
* Register a section DOM element for state notifications.
|
|
91
98
|
* The callback is invoked immediately with the current state, and again whenever
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Selector } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Get the display name for a single option value.
|
|
4
|
+
*
|
|
5
|
+
* Resolves the option's display name by trying `getOptionName` first,
|
|
6
|
+
* then falling back to `getOptionId`, returning `''` for nullish values.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getOptionDisplayName<O>(value: O | undefined, getOptionName?: Selector<O, string | undefined | null>, getOptionId?: Selector<O>): string;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import type { HasAriaDisabled } from '../../types/HasAriaDisabled';
|
|
2
|
+
import type { HasClassName } from '../../types/HasClassName';
|
|
3
|
+
import type { HasTheme } from '../../types/HasTheme';
|
|
4
|
+
import type { JSXElement, Selector } from '../../types';
|
|
5
|
+
/**
|
|
6
|
+
* Status of the SelectTextField dropdown list.
|
|
7
|
+
*
|
|
8
|
+
* - `'idle'` — Default state, no loading indicators.
|
|
9
|
+
* - `'loading'` — Full loading: shows skeleton placeholders, hides real options.
|
|
10
|
+
* - `'loadingMore'` — Paginated loading: appends a skeleton after existing options.
|
|
11
|
+
* - `'error'` — Error state: shows an error message in the dropdown.
|
|
12
|
+
*/
|
|
13
|
+
export type SelectTextFieldStatus = 'idle' | 'loading' | 'loadingMore' | 'error';
|
|
14
|
+
/**
|
|
15
|
+
* Context passed to the `renderOption` callback alongside the option object.
|
|
16
|
+
* Contains core-computed values that the consumer should forward to `<Combobox.Option>`.
|
|
17
|
+
*/
|
|
18
|
+
export interface RenderOptionContext {
|
|
19
|
+
/** Index of the option in the current (possibly section-filtered) list. */
|
|
20
|
+
index: number;
|
|
21
|
+
/** Resolved option id (from `getOptionId`). Should be passed as `value` to `<Combobox.Option>`. */
|
|
22
|
+
value: any;
|
|
23
|
+
/** Whether this option is currently selected. Should be forwarded as `isSelected`. */
|
|
24
|
+
isSelected: boolean;
|
|
25
|
+
/** Resolved description string (from `getOptionDescription`), if any. Should be forwarded as `description`. */
|
|
26
|
+
description?: string | null;
|
|
27
|
+
}
|
|
28
|
+
export interface BaseSelectProps<O> {
|
|
29
|
+
/** List of option objects. */
|
|
30
|
+
options?: Array<O>;
|
|
31
|
+
/** Option object id selector. */
|
|
32
|
+
getOptionId: Selector<O>;
|
|
33
|
+
/** Option object name selector (falls back to id if not defined). */
|
|
34
|
+
getOptionName?: Selector<O, string | undefined | null>;
|
|
35
|
+
/** Option object description selector. */
|
|
36
|
+
getOptionDescription?: Selector<O, string | undefined | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Custom option render function (core/Vue contract).
|
|
39
|
+
* Receives the option object and a `RenderOptionContext` with core-computed props (`value`,
|
|
40
|
+
* `isSelected`, `description`, `index`). The callee must render a `<Combobox.Option>` and
|
|
41
|
+
* forward those context values, including a unique `key`.
|
|
42
|
+
*
|
|
43
|
+
* @example (Vue / core level)
|
|
44
|
+
* renderOption={(fruit, { value, isSelected, description }) => (
|
|
45
|
+
* <Combobox.Option key={value} value={value} isSelected={isSelected} description={description}>
|
|
46
|
+
* <strong>{fruit.name}</strong>
|
|
47
|
+
* </Combobox.Option>
|
|
48
|
+
* )}
|
|
49
|
+
*/
|
|
50
|
+
renderOption?: (option: O, context: RenderOptionContext) => JSXElement;
|
|
51
|
+
/**
|
|
52
|
+
* Selector returning a section id string for each option. Options with the same
|
|
53
|
+
* section id are grouped together. The id is also used as the default displayed
|
|
54
|
+
* label unless `renderSectionTitle` is provided.
|
|
55
|
+
*/
|
|
56
|
+
getSectionId?: Selector<O, string>;
|
|
57
|
+
/**
|
|
58
|
+
* Custom section title render function. Receives the section id and the options
|
|
59
|
+
* in that section. Returns custom JSX to display as the section header.
|
|
60
|
+
* When not provided, the section id is used as a plain text label.
|
|
61
|
+
*/
|
|
62
|
+
renderSectionTitle?: (sectionId: string, options: O[]) => JSXElement;
|
|
63
|
+
}
|
|
64
|
+
export interface BaseSelectComponents {
|
|
65
|
+
/** Combobox compound component. */
|
|
66
|
+
Combobox: {
|
|
67
|
+
Provider: any;
|
|
68
|
+
Button: any;
|
|
69
|
+
Input: any;
|
|
70
|
+
Popover: any;
|
|
71
|
+
List: any;
|
|
72
|
+
Section: any;
|
|
73
|
+
Option: any;
|
|
74
|
+
State: any;
|
|
75
|
+
OptionSkeleton: any;
|
|
76
|
+
};
|
|
77
|
+
/** Framework-specific InfiniteScroll component (handles IntersectionObserver lifecycle). */
|
|
78
|
+
InfiniteScroll?: any;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Props for rendering select options.
|
|
82
|
+
*/
|
|
83
|
+
export interface RenderSelectOptionsProps<O> extends BaseSelectProps<O> {
|
|
84
|
+
/** Selected option (single) or options (multiple). */
|
|
85
|
+
selected?: O | O[];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Shared translation labels for SelectTextField wrappers (React and Vue).
|
|
89
|
+
*/
|
|
90
|
+
export interface SelectTextFieldTranslations {
|
|
91
|
+
/** Accessible label for the clear button. */
|
|
92
|
+
clearLabel?: string;
|
|
93
|
+
/** Accessible label for the show-suggestions toggle button. When omitted, the toggle button is not rendered. */
|
|
94
|
+
showSuggestionsLabel?: string;
|
|
95
|
+
/** Accessible label for the chip group. */
|
|
96
|
+
chipGroupLabel?: string;
|
|
97
|
+
/** Accessible label for the remove action on chips (used in visually hidden text). */
|
|
98
|
+
chipRemoveLabel?: string;
|
|
99
|
+
/** Screen reader loading announcement (e.g. "Loading…"). */
|
|
100
|
+
loadingMessage?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Message to display when the list has no visible options.
|
|
103
|
+
* Can be a plain string or a function receiving the current input value (for dynamic messages).
|
|
104
|
+
* When omitted, the empty state is not shown.
|
|
105
|
+
*/
|
|
106
|
+
emptyMessage?: string | ((inputValue: string) => string);
|
|
107
|
+
/**
|
|
108
|
+
* Message callback to display the number of available options.
|
|
109
|
+
* Called with the current visible option count and should return a human-readable string
|
|
110
|
+
* (e.g. `(n) => \`${n} result(s) available\``).
|
|
111
|
+
* Displayed when the combobox is open, not empty, not loading, and not in error.
|
|
112
|
+
* When omitted, no option count message is shown.
|
|
113
|
+
*/
|
|
114
|
+
nbOptionMessage?: (optionsLength: number) => string;
|
|
115
|
+
/** Error title displayed in the dropdown (e.g. "Failed to load"). */
|
|
116
|
+
errorMessage?: string;
|
|
117
|
+
/** Secondary error message (e.g. "Please try again"). */
|
|
118
|
+
errorTryReloadMessage?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Wrapper-level props shared between React and Vue SelectTextField implementations.
|
|
122
|
+
* These are framework-specific concerns (not part of the core template) that both
|
|
123
|
+
* wrappers need — extracted here to avoid duplication.
|
|
124
|
+
*/
|
|
125
|
+
export interface BaseSelectTextFieldWrapperProps<O> extends Pick<BaseSelectProps<O>, 'options' | 'getOptionId' | 'getOptionName' | 'getOptionDescription' | 'getSectionId'>, HasAriaDisabled, HasClassName, HasTheme {
|
|
126
|
+
/** Selection type: 'single' or 'multiple'. */
|
|
127
|
+
selectionType: 'single' | 'multiple';
|
|
128
|
+
/**
|
|
129
|
+
* Status of the dropdown list.
|
|
130
|
+
* @default 'idle'
|
|
131
|
+
*/
|
|
132
|
+
listStatus?: SelectTextFieldStatus;
|
|
133
|
+
/**
|
|
134
|
+
* Controls how the combobox filters options as the user types.
|
|
135
|
+
*
|
|
136
|
+
* - `'auto'` — Options that do not match the input value are hidden client-side.
|
|
137
|
+
* - `'manual'` — All options remain visible; filtering is the consumer's
|
|
138
|
+
* responsibility (e.g. by updating the `options` prop in response to `onSearch`).
|
|
139
|
+
* - `'off'` — Like `'manual'`, but the input is also set to `readOnly` and
|
|
140
|
+
* `openOnFocus` defaults to `true` (useful for static dropdowns / pure pickers).
|
|
141
|
+
*
|
|
142
|
+
* This prop is independent of `onSearch`: you can use both together (e.g. client-side
|
|
143
|
+
* filtering + tracking search text for a "create" action), or use `filter: 'manual'`
|
|
144
|
+
* without `onSearch` for static dropdowns.
|
|
145
|
+
*/
|
|
146
|
+
filter: 'auto' | 'manual' | 'off';
|
|
147
|
+
/**
|
|
148
|
+
* Controlled search input value.
|
|
149
|
+
* When provided, this value seeds (and resets) the visible search text in the input.
|
|
150
|
+
* Setting it to `''` (empty string) resets the input.
|
|
151
|
+
*/
|
|
152
|
+
searchInputValue?: string;
|
|
153
|
+
/**
|
|
154
|
+
* Whether to show a clear button when a value is selected.
|
|
155
|
+
* @default true
|
|
156
|
+
*/
|
|
157
|
+
hasClearButton?: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* When true, the dropdown opens automatically when the input receives focus.
|
|
160
|
+
* When false (default), the dropdown only opens on click, typing, or keyboard navigation.
|
|
161
|
+
*
|
|
162
|
+
* @default false
|
|
163
|
+
*/
|
|
164
|
+
openOnFocus?: boolean;
|
|
165
|
+
/** Field label (required). Also used as aria-label for the listbox. */
|
|
166
|
+
label: string;
|
|
167
|
+
/** Input placeholder text. */
|
|
168
|
+
placeholder?: string;
|
|
169
|
+
/** Leading icon (SVG path). */
|
|
170
|
+
icon?: string;
|
|
171
|
+
/** Disabled state. */
|
|
172
|
+
isDisabled?: boolean;
|
|
173
|
+
/** Required field indicator. */
|
|
174
|
+
isRequired?: boolean;
|
|
175
|
+
/** Error state flag. */
|
|
176
|
+
hasError?: boolean;
|
|
177
|
+
/** Error message text. */
|
|
178
|
+
error?: string;
|
|
179
|
+
/** Helper text below the field. */
|
|
180
|
+
helper?: string;
|
|
181
|
+
/** Native input id attribute. */
|
|
182
|
+
id?: string;
|
|
183
|
+
/** Native input name attribute. */
|
|
184
|
+
name?: string;
|
|
185
|
+
/** Whether displayed with valid style. */
|
|
186
|
+
isValid?: boolean;
|
|
187
|
+
/** Maximum string length (shows character counter). */
|
|
188
|
+
maxLength?: number;
|
|
189
|
+
/** Accessible label for the input element (overrides the visual label for screen readers). */
|
|
190
|
+
ariaLabel?: string;
|
|
191
|
+
/** Additional props forwarded to the Combobox.Input (and ultimately to TextField). */
|
|
192
|
+
inputProps?: Record<string, any>;
|
|
193
|
+
/** Props forwarded to the Combobox.Popover. */
|
|
194
|
+
popoverProps?: Record<string, any>;
|
|
195
|
+
/** Labels for the clear button, toggle button, and chip group. */
|
|
196
|
+
translations: SelectTextFieldTranslations;
|
|
197
|
+
}
|
package/lumx.css
CHANGED
|
@@ -10253,6 +10253,7 @@ table {
|
|
|
10253
10253
|
align-items: center;
|
|
10254
10254
|
margin: calc((var(--lumx-text-field-input-min-height) - var(--lumx-size-s) - 6px) / 2 + 3px) 0;
|
|
10255
10255
|
gap: 6px;
|
|
10256
|
+
min-width: 0;
|
|
10256
10257
|
}
|
|
10257
10258
|
.lumx-select--theme-light .lumx-select__input-native {
|
|
10258
10259
|
display: block;
|
|
@@ -12336,6 +12337,7 @@ table {
|
|
|
12336
12337
|
align-items: center;
|
|
12337
12338
|
margin: calc((var(--lumx-text-field-input-min-height) - var(--lumx-size-s) - 6px) / 2 + 3px) 0;
|
|
12338
12339
|
gap: 6px;
|
|
12340
|
+
min-width: 0;
|
|
12339
12341
|
}
|
|
12340
12342
|
.lumx-text-field__helper {
|
|
12341
12343
|
margin-top: 8px;
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@floating-ui/dom": "^1.7.5",
|
|
10
|
-
"@lumx/icons": "^4.12.0-next.
|
|
10
|
+
"@lumx/icons": "^4.12.0-next.1",
|
|
11
11
|
"classnames": "^2.3.2",
|
|
12
12
|
"focus-visible": "^5.0.2",
|
|
13
13
|
"lodash": "4.18.1",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"update-version-changelog": "yarn version-changelog ../../CHANGELOG.md"
|
|
70
70
|
},
|
|
71
71
|
"sideEffects": false,
|
|
72
|
-
"version": "4.12.0-next.
|
|
72
|
+
"version": "4.12.0-next.1",
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
75
75
|
"@testing-library/dom": "^10.4.1",
|