forge-select 0.3.0 → 0.5.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/README.md +24 -15
- package/dist/index.cjs +667 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +178 -9
- package/dist/index.d.ts +178 -9
- package/dist/index.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +667 -63
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/styles/forge-select.css +37 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
type Handler = (...args: unknown[]) => void;
|
|
2
|
-
|
|
3
1
|
interface Option {
|
|
4
2
|
value: string;
|
|
5
3
|
label: string;
|
|
@@ -10,6 +8,8 @@ interface Option {
|
|
|
10
8
|
description?: string;
|
|
11
9
|
/** Arbitrary payload for custom templates; ForgeSelect never reads it. */
|
|
12
10
|
meta?: Record<string, unknown>;
|
|
11
|
+
/** Extra CSS class(es) applied to this option's rendered <li>. */
|
|
12
|
+
className?: string;
|
|
13
13
|
/**
|
|
14
14
|
* Nested options, making this a tree node. Purely additive: lists where
|
|
15
15
|
* no option has `children` render and behave exactly as a flat list.
|
|
@@ -22,10 +22,26 @@ interface OptionGroup {
|
|
|
22
22
|
}
|
|
23
23
|
type DataItem = Option | OptionGroup;
|
|
24
24
|
interface AjaxConfig {
|
|
25
|
-
|
|
25
|
+
/** GET endpoint. Optional when `request` supplies a custom transport. */
|
|
26
|
+
url?: string | ((query: string, page: number) => string);
|
|
27
|
+
/**
|
|
28
|
+
* Custom transport for POST/authenticated/GraphQL requests. Takes precedence
|
|
29
|
+
* over `url`; the returned payload is passed through `transform`.
|
|
30
|
+
*/
|
|
31
|
+
request?: (query: string, page: number, signal: AbortSignal) => Promise<unknown>;
|
|
26
32
|
params?: (query: string, page: number) => Record<string, unknown>;
|
|
27
33
|
/** Debounce in milliseconds. Default 250. */
|
|
28
34
|
debounce?: number;
|
|
35
|
+
/** Load the initial empty query when the dropdown opens. Default true. */
|
|
36
|
+
loadOnOpen?: boolean;
|
|
37
|
+
/** Cache successful pages for this many milliseconds. Set 0 to disable. Default 30000. */
|
|
38
|
+
cacheTtl?: number;
|
|
39
|
+
/** Number of retries after a failed request. Default 0. */
|
|
40
|
+
retry?: number;
|
|
41
|
+
/** Base delay for exponential retry backoff. Default 250ms. */
|
|
42
|
+
retryDelay?: number;
|
|
43
|
+
/** Queries to warm in the background after construction. */
|
|
44
|
+
prefetch?: string[];
|
|
29
45
|
/**
|
|
30
46
|
* Opt in to loading additional pages as the user scrolls near the bottom
|
|
31
47
|
* of the dropdown, instead of only reloading on search. Default false.
|
|
@@ -49,6 +65,8 @@ interface ForgeSelectPlugin {
|
|
|
49
65
|
onDestroy?(select: ForgeSelect): void;
|
|
50
66
|
}
|
|
51
67
|
type TemplateFn = (option: Option) => string | Node;
|
|
68
|
+
type SearchField = "label" | "description" | `meta.${string}`;
|
|
69
|
+
type SearchScorer = (option: Option, query: string, normalizedQuery: string) => number;
|
|
52
70
|
interface ForgeSelectOptions {
|
|
53
71
|
placeholder?: string;
|
|
54
72
|
searchable?: boolean;
|
|
@@ -62,28 +80,118 @@ interface ForgeSelectOptions {
|
|
|
62
80
|
* behavior and tag markup are unchanged when this is left off.
|
|
63
81
|
*/
|
|
64
82
|
sortable?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Multi-select only: close the dropdown immediately after each pick
|
|
85
|
+
* instead of staying open for further selections. Default false —
|
|
86
|
+
* existing multi-select behavior (stays open) is unchanged.
|
|
87
|
+
*/
|
|
88
|
+
closeOnSelect?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Multi-select only: caps the number of selected values. Once reached,
|
|
91
|
+
* further picks (including via allowCreate) are ignored until one is
|
|
92
|
+
* removed. Only gates interactive selection — setValue() is not clamped.
|
|
93
|
+
* Default undefined (no limit).
|
|
94
|
+
*/
|
|
95
|
+
maxSelections?: number;
|
|
65
96
|
theme?: string;
|
|
66
97
|
disabled?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Marks the field as required for native form validation. When mounted on
|
|
100
|
+
* a real <select>, an empty selection blocks form submission and shows
|
|
101
|
+
* inline invalid styling, mirroring native <select required> behavior.
|
|
102
|
+
* On a plain-element mount this only sets aria-required (no native form
|
|
103
|
+
* to hook into). Default false.
|
|
104
|
+
*/
|
|
105
|
+
required?: boolean;
|
|
67
106
|
data?: DataItem[];
|
|
68
107
|
ajax?: AjaxConfig;
|
|
69
108
|
templateResult?: TemplateFn;
|
|
70
109
|
templateSelection?: TemplateFn;
|
|
110
|
+
/**
|
|
111
|
+
* Custom match predicate, replacing the built-in label/description
|
|
112
|
+
* substring match. Receives the trimmed (not lowercased) query.
|
|
113
|
+
*/
|
|
114
|
+
filterOption?: (option: Option, query: string) => boolean;
|
|
115
|
+
/** Fields used by built-in search. Default: label and description. */
|
|
116
|
+
searchFields?: SearchField[];
|
|
117
|
+
/** Split the query into tokens which may match across fields. Default true. */
|
|
118
|
+
tokenSearch?: boolean;
|
|
119
|
+
/** Match text without case or diacritics. Default true. */
|
|
120
|
+
accentInsensitive?: boolean;
|
|
121
|
+
/** Optional relevance scorer. Values <= 0 exclude an option. */
|
|
122
|
+
searchScorer?: SearchScorer;
|
|
123
|
+
/** Highlight built-in label matches with <mark>. Default false. */
|
|
124
|
+
highlightSearch?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Hides results (showing a hint row instead) until the trimmed search
|
|
127
|
+
* query reaches this length. Also delays ajax requests until the
|
|
128
|
+
* threshold is met. Default 0 (no gate).
|
|
129
|
+
*/
|
|
130
|
+
minSearchLength?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Hides the search field when a local list contains fewer options than
|
|
133
|
+
* this threshold. AJAX-backed lists always keep search visible. Default 0.
|
|
134
|
+
*/
|
|
135
|
+
minResultsForSearch?: number;
|
|
136
|
+
/**
|
|
137
|
+
* Dynamically disables an option, in addition to its static `disabled`
|
|
138
|
+
* field. Re-evaluated on every render, so it can react to external state
|
|
139
|
+
* (e.g. a quota) without rebuilding `data` via setData().
|
|
140
|
+
*/
|
|
141
|
+
isOptionDisabled?: (option: Option) => boolean;
|
|
71
142
|
/**
|
|
72
143
|
* false = never virtualize. true or unset = virtualize automatically
|
|
73
144
|
* once the list exceeds ~100 rows.
|
|
74
145
|
*/
|
|
75
146
|
virtualScroll?: boolean;
|
|
76
|
-
/** Row height in px
|
|
77
|
-
itemHeight?: number;
|
|
147
|
+
/** Row height in px, or "auto" to measure variable-height rows. Default 36. */
|
|
148
|
+
itemHeight?: number | "auto";
|
|
78
149
|
language?: string | Record<string, string>;
|
|
79
150
|
plugins?: ForgeSelectPlugin[];
|
|
151
|
+
/**
|
|
152
|
+
* Opens the dropdown when the control receives keyboard focus (e.g. via
|
|
153
|
+
* Tab). Default false — focusing alone still requires Enter/Space/ArrowDown
|
|
154
|
+
* to open, matching existing behavior.
|
|
155
|
+
*/
|
|
156
|
+
openOnFocus?: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Optional portal container for the dropdown, useful inside overflow-hidden
|
|
159
|
+
* modals and drawers. Accepts an element or selector. Default: the root.
|
|
160
|
+
*/
|
|
161
|
+
dropdownParent?: HTMLElement | string;
|
|
80
162
|
}
|
|
81
163
|
type ForgeSelectValue = string | string[] | null;
|
|
82
164
|
interface SetValueOptions {
|
|
83
165
|
/** Emit Forge Select's `change` event after updating. Default true. */
|
|
84
166
|
emitChange?: boolean;
|
|
85
167
|
}
|
|
86
|
-
|
|
168
|
+
interface SetSearchQueryOptions {
|
|
169
|
+
/** Emit the `search` event. Default true. */
|
|
170
|
+
emitSearch?: boolean;
|
|
171
|
+
}
|
|
172
|
+
/** Runtime-updateable options. Structural mode/plugin/portal changes still require remounting. */
|
|
173
|
+
type ForgeSelectUpdateOptions = Omit<Partial<ForgeSelectOptions>, "multiple" | "searchable" | "plugins" | "dropdownParent">;
|
|
174
|
+
interface MaximumSelectionEvent {
|
|
175
|
+
limit: number;
|
|
176
|
+
option: Option;
|
|
177
|
+
}
|
|
178
|
+
interface ForgeSelectEventMap {
|
|
179
|
+
change: ForgeSelectValue;
|
|
180
|
+
open: void;
|
|
181
|
+
close: void;
|
|
182
|
+
search: string;
|
|
183
|
+
clear: void;
|
|
184
|
+
error: Error;
|
|
185
|
+
loading: boolean;
|
|
186
|
+
invalid: string;
|
|
187
|
+
select: Option;
|
|
188
|
+
unselect: Option;
|
|
189
|
+
create: Option;
|
|
190
|
+
reorder: string[];
|
|
191
|
+
maximum: MaximumSelectionEvent;
|
|
192
|
+
}
|
|
193
|
+
type ForgeSelectEvent = keyof ForgeSelectEventMap;
|
|
194
|
+
type ForgeSelectEventHandler<E extends ForgeSelectEvent> = ForgeSelectEventMap[E] extends void ? () => void : (payload: ForgeSelectEventMap[E]) => void;
|
|
87
195
|
|
|
88
196
|
declare class ForgeSelect {
|
|
89
197
|
/** The original element ForgeSelect was mounted on. */
|
|
@@ -105,6 +213,7 @@ declare class ForgeSelect {
|
|
|
105
213
|
private searchInput;
|
|
106
214
|
private list;
|
|
107
215
|
private liveRegion;
|
|
216
|
+
private portalHost;
|
|
108
217
|
private isOpen;
|
|
109
218
|
private isDisabled;
|
|
110
219
|
private destroyed;
|
|
@@ -113,6 +222,8 @@ declare class ForgeSelect {
|
|
|
113
222
|
private navItems;
|
|
114
223
|
private highlightedIndex;
|
|
115
224
|
private rowContentCache;
|
|
225
|
+
private rowHeightCache;
|
|
226
|
+
private searchIndex;
|
|
116
227
|
private expandedValues;
|
|
117
228
|
private loading;
|
|
118
229
|
private loadingMore;
|
|
@@ -122,26 +233,66 @@ declare class ForgeSelect {
|
|
|
122
233
|
private ajaxRequestId;
|
|
123
234
|
private ajaxController;
|
|
124
235
|
private remoteLoaded;
|
|
236
|
+
private remoteCache;
|
|
125
237
|
private loadError;
|
|
126
238
|
private originalDisplay;
|
|
127
239
|
private originalDisabled;
|
|
128
240
|
private nativeSelect;
|
|
129
241
|
private nativeForm;
|
|
130
242
|
private syncingNative;
|
|
243
|
+
/** Combines the static `disabled` field with the dynamic `isOptionDisabled` callback. */
|
|
244
|
+
private isOptionDisabled;
|
|
245
|
+
private pointerDownOnControl;
|
|
131
246
|
private onDocumentMouseDown;
|
|
247
|
+
private onWindowResize;
|
|
248
|
+
private onAncestorScroll;
|
|
249
|
+
private onNativeInvalid;
|
|
132
250
|
private onNativeChange;
|
|
133
251
|
private applyNativeValues;
|
|
134
252
|
private onFormReset;
|
|
135
253
|
constructor(target: string | HTMLElement, options?: ForgeSelectOptions);
|
|
136
254
|
open(): void;
|
|
137
255
|
close(): void;
|
|
256
|
+
/**
|
|
257
|
+
* Flips the dropdown above the control when there isn't enough room below
|
|
258
|
+
* but there is above. Recomputed on open() and on window resize — the
|
|
259
|
+
* dropdown is positioned absolutely inside the relatively-positioned root,
|
|
260
|
+
* so it already tracks the control correctly on page scroll without
|
|
261
|
+
* needing a scroll listener.
|
|
262
|
+
*/
|
|
263
|
+
private positionDropdown;
|
|
138
264
|
destroy(): void;
|
|
139
265
|
getValue(): ForgeSelectValue;
|
|
266
|
+
getSearchQuery(): string;
|
|
267
|
+
setSearchQuery(query: string, options?: SetSearchQueryOptions): void;
|
|
268
|
+
isDropdownOpen(): boolean;
|
|
269
|
+
updateOptions(options: ForgeSelectUpdateOptions): void;
|
|
270
|
+
validate(): boolean;
|
|
271
|
+
setCustomValidity(message: string): void;
|
|
272
|
+
reportValidity(): boolean;
|
|
273
|
+
reload(): void;
|
|
274
|
+
clearRemoteCache(): void;
|
|
140
275
|
setValue(value: ForgeSelectValue, options?: SetValueOptions): void;
|
|
276
|
+
/**
|
|
277
|
+
* Replaces the option list after construction. An open dropdown re-renders
|
|
278
|
+
* immediately; a selection whose value isn't in the new data stays
|
|
279
|
+
* selected (rendered via the already-selected option's own label/avatar,
|
|
280
|
+
* the same fallback used for values selected from a stale ajax page).
|
|
281
|
+
*/
|
|
282
|
+
setData(data: DataItem[]): void;
|
|
283
|
+
/**
|
|
284
|
+
* Multi-select only: selects every currently non-disabled option, including
|
|
285
|
+
* nested tree descendants and options inside groups. If `maxSelections` is
|
|
286
|
+
* set, stops once the cap is reached rather than exceeding it. A no-op for
|
|
287
|
+
* single-select.
|
|
288
|
+
*/
|
|
289
|
+
selectAll(): void;
|
|
290
|
+
/** Clears every selection. Equivalent to `setValue(null)`. */
|
|
291
|
+
clearAll(): void;
|
|
141
292
|
enable(): void;
|
|
142
293
|
disable(): void;
|
|
143
|
-
on(event:
|
|
144
|
-
off(event:
|
|
294
|
+
on<E extends ForgeSelectEvent>(event: E, handler: ForgeSelectEventHandler<E>): void;
|
|
295
|
+
off<E extends ForgeSelectEvent>(event: E, handler: ForgeSelectEventHandler<E>): void;
|
|
145
296
|
/**
|
|
146
297
|
* The original target (a hidden native <select> or a plain mount div) can
|
|
147
298
|
* carry an accessible name via aria-label/aria-labelledby, or via a
|
|
@@ -151,9 +302,15 @@ declare class ForgeSelect {
|
|
|
151
302
|
* interactive `this.control` ourselves.
|
|
152
303
|
*/
|
|
153
304
|
private applyAccessibleName;
|
|
305
|
+
private shouldShowSearch;
|
|
306
|
+
private updateSearchVisibility;
|
|
154
307
|
private buildDom;
|
|
155
308
|
private bindEvents;
|
|
309
|
+
private applySearchQuery;
|
|
156
310
|
private handleKeydown;
|
|
311
|
+
private canSelectOption;
|
|
312
|
+
private hasReachedMaximum;
|
|
313
|
+
private announceMaximum;
|
|
157
314
|
private selectValue;
|
|
158
315
|
private deselectValue;
|
|
159
316
|
/**
|
|
@@ -164,9 +321,13 @@ declare class ForgeSelect {
|
|
|
164
321
|
*/
|
|
165
322
|
private syncTreeAncestors;
|
|
166
323
|
private clearSelection;
|
|
324
|
+
private allSelectableValues;
|
|
167
325
|
private afterSelectionChange;
|
|
168
326
|
private syncNativeSelect;
|
|
169
327
|
private findOption;
|
|
328
|
+
private findOptionByLabel;
|
|
329
|
+
/** Selects an existing option matching `label` exactly, or creates and selects a new one. */
|
|
330
|
+
private createTag;
|
|
170
331
|
private createFromQuery;
|
|
171
332
|
private activateNavItem;
|
|
172
333
|
private renderValue;
|
|
@@ -187,6 +348,10 @@ declare class ForgeSelect {
|
|
|
187
348
|
private buildRows;
|
|
188
349
|
private hasExactMatch;
|
|
189
350
|
private usesVirtualScroll;
|
|
351
|
+
private rowKey;
|
|
352
|
+
private measuredRowHeight;
|
|
353
|
+
private rowOffset;
|
|
354
|
+
private rowOffsets;
|
|
190
355
|
private renderList;
|
|
191
356
|
private announceStatus;
|
|
192
357
|
private renderRows;
|
|
@@ -203,6 +368,10 @@ declare class ForgeSelect {
|
|
|
203
368
|
private navigateTree;
|
|
204
369
|
private updateActiveDescendant;
|
|
205
370
|
private scheduleRemoteLoad;
|
|
371
|
+
private setLoading;
|
|
372
|
+
private remoteCacheKey;
|
|
373
|
+
private requestRemote;
|
|
374
|
+
private prefetchRemote;
|
|
206
375
|
/**
|
|
207
376
|
* Fires on every list scroll. Only acts when pagination is opted into via
|
|
208
377
|
* `ajax.pagination`; reads real scroll geometry rather than row counts so
|
|
@@ -212,4 +381,4 @@ declare class ForgeSelect {
|
|
|
212
381
|
private loadRemote;
|
|
213
382
|
}
|
|
214
383
|
|
|
215
|
-
export { type AjaxConfig, type DataItem, ForgeSelect, type ForgeSelectEvent, type ForgeSelectOptions, type ForgeSelectPlugin, type ForgeSelectValue, type Option, type OptionGroup, type SetValueOptions, type TemplateFn, ForgeSelect as default };
|
|
384
|
+
export { type AjaxConfig, type DataItem, ForgeSelect, type ForgeSelectEvent, type ForgeSelectEventHandler, type ForgeSelectEventMap, type ForgeSelectOptions, type ForgeSelectPlugin, type ForgeSelectUpdateOptions, type ForgeSelectValue, type MaximumSelectionEvent, type Option, type OptionGroup, type SearchField, type SearchScorer, type SetSearchQueryOptions, type SetValueOptions, type TemplateFn, ForgeSelect as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
type Handler = (...args: unknown[]) => void;
|
|
2
|
-
|
|
3
1
|
interface Option {
|
|
4
2
|
value: string;
|
|
5
3
|
label: string;
|
|
@@ -10,6 +8,8 @@ interface Option {
|
|
|
10
8
|
description?: string;
|
|
11
9
|
/** Arbitrary payload for custom templates; ForgeSelect never reads it. */
|
|
12
10
|
meta?: Record<string, unknown>;
|
|
11
|
+
/** Extra CSS class(es) applied to this option's rendered <li>. */
|
|
12
|
+
className?: string;
|
|
13
13
|
/**
|
|
14
14
|
* Nested options, making this a tree node. Purely additive: lists where
|
|
15
15
|
* no option has `children` render and behave exactly as a flat list.
|
|
@@ -22,10 +22,26 @@ interface OptionGroup {
|
|
|
22
22
|
}
|
|
23
23
|
type DataItem = Option | OptionGroup;
|
|
24
24
|
interface AjaxConfig {
|
|
25
|
-
|
|
25
|
+
/** GET endpoint. Optional when `request` supplies a custom transport. */
|
|
26
|
+
url?: string | ((query: string, page: number) => string);
|
|
27
|
+
/**
|
|
28
|
+
* Custom transport for POST/authenticated/GraphQL requests. Takes precedence
|
|
29
|
+
* over `url`; the returned payload is passed through `transform`.
|
|
30
|
+
*/
|
|
31
|
+
request?: (query: string, page: number, signal: AbortSignal) => Promise<unknown>;
|
|
26
32
|
params?: (query: string, page: number) => Record<string, unknown>;
|
|
27
33
|
/** Debounce in milliseconds. Default 250. */
|
|
28
34
|
debounce?: number;
|
|
35
|
+
/** Load the initial empty query when the dropdown opens. Default true. */
|
|
36
|
+
loadOnOpen?: boolean;
|
|
37
|
+
/** Cache successful pages for this many milliseconds. Set 0 to disable. Default 30000. */
|
|
38
|
+
cacheTtl?: number;
|
|
39
|
+
/** Number of retries after a failed request. Default 0. */
|
|
40
|
+
retry?: number;
|
|
41
|
+
/** Base delay for exponential retry backoff. Default 250ms. */
|
|
42
|
+
retryDelay?: number;
|
|
43
|
+
/** Queries to warm in the background after construction. */
|
|
44
|
+
prefetch?: string[];
|
|
29
45
|
/**
|
|
30
46
|
* Opt in to loading additional pages as the user scrolls near the bottom
|
|
31
47
|
* of the dropdown, instead of only reloading on search. Default false.
|
|
@@ -49,6 +65,8 @@ interface ForgeSelectPlugin {
|
|
|
49
65
|
onDestroy?(select: ForgeSelect): void;
|
|
50
66
|
}
|
|
51
67
|
type TemplateFn = (option: Option) => string | Node;
|
|
68
|
+
type SearchField = "label" | "description" | `meta.${string}`;
|
|
69
|
+
type SearchScorer = (option: Option, query: string, normalizedQuery: string) => number;
|
|
52
70
|
interface ForgeSelectOptions {
|
|
53
71
|
placeholder?: string;
|
|
54
72
|
searchable?: boolean;
|
|
@@ -62,28 +80,118 @@ interface ForgeSelectOptions {
|
|
|
62
80
|
* behavior and tag markup are unchanged when this is left off.
|
|
63
81
|
*/
|
|
64
82
|
sortable?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Multi-select only: close the dropdown immediately after each pick
|
|
85
|
+
* instead of staying open for further selections. Default false —
|
|
86
|
+
* existing multi-select behavior (stays open) is unchanged.
|
|
87
|
+
*/
|
|
88
|
+
closeOnSelect?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Multi-select only: caps the number of selected values. Once reached,
|
|
91
|
+
* further picks (including via allowCreate) are ignored until one is
|
|
92
|
+
* removed. Only gates interactive selection — setValue() is not clamped.
|
|
93
|
+
* Default undefined (no limit).
|
|
94
|
+
*/
|
|
95
|
+
maxSelections?: number;
|
|
65
96
|
theme?: string;
|
|
66
97
|
disabled?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Marks the field as required for native form validation. When mounted on
|
|
100
|
+
* a real <select>, an empty selection blocks form submission and shows
|
|
101
|
+
* inline invalid styling, mirroring native <select required> behavior.
|
|
102
|
+
* On a plain-element mount this only sets aria-required (no native form
|
|
103
|
+
* to hook into). Default false.
|
|
104
|
+
*/
|
|
105
|
+
required?: boolean;
|
|
67
106
|
data?: DataItem[];
|
|
68
107
|
ajax?: AjaxConfig;
|
|
69
108
|
templateResult?: TemplateFn;
|
|
70
109
|
templateSelection?: TemplateFn;
|
|
110
|
+
/**
|
|
111
|
+
* Custom match predicate, replacing the built-in label/description
|
|
112
|
+
* substring match. Receives the trimmed (not lowercased) query.
|
|
113
|
+
*/
|
|
114
|
+
filterOption?: (option: Option, query: string) => boolean;
|
|
115
|
+
/** Fields used by built-in search. Default: label and description. */
|
|
116
|
+
searchFields?: SearchField[];
|
|
117
|
+
/** Split the query into tokens which may match across fields. Default true. */
|
|
118
|
+
tokenSearch?: boolean;
|
|
119
|
+
/** Match text without case or diacritics. Default true. */
|
|
120
|
+
accentInsensitive?: boolean;
|
|
121
|
+
/** Optional relevance scorer. Values <= 0 exclude an option. */
|
|
122
|
+
searchScorer?: SearchScorer;
|
|
123
|
+
/** Highlight built-in label matches with <mark>. Default false. */
|
|
124
|
+
highlightSearch?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Hides results (showing a hint row instead) until the trimmed search
|
|
127
|
+
* query reaches this length. Also delays ajax requests until the
|
|
128
|
+
* threshold is met. Default 0 (no gate).
|
|
129
|
+
*/
|
|
130
|
+
minSearchLength?: number;
|
|
131
|
+
/**
|
|
132
|
+
* Hides the search field when a local list contains fewer options than
|
|
133
|
+
* this threshold. AJAX-backed lists always keep search visible. Default 0.
|
|
134
|
+
*/
|
|
135
|
+
minResultsForSearch?: number;
|
|
136
|
+
/**
|
|
137
|
+
* Dynamically disables an option, in addition to its static `disabled`
|
|
138
|
+
* field. Re-evaluated on every render, so it can react to external state
|
|
139
|
+
* (e.g. a quota) without rebuilding `data` via setData().
|
|
140
|
+
*/
|
|
141
|
+
isOptionDisabled?: (option: Option) => boolean;
|
|
71
142
|
/**
|
|
72
143
|
* false = never virtualize. true or unset = virtualize automatically
|
|
73
144
|
* once the list exceeds ~100 rows.
|
|
74
145
|
*/
|
|
75
146
|
virtualScroll?: boolean;
|
|
76
|
-
/** Row height in px
|
|
77
|
-
itemHeight?: number;
|
|
147
|
+
/** Row height in px, or "auto" to measure variable-height rows. Default 36. */
|
|
148
|
+
itemHeight?: number | "auto";
|
|
78
149
|
language?: string | Record<string, string>;
|
|
79
150
|
plugins?: ForgeSelectPlugin[];
|
|
151
|
+
/**
|
|
152
|
+
* Opens the dropdown when the control receives keyboard focus (e.g. via
|
|
153
|
+
* Tab). Default false — focusing alone still requires Enter/Space/ArrowDown
|
|
154
|
+
* to open, matching existing behavior.
|
|
155
|
+
*/
|
|
156
|
+
openOnFocus?: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Optional portal container for the dropdown, useful inside overflow-hidden
|
|
159
|
+
* modals and drawers. Accepts an element or selector. Default: the root.
|
|
160
|
+
*/
|
|
161
|
+
dropdownParent?: HTMLElement | string;
|
|
80
162
|
}
|
|
81
163
|
type ForgeSelectValue = string | string[] | null;
|
|
82
164
|
interface SetValueOptions {
|
|
83
165
|
/** Emit Forge Select's `change` event after updating. Default true. */
|
|
84
166
|
emitChange?: boolean;
|
|
85
167
|
}
|
|
86
|
-
|
|
168
|
+
interface SetSearchQueryOptions {
|
|
169
|
+
/** Emit the `search` event. Default true. */
|
|
170
|
+
emitSearch?: boolean;
|
|
171
|
+
}
|
|
172
|
+
/** Runtime-updateable options. Structural mode/plugin/portal changes still require remounting. */
|
|
173
|
+
type ForgeSelectUpdateOptions = Omit<Partial<ForgeSelectOptions>, "multiple" | "searchable" | "plugins" | "dropdownParent">;
|
|
174
|
+
interface MaximumSelectionEvent {
|
|
175
|
+
limit: number;
|
|
176
|
+
option: Option;
|
|
177
|
+
}
|
|
178
|
+
interface ForgeSelectEventMap {
|
|
179
|
+
change: ForgeSelectValue;
|
|
180
|
+
open: void;
|
|
181
|
+
close: void;
|
|
182
|
+
search: string;
|
|
183
|
+
clear: void;
|
|
184
|
+
error: Error;
|
|
185
|
+
loading: boolean;
|
|
186
|
+
invalid: string;
|
|
187
|
+
select: Option;
|
|
188
|
+
unselect: Option;
|
|
189
|
+
create: Option;
|
|
190
|
+
reorder: string[];
|
|
191
|
+
maximum: MaximumSelectionEvent;
|
|
192
|
+
}
|
|
193
|
+
type ForgeSelectEvent = keyof ForgeSelectEventMap;
|
|
194
|
+
type ForgeSelectEventHandler<E extends ForgeSelectEvent> = ForgeSelectEventMap[E] extends void ? () => void : (payload: ForgeSelectEventMap[E]) => void;
|
|
87
195
|
|
|
88
196
|
declare class ForgeSelect {
|
|
89
197
|
/** The original element ForgeSelect was mounted on. */
|
|
@@ -105,6 +213,7 @@ declare class ForgeSelect {
|
|
|
105
213
|
private searchInput;
|
|
106
214
|
private list;
|
|
107
215
|
private liveRegion;
|
|
216
|
+
private portalHost;
|
|
108
217
|
private isOpen;
|
|
109
218
|
private isDisabled;
|
|
110
219
|
private destroyed;
|
|
@@ -113,6 +222,8 @@ declare class ForgeSelect {
|
|
|
113
222
|
private navItems;
|
|
114
223
|
private highlightedIndex;
|
|
115
224
|
private rowContentCache;
|
|
225
|
+
private rowHeightCache;
|
|
226
|
+
private searchIndex;
|
|
116
227
|
private expandedValues;
|
|
117
228
|
private loading;
|
|
118
229
|
private loadingMore;
|
|
@@ -122,26 +233,66 @@ declare class ForgeSelect {
|
|
|
122
233
|
private ajaxRequestId;
|
|
123
234
|
private ajaxController;
|
|
124
235
|
private remoteLoaded;
|
|
236
|
+
private remoteCache;
|
|
125
237
|
private loadError;
|
|
126
238
|
private originalDisplay;
|
|
127
239
|
private originalDisabled;
|
|
128
240
|
private nativeSelect;
|
|
129
241
|
private nativeForm;
|
|
130
242
|
private syncingNative;
|
|
243
|
+
/** Combines the static `disabled` field with the dynamic `isOptionDisabled` callback. */
|
|
244
|
+
private isOptionDisabled;
|
|
245
|
+
private pointerDownOnControl;
|
|
131
246
|
private onDocumentMouseDown;
|
|
247
|
+
private onWindowResize;
|
|
248
|
+
private onAncestorScroll;
|
|
249
|
+
private onNativeInvalid;
|
|
132
250
|
private onNativeChange;
|
|
133
251
|
private applyNativeValues;
|
|
134
252
|
private onFormReset;
|
|
135
253
|
constructor(target: string | HTMLElement, options?: ForgeSelectOptions);
|
|
136
254
|
open(): void;
|
|
137
255
|
close(): void;
|
|
256
|
+
/**
|
|
257
|
+
* Flips the dropdown above the control when there isn't enough room below
|
|
258
|
+
* but there is above. Recomputed on open() and on window resize — the
|
|
259
|
+
* dropdown is positioned absolutely inside the relatively-positioned root,
|
|
260
|
+
* so it already tracks the control correctly on page scroll without
|
|
261
|
+
* needing a scroll listener.
|
|
262
|
+
*/
|
|
263
|
+
private positionDropdown;
|
|
138
264
|
destroy(): void;
|
|
139
265
|
getValue(): ForgeSelectValue;
|
|
266
|
+
getSearchQuery(): string;
|
|
267
|
+
setSearchQuery(query: string, options?: SetSearchQueryOptions): void;
|
|
268
|
+
isDropdownOpen(): boolean;
|
|
269
|
+
updateOptions(options: ForgeSelectUpdateOptions): void;
|
|
270
|
+
validate(): boolean;
|
|
271
|
+
setCustomValidity(message: string): void;
|
|
272
|
+
reportValidity(): boolean;
|
|
273
|
+
reload(): void;
|
|
274
|
+
clearRemoteCache(): void;
|
|
140
275
|
setValue(value: ForgeSelectValue, options?: SetValueOptions): void;
|
|
276
|
+
/**
|
|
277
|
+
* Replaces the option list after construction. An open dropdown re-renders
|
|
278
|
+
* immediately; a selection whose value isn't in the new data stays
|
|
279
|
+
* selected (rendered via the already-selected option's own label/avatar,
|
|
280
|
+
* the same fallback used for values selected from a stale ajax page).
|
|
281
|
+
*/
|
|
282
|
+
setData(data: DataItem[]): void;
|
|
283
|
+
/**
|
|
284
|
+
* Multi-select only: selects every currently non-disabled option, including
|
|
285
|
+
* nested tree descendants and options inside groups. If `maxSelections` is
|
|
286
|
+
* set, stops once the cap is reached rather than exceeding it. A no-op for
|
|
287
|
+
* single-select.
|
|
288
|
+
*/
|
|
289
|
+
selectAll(): void;
|
|
290
|
+
/** Clears every selection. Equivalent to `setValue(null)`. */
|
|
291
|
+
clearAll(): void;
|
|
141
292
|
enable(): void;
|
|
142
293
|
disable(): void;
|
|
143
|
-
on(event:
|
|
144
|
-
off(event:
|
|
294
|
+
on<E extends ForgeSelectEvent>(event: E, handler: ForgeSelectEventHandler<E>): void;
|
|
295
|
+
off<E extends ForgeSelectEvent>(event: E, handler: ForgeSelectEventHandler<E>): void;
|
|
145
296
|
/**
|
|
146
297
|
* The original target (a hidden native <select> or a plain mount div) can
|
|
147
298
|
* carry an accessible name via aria-label/aria-labelledby, or via a
|
|
@@ -151,9 +302,15 @@ declare class ForgeSelect {
|
|
|
151
302
|
* interactive `this.control` ourselves.
|
|
152
303
|
*/
|
|
153
304
|
private applyAccessibleName;
|
|
305
|
+
private shouldShowSearch;
|
|
306
|
+
private updateSearchVisibility;
|
|
154
307
|
private buildDom;
|
|
155
308
|
private bindEvents;
|
|
309
|
+
private applySearchQuery;
|
|
156
310
|
private handleKeydown;
|
|
311
|
+
private canSelectOption;
|
|
312
|
+
private hasReachedMaximum;
|
|
313
|
+
private announceMaximum;
|
|
157
314
|
private selectValue;
|
|
158
315
|
private deselectValue;
|
|
159
316
|
/**
|
|
@@ -164,9 +321,13 @@ declare class ForgeSelect {
|
|
|
164
321
|
*/
|
|
165
322
|
private syncTreeAncestors;
|
|
166
323
|
private clearSelection;
|
|
324
|
+
private allSelectableValues;
|
|
167
325
|
private afterSelectionChange;
|
|
168
326
|
private syncNativeSelect;
|
|
169
327
|
private findOption;
|
|
328
|
+
private findOptionByLabel;
|
|
329
|
+
/** Selects an existing option matching `label` exactly, or creates and selects a new one. */
|
|
330
|
+
private createTag;
|
|
170
331
|
private createFromQuery;
|
|
171
332
|
private activateNavItem;
|
|
172
333
|
private renderValue;
|
|
@@ -187,6 +348,10 @@ declare class ForgeSelect {
|
|
|
187
348
|
private buildRows;
|
|
188
349
|
private hasExactMatch;
|
|
189
350
|
private usesVirtualScroll;
|
|
351
|
+
private rowKey;
|
|
352
|
+
private measuredRowHeight;
|
|
353
|
+
private rowOffset;
|
|
354
|
+
private rowOffsets;
|
|
190
355
|
private renderList;
|
|
191
356
|
private announceStatus;
|
|
192
357
|
private renderRows;
|
|
@@ -203,6 +368,10 @@ declare class ForgeSelect {
|
|
|
203
368
|
private navigateTree;
|
|
204
369
|
private updateActiveDescendant;
|
|
205
370
|
private scheduleRemoteLoad;
|
|
371
|
+
private setLoading;
|
|
372
|
+
private remoteCacheKey;
|
|
373
|
+
private requestRemote;
|
|
374
|
+
private prefetchRemote;
|
|
206
375
|
/**
|
|
207
376
|
* Fires on every list scroll. Only acts when pagination is opted into via
|
|
208
377
|
* `ajax.pagination`; reads real scroll geometry rather than row counts so
|
|
@@ -212,4 +381,4 @@ declare class ForgeSelect {
|
|
|
212
381
|
private loadRemote;
|
|
213
382
|
}
|
|
214
383
|
|
|
215
|
-
export { type AjaxConfig, type DataItem, ForgeSelect, type ForgeSelectEvent, type ForgeSelectOptions, type ForgeSelectPlugin, type ForgeSelectValue, type Option, type OptionGroup, type SetValueOptions, type TemplateFn, ForgeSelect as default };
|
|
384
|
+
export { type AjaxConfig, type DataItem, ForgeSelect, type ForgeSelectEvent, type ForgeSelectEventHandler, type ForgeSelectEventMap, type ForgeSelectOptions, type ForgeSelectPlugin, type ForgeSelectUpdateOptions, type ForgeSelectValue, type MaximumSelectionEvent, type Option, type OptionGroup, type SearchField, type SearchScorer, type SetSearchQueryOptions, type SetValueOptions, type TemplateFn, ForgeSelect as default };
|