@keenmate/web-multiselect 1.12.0-rc04 → 1.12.0-rc06
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 +39 -11
- package/component-variables.manifest.json +1 -0
- package/dist/index.d.ts +340 -21
- package/dist/multiselect.js +1608 -878
- package/dist/multiselect.umd.js +22 -21
- package/dist/style.css +1 -1
- package/docs/examples.md +46 -2
- package/docs/usage.md +32 -4
- package/package.json +2 -1
- package/src/css/controls.css +50 -4
- package/src/css/floating.css +28 -0
- package/src/css/main.css +1 -0
- package/src/css/options.css +52 -2
- package/src/css/tree.css +42 -0
- package/src/css/variables.css +45 -4
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ declare interface ActionButton<T = any> {
|
|
|
11
11
|
text: string;
|
|
12
12
|
/** Optional CSS class(es) to add to the button */
|
|
13
13
|
cssClass?: string;
|
|
14
|
+
/**
|
|
15
|
+
* 1-based row this button belongs to (default `1`). Buttons sharing a `row` render on the same
|
|
16
|
+
* horizontal line; different values stack into multiple rows. Row 1 sits at the panel's outer edge
|
|
17
|
+
* and higher rows stack inward toward the options list — so with `actions-position="top"` row 1 is
|
|
18
|
+
* the topmost line, and with `actions-position="bottom"` row 1 is the bottommost line.
|
|
19
|
+
*/
|
|
20
|
+
row?: number;
|
|
14
21
|
/** Optional tooltip text */
|
|
15
22
|
tooltip?: string;
|
|
16
23
|
/** Static visibility - set to false to hide button */
|
|
@@ -20,9 +27,9 @@ declare interface ActionButton<T = any> {
|
|
|
20
27
|
/** Custom click handler (required for 'custom' action) */
|
|
21
28
|
onClick?: (multiselect: any) => void | Promise<void>;
|
|
22
29
|
/** Dynamic visibility callback - return false to hide button (takes priority over isVisible) */
|
|
23
|
-
|
|
30
|
+
getIsVisibleCallback?: (multiselect: any) => boolean;
|
|
24
31
|
/** Dynamic disabled state callback - return true to disable button (takes priority over isDisabled) */
|
|
25
|
-
|
|
32
|
+
getIsDisabledCallback?: (multiselect: any) => boolean;
|
|
26
33
|
/** Dynamic text callback - return button text (takes priority over text) */
|
|
27
34
|
getTextCallback?: (multiselect: any) => string;
|
|
28
35
|
/** Dynamic CSS class callback - return class name(s) (takes priority over cssClass) */
|
|
@@ -31,6 +38,9 @@ declare interface ActionButton<T = any> {
|
|
|
31
38
|
getTooltipCallback?: (multiselect: any) => string;
|
|
32
39
|
}
|
|
33
40
|
|
|
41
|
+
/** Horizontal arrangement of buttons within an action row. `stretch` = full-width (default). */
|
|
42
|
+
declare type ActionsAlign = 'stretch' | 'left' | 'right' | 'center' | 'space-between';
|
|
43
|
+
|
|
34
44
|
/**
|
|
35
45
|
* Layout mode for action buttons container
|
|
36
46
|
* - 'nowrap': Buttons stay in single row (default)
|
|
@@ -38,6 +48,9 @@ declare interface ActionButton<T = any> {
|
|
|
38
48
|
*/
|
|
39
49
|
declare type ActionsLayout = 'nowrap' | 'wrap';
|
|
40
50
|
|
|
51
|
+
/** Where the action-buttons block sits in the dropdown panel. */
|
|
52
|
+
declare type ActionsPosition = 'top' | 'bottom';
|
|
53
|
+
|
|
41
54
|
/**
|
|
42
55
|
* Context provided to renderBadgeContentCallback
|
|
43
56
|
*/
|
|
@@ -107,6 +120,31 @@ export declare const interactionLogger: any;
|
|
|
107
120
|
*/
|
|
108
121
|
export declare const LOGGING_CATEGORIES: string[];
|
|
109
122
|
|
|
123
|
+
declare interface LTreeNode<T> {
|
|
124
|
+
treeId: string;
|
|
125
|
+
id: NodeId;
|
|
126
|
+
/** Materialized dot-path, e.g. "1.2.3". */
|
|
127
|
+
path: string;
|
|
128
|
+
/** This node's own segment relative to its parent. */
|
|
129
|
+
pathSegment: string;
|
|
130
|
+
parentPath: string | null | undefined;
|
|
131
|
+
/** Depth in the tree (1-based; root children are level 1). */
|
|
132
|
+
level: number | null | undefined;
|
|
133
|
+
/** Children keyed by prefixed segment (see `segmentPrefix` in ltree.ts). */
|
|
134
|
+
children: Record<string, LTreeNode<T>>;
|
|
135
|
+
hasChildren: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Whether this node may be selected. Defaults to `true`; set `false` (via
|
|
138
|
+
* `isSelectableMember`/`getIsSelectableCallback`) to make a node non-interactive
|
|
139
|
+
* — it renders normally (no grey/disabled styling) but has no checkbox, is
|
|
140
|
+
* skipped by keyboard focus, and cannot be toggled or selected by Select-All.
|
|
141
|
+
* This is distinct from `disabled` (which greys the row out).
|
|
142
|
+
*/
|
|
143
|
+
isSelectable: boolean;
|
|
144
|
+
/** The original option object this node was built from. */
|
|
145
|
+
data: T | null | undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
110
148
|
/**
|
|
111
149
|
* Generic configuration options for the MultiSelect component
|
|
112
150
|
* @template T The type of data items
|
|
@@ -124,6 +162,15 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
124
162
|
getDisplayValueCallback?: (item: T) => string;
|
|
125
163
|
/** Callback to customize badge display text (defaults to display value if not provided) */
|
|
126
164
|
getBadgeDisplayCallback?: (item: T) => string;
|
|
165
|
+
/**
|
|
166
|
+
* Member property name for a "full title" — a fully-qualified label that ships with the
|
|
167
|
+
* data (e.g. a breadcrumb like "Fruit / Pome fruit / Apple"). It is never computed by the
|
|
168
|
+
* component. When `isBadgeFullTitleShown` is on, badges display this instead of the display
|
|
169
|
+
* value (falling back to the display value when an option has none).
|
|
170
|
+
*/
|
|
171
|
+
fullTitleMember?: string;
|
|
172
|
+
/** Callback to extract the full title from an item (takes precedence over `fullTitleMember`). */
|
|
173
|
+
getFullTitleCallback?: (item: T) => string;
|
|
127
174
|
/** Callback to add custom CSS classes to badges - return string or array of class names */
|
|
128
175
|
getBadgeClassCallback?: (item: T) => string | string[];
|
|
129
176
|
/** Callback to inject custom CSS into Shadow DOM - return CSS string for styling custom classes */
|
|
@@ -140,6 +187,55 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
140
187
|
subtitleMember?: string;
|
|
141
188
|
/** Callback to extract subtitle from item */
|
|
142
189
|
getSubtitleCallback?: (item: T) => string;
|
|
190
|
+
/**
|
|
191
|
+
* Enable tree mode: options are rendered as a hierarchy, indented by depth.
|
|
192
|
+
* Auto-enabled when a path source (`pathMember`/`getPathCallback`) is set;
|
|
193
|
+
* pass `false` to force it off. The tree is always fully expanded — there is
|
|
194
|
+
* no collapse (use @keenmate/web-treeview if you need expand/collapse).
|
|
195
|
+
*/
|
|
196
|
+
isTreeEnabled?: boolean;
|
|
197
|
+
/** Member property name holding each option's materialized dot-path (e.g. "1.2.3"). */
|
|
198
|
+
pathMember?: string;
|
|
199
|
+
/** Callback returning an option's materialized dot-path (takes precedence over pathMember). */
|
|
200
|
+
getPathCallback?: (item: T) => string;
|
|
201
|
+
/** Member holding an option's parent path (otherwise derived from its path). */
|
|
202
|
+
parentPathMember?: string;
|
|
203
|
+
/** Member holding an option's depth/level (otherwise derived from its path). */
|
|
204
|
+
levelMember?: string;
|
|
205
|
+
/** Member holding a precomputed hasChildren flag (otherwise derived from the tree). */
|
|
206
|
+
hasChildrenMember?: string;
|
|
207
|
+
/** Path separator for tree paths. Default: "." */
|
|
208
|
+
treePathSeparator?: string;
|
|
209
|
+
/**
|
|
210
|
+
* Member holding a per-option `isSelectable` flag for tree mode. A node with a
|
|
211
|
+
* falsy value renders normally (NOT greyed like `disabled`) but has no checkbox,
|
|
212
|
+
* is skipped by keyboard focus, and cannot be toggled or picked by Select-All.
|
|
213
|
+
* Options default to selectable. Tree mode only.
|
|
214
|
+
*/
|
|
215
|
+
isSelectableMember?: string;
|
|
216
|
+
/**
|
|
217
|
+
* Callback deciding whether a tree node is selectable (takes precedence over
|
|
218
|
+
* `isSelectableMember`). Receives the built tree node, so `node.hasChildren` /
|
|
219
|
+
* `node.level` are available — e.g. `(node) => !node.hasChildren` for a
|
|
220
|
+
* leaves-only tree. Tree mode only.
|
|
221
|
+
*/
|
|
222
|
+
getIsSelectableCallback?: (node: LTreeNode<T>) => boolean;
|
|
223
|
+
/**
|
|
224
|
+
* Tree checkbox interaction. `independent` (default) toggles only the clicked
|
|
225
|
+
* node. `cascade` checks a node's whole subtree and shows a tristate
|
|
226
|
+
* (checked / indeterminate / unchecked) box on branches. Tree + multiple only.
|
|
227
|
+
*/
|
|
228
|
+
checkboxMode?: 'independent' | 'cascade';
|
|
229
|
+
/**
|
|
230
|
+
* In `cascade` mode, which values a selection emits (badges / form / change):
|
|
231
|
+
* - `rolled-up` (default) — minimal cover: a fully-selected subtree collapses
|
|
232
|
+
* to its root ("complete node"); partially-selected branches emit their
|
|
233
|
+
* individually-checked descendants. Rolls to the nearest selectable
|
|
234
|
+
* descendant when the complete node itself is non-selectable.
|
|
235
|
+
* - `leaves` — only the checked leaf-level nodes.
|
|
236
|
+
* - `all` — every fully-checked node (branches and leaves), like web-treeview.
|
|
237
|
+
*/
|
|
238
|
+
cascadeSelectPolicy?: 'rolled-up' | 'leaves' | 'all';
|
|
143
239
|
/** Member property name for group extraction */
|
|
144
240
|
groupMember?: string;
|
|
145
241
|
/** Callback to extract group from item */
|
|
@@ -186,6 +282,12 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
186
282
|
isAddNewAllowed?: boolean;
|
|
187
283
|
/** Show count badge next to toggle icon (internal: isCounterShown) */
|
|
188
284
|
isCounterShown?: boolean;
|
|
285
|
+
/**
|
|
286
|
+
* Make badges display each option's `fullTitleMember` / `getFullTitleCallback` value
|
|
287
|
+
* instead of its display value. Falls back to the display value for options without a
|
|
288
|
+
* full title. An explicit `getBadgeDisplayCallback` still takes precedence. Off by default.
|
|
289
|
+
*/
|
|
290
|
+
isBadgeFullTitleShown?: boolean;
|
|
189
291
|
/** Keep initial options visible when searchCallback is active and search term is empty/short (internal: isKeepOptionsOnSearch) */
|
|
190
292
|
isKeepOptionsOnSearch?: boolean;
|
|
191
293
|
/** Keep search text and filtered results when dropdown closes (default: true) */
|
|
@@ -232,6 +334,10 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
232
334
|
searchMode?: SearchMode;
|
|
233
335
|
/** Layout mode for action buttons: 'nowrap' (default) or 'wrap' for multi-row */
|
|
234
336
|
actionsLayout?: ActionsLayout;
|
|
337
|
+
/** Where the action-buttons block sits in the dropdown: 'top' (default) or 'bottom' (sticky footer). */
|
|
338
|
+
actionsPosition?: ActionsPosition;
|
|
339
|
+
/** Horizontal arrangement of buttons within a row: 'stretch' (default, full-width), 'left', 'right', 'center', or 'space-between'. */
|
|
340
|
+
actionsAlign?: ActionsAlign;
|
|
235
341
|
/** Auto-switch from badges to count when threshold is exceeded */
|
|
236
342
|
badgesThreshold?: number | null;
|
|
237
343
|
/** Maximum number of badges to show in partial mode (used with thresholdMode='partial') */
|
|
@@ -255,6 +361,23 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
255
361
|
virtualScrollBuffer?: number;
|
|
256
362
|
/** Pre-process search term before calling searchCallback. Return null to prevent search. Use for accent removal, validation, etc. */
|
|
257
363
|
beforeSearchCallback?: ((searchTerm: string) => string | null) | null;
|
|
364
|
+
/**
|
|
365
|
+
* Interceptor: runs before an option is selected via user interaction.
|
|
366
|
+
* Receives the option about to be added and the current selection (before the change).
|
|
367
|
+
* Return `false` to block the selection; return `true`/`undefined` to allow.
|
|
368
|
+
* Silent — a blocked action fires no event. Bypassed by programmatic `setSelected`
|
|
369
|
+
* and the Select-All action button.
|
|
370
|
+
*/
|
|
371
|
+
beforeSelectCallback?: ((option: T, selectedOptions: T[]) => boolean | void) | null;
|
|
372
|
+
/**
|
|
373
|
+
* Interceptor: runs before an option is deselected via user interaction — the dropdown
|
|
374
|
+
* option toggle, a badge's remove (×) button, the selected-items popover's remove button,
|
|
375
|
+
* and the "remove hidden" badge (checked per item). Receives the option about to be
|
|
376
|
+
* removed and the current selection (before the change). Return `false` to block the
|
|
377
|
+
* deselection; return `true`/`undefined` to allow. Silent — a blocked action fires no
|
|
378
|
+
* event. Bypassed by programmatic `setSelected` and the Clear-All action button.
|
|
379
|
+
*/
|
|
380
|
+
beforeDeselectCallback?: ((option: T, selectedOptions: T[]) => boolean | void) | null;
|
|
258
381
|
/**
|
|
259
382
|
* Async function to load data: `(searchTerm, signal) => Promise<options[]>`.
|
|
260
383
|
* The optional second argument is an `AbortSignal` that fires when a newer search
|
|
@@ -264,12 +387,12 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
264
387
|
searchCallback?: ((searchTerm: string, signal?: AbortSignal) => Promise<T[]>) | null;
|
|
265
388
|
/** Callback to add a new option when isAddNewAllowed is true */
|
|
266
389
|
addNewCallback?: ((value: string) => T | Promise<T>) | null;
|
|
267
|
-
/**
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
|
|
390
|
+
/** Event handler: an option was selected (fire-and-forget; return value ignored). Mirrors the bubbling `select` CustomEvent on the element. */
|
|
391
|
+
onSelect?: ((option: T) => void) | null;
|
|
392
|
+
/** Event handler: an option was deselected (fire-and-forget). Mirrors the bubbling `deselect` CustomEvent on the element. */
|
|
393
|
+
onDeselect?: ((option: T) => void) | null;
|
|
394
|
+
/** Event handler: the selection set changed (fire-and-forget). Mirrors the bubbling `change` CustomEvent on the element. */
|
|
395
|
+
onChange?: ((selectedOptions: T[]) => void) | null;
|
|
273
396
|
/** Callback to format count badge text (for i18n/pluralization). When moreCount is provided, it's for the "+X more" badge in partial mode. */
|
|
274
397
|
getCounterCallback?: ((count: number, moreCount?: number) => string) | null;
|
|
275
398
|
/** Enable tooltips on selected item badges (internal: isBadgeTooltipsEnabled) */
|
|
@@ -286,6 +409,18 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
286
409
|
badgeTooltipDelay?: number;
|
|
287
410
|
/** Offset distance for tooltip in pixels */
|
|
288
411
|
badgeTooltipOffset?: number;
|
|
412
|
+
/** Enable tooltips on dropdown options (internal: isOptionTooltipsEnabled) */
|
|
413
|
+
isOptionTooltipsEnabled?: boolean;
|
|
414
|
+
/** Callback to generate custom tooltip content for a dropdown option. Default: display value, plus subtitle on the next line when present. */
|
|
415
|
+
getOptionTooltipCallback?: ((item: T) => string | HTMLElement) | null;
|
|
416
|
+
/** Option tooltip placement. Default `'top-start'` (anchored to the row's start edge, so it doesn't center on a full-width row). Use `'left'`/`'right'` (start/end side) for a narrow multiselect. */
|
|
417
|
+
optionTooltipPlacement?: Placement;
|
|
418
|
+
/** Delay before showing an option tooltip (ms). Falls back to `badgeTooltipDelay`, then `100`. */
|
|
419
|
+
optionTooltipDelay?: number;
|
|
420
|
+
/** Offset distance for an option tooltip (px). Falls back to `badgeTooltipOffset`, then `8`. */
|
|
421
|
+
optionTooltipOffset?: number;
|
|
422
|
+
/** Anchor the option tooltip to the mouse pointer and follow it across the row (best for full-width rows). Default `false`. */
|
|
423
|
+
isOptionTooltipFollowCursor?: boolean;
|
|
289
424
|
/** Container element for dropdown/hint/popover (for Shadow DOM support) */
|
|
290
425
|
container?: HTMLElement | null;
|
|
291
426
|
/** Host element for appending hidden inputs (for form integration with shadow DOM) */
|
|
@@ -313,13 +448,18 @@ export declare class MultiSelectElement<T = any> extends BaseElement {
|
|
|
313
448
|
private _getIconCallback?;
|
|
314
449
|
private _subtitleMember?;
|
|
315
450
|
private _getSubtitleCallback?;
|
|
451
|
+
private _getFullTitleCallback?;
|
|
316
452
|
private _groupMember?;
|
|
317
453
|
private _getGroupCallback?;
|
|
318
454
|
private _renderGroupLabelContentCallback?;
|
|
319
455
|
private _disabledMember?;
|
|
320
456
|
private _getDisabledCallback?;
|
|
457
|
+
private _getPathCallback?;
|
|
458
|
+
private _isTreeEnabled?;
|
|
459
|
+
private _getIsSelectableCallback?;
|
|
321
460
|
private _getValueFormatCallback?;
|
|
322
461
|
private _getBadgeTooltipCallback?;
|
|
462
|
+
private _getOptionTooltipCallback?;
|
|
323
463
|
private _getRemoveButtonTooltipCallback?;
|
|
324
464
|
private _renderOptionContentCallback?;
|
|
325
465
|
private _renderBadgeContentCallback?;
|
|
@@ -332,11 +472,13 @@ export declare class MultiSelectElement<T = any> extends BaseElement {
|
|
|
332
472
|
private _batchPartial;
|
|
333
473
|
private _batchNeedsReinit;
|
|
334
474
|
private _beforeSearchCallback?;
|
|
475
|
+
private _beforeSelectCallback?;
|
|
476
|
+
private _beforeDeselectCallback?;
|
|
335
477
|
private _searchCallback?;
|
|
336
478
|
private _addNewCallback?;
|
|
337
|
-
private
|
|
338
|
-
private
|
|
339
|
-
private
|
|
479
|
+
private _onSelect?;
|
|
480
|
+
private _onDeselect?;
|
|
481
|
+
private _onChange?;
|
|
340
482
|
static get observedAttributes(): string[];
|
|
341
483
|
constructor();
|
|
342
484
|
/**
|
|
@@ -398,10 +540,28 @@ export declare class MultiSelectElement<T = any> extends BaseElement {
|
|
|
398
540
|
get iconMember(): string | null;
|
|
399
541
|
set subtitleMember(value: string | null);
|
|
400
542
|
get subtitleMember(): string | null;
|
|
543
|
+
set fullTitleMember(value: string | null);
|
|
544
|
+
get fullTitleMember(): string | null;
|
|
401
545
|
set groupMember(value: string | null);
|
|
402
546
|
get groupMember(): string | null;
|
|
403
547
|
set disabledMember(value: string | null);
|
|
404
548
|
get disabledMember(): string | null;
|
|
549
|
+
set pathMember(value: string | null);
|
|
550
|
+
get pathMember(): string | null;
|
|
551
|
+
set parentPathMember(value: string | null);
|
|
552
|
+
get parentPathMember(): string | null;
|
|
553
|
+
set levelMember(value: string | null);
|
|
554
|
+
get levelMember(): string | null;
|
|
555
|
+
set hasChildrenMember(value: string | null);
|
|
556
|
+
get hasChildrenMember(): string | null;
|
|
557
|
+
set isSelectableMember(value: string | null);
|
|
558
|
+
get isSelectableMember(): string | null;
|
|
559
|
+
set treePathSeparator(value: string | null);
|
|
560
|
+
get treePathSeparator(): string | null;
|
|
561
|
+
set checkboxMode(value: 'independent' | 'cascade' | null);
|
|
562
|
+
get checkboxMode(): 'independent' | 'cascade' | null;
|
|
563
|
+
set cascadeSelectPolicy(value: 'rolled-up' | 'leaves' | 'all' | null);
|
|
564
|
+
get cascadeSelectPolicy(): 'rolled-up' | 'leaves' | 'all' | null;
|
|
405
565
|
set getValueCallback(callback: ((item: T) => string | number) | undefined);
|
|
406
566
|
get getValueCallback(): ((item: T) => string | number) | undefined;
|
|
407
567
|
set getDisplayValueCallback(callback: ((item: T) => string) | undefined);
|
|
@@ -418,8 +578,24 @@ export declare class MultiSelectElement<T = any> extends BaseElement {
|
|
|
418
578
|
get getIconCallback(): ((item: T) => string) | undefined;
|
|
419
579
|
set getSubtitleCallback(callback: ((item: T) => string) | undefined);
|
|
420
580
|
get getSubtitleCallback(): ((item: T) => string) | undefined;
|
|
581
|
+
/** Callback returning an option's full title (used by badges when show-badge-full-title is on). */
|
|
582
|
+
set getFullTitleCallback(callback: ((item: T) => string) | undefined);
|
|
583
|
+
get getFullTitleCallback(): ((item: T) => string) | undefined;
|
|
421
584
|
set getGroupCallback(callback: ((item: T) => string) | undefined);
|
|
422
585
|
get getGroupCallback(): ((item: T) => string) | undefined;
|
|
586
|
+
/** Callback returning an option's materialized dot-path (enables tree mode). */
|
|
587
|
+
set getPathCallback(callback: ((item: T) => string) | undefined);
|
|
588
|
+
get getPathCallback(): ((item: T) => string) | undefined;
|
|
589
|
+
/** Force tree mode on/off. When unset, tree mode auto-enables if a path source is present. */
|
|
590
|
+
set isTreeEnabled(value: boolean | undefined);
|
|
591
|
+
get isTreeEnabled(): boolean | undefined;
|
|
592
|
+
/**
|
|
593
|
+
* Callback deciding whether a tree node is selectable (takes precedence over
|
|
594
|
+
* `is-selectable-member`). Receives the built node — e.g.
|
|
595
|
+
* `el.getIsSelectableCallback = (node) => !node.hasChildren` for leaves only.
|
|
596
|
+
*/
|
|
597
|
+
set getIsSelectableCallback(callback: ((node: LTreeNode<T>) => boolean) | undefined);
|
|
598
|
+
get getIsSelectableCallback(): ((node: LTreeNode<T>) => boolean) | undefined;
|
|
423
599
|
set renderGroupLabelContentCallback(callback: ((groupName: string) => string | HTMLElement) | undefined);
|
|
424
600
|
get renderGroupLabelContentCallback(): ((groupName: string) => string | HTMLElement) | undefined;
|
|
425
601
|
set getDisabledCallback(callback: ((item: T) => boolean) | undefined);
|
|
@@ -448,6 +624,18 @@ export declare class MultiSelectElement<T = any> extends BaseElement {
|
|
|
448
624
|
get checkboxAlign(): string | null;
|
|
449
625
|
set enableBadgeTooltips(value: boolean);
|
|
450
626
|
get enableBadgeTooltips(): boolean;
|
|
627
|
+
set enableOptionTooltips(value: boolean);
|
|
628
|
+
get enableOptionTooltips(): boolean;
|
|
629
|
+
set getOptionTooltipCallback(callback: ((item: T) => string | HTMLElement) | undefined);
|
|
630
|
+
get getOptionTooltipCallback(): ((item: T) => string | HTMLElement) | undefined;
|
|
631
|
+
set optionTooltipPlacement(value: string | null);
|
|
632
|
+
get optionTooltipPlacement(): string | null;
|
|
633
|
+
set optionTooltipFollowCursor(value: boolean);
|
|
634
|
+
get optionTooltipFollowCursor(): boolean;
|
|
635
|
+
set actionsPosition(value: string | null);
|
|
636
|
+
get actionsPosition(): string | null;
|
|
637
|
+
set actionsAlign(value: string | null);
|
|
638
|
+
get actionsAlign(): string | null;
|
|
451
639
|
set badgeTooltipPlacement(value: string | null);
|
|
452
640
|
get badgeTooltipPlacement(): string | null;
|
|
453
641
|
set getBadgeTooltipCallback(callback: ((item: T) => string | HTMLElement) | undefined);
|
|
@@ -460,16 +648,20 @@ export declare class MultiSelectElement<T = any> extends BaseElement {
|
|
|
460
648
|
get getCounterCallback(): ((count: number, moreCount?: number) => string) | undefined;
|
|
461
649
|
get beforeSearchCallback(): ((searchTerm: string) => string | null) | undefined;
|
|
462
650
|
set beforeSearchCallback(callback: ((searchTerm: string) => string | null) | undefined);
|
|
651
|
+
get beforeSelectCallback(): ((option: T, selectedOptions: T[]) => boolean | void) | undefined;
|
|
652
|
+
set beforeSelectCallback(callback: ((option: T, selectedOptions: T[]) => boolean | void) | undefined);
|
|
653
|
+
get beforeDeselectCallback(): ((option: T, selectedOptions: T[]) => boolean | void) | undefined;
|
|
654
|
+
set beforeDeselectCallback(callback: ((option: T, selectedOptions: T[]) => boolean | void) | undefined);
|
|
463
655
|
get searchCallback(): ((searchTerm: string, signal?: AbortSignal) => Promise<T[]>) | undefined;
|
|
464
656
|
set searchCallback(callback: ((searchTerm: string, signal?: AbortSignal) => Promise<T[]>) | undefined);
|
|
465
657
|
get addNewCallback(): ((value: string) => T | Promise<T>) | undefined;
|
|
466
658
|
set addNewCallback(callback: ((value: string) => T | Promise<T>) | undefined);
|
|
467
|
-
get
|
|
468
|
-
set
|
|
469
|
-
get
|
|
470
|
-
set
|
|
471
|
-
get
|
|
472
|
-
set
|
|
659
|
+
get onSelect(): ((option: T) => void) | undefined;
|
|
660
|
+
set onSelect(callback: ((option: T) => void) | undefined);
|
|
661
|
+
get onDeselect(): ((option: T) => void) | undefined;
|
|
662
|
+
set onDeselect(callback: ((option: T) => void) | undefined);
|
|
663
|
+
get onChange(): ((selectedOptions: T[]) => void) | undefined;
|
|
664
|
+
set onChange(callback: ((selectedOptions: T[]) => void) | undefined);
|
|
473
665
|
get actionButtons(): any[] | undefined;
|
|
474
666
|
set actionButtons(value: any[] | undefined);
|
|
475
667
|
get selectedValue(): string | number | (string | number)[] | null;
|
|
@@ -521,11 +713,22 @@ export declare interface MultiSelectOptions extends MultiSelectConfig<MultiSelec
|
|
|
521
713
|
options?: MultiSelectOption[];
|
|
522
714
|
searchCallback?: ((searchTerm: string, signal?: AbortSignal) => Promise<MultiSelectOption[]>) | null;
|
|
523
715
|
addNewCallback?: ((value: string) => MultiSelectOption | Promise<MultiSelectOption>) | null;
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
716
|
+
onSelect?: ((option: MultiSelectOption) => void) | null;
|
|
717
|
+
onDeselect?: ((option: MultiSelectOption) => void) | null;
|
|
718
|
+
onChange?: ((selectedOptions: MultiSelectOption[]) => void) | null;
|
|
527
719
|
}
|
|
528
720
|
|
|
721
|
+
/**
|
|
722
|
+
* LTreeNode — a single node in the option tree.
|
|
723
|
+
*
|
|
724
|
+
* Trimmed lift of web-treeview's `ltree/ltree-node.ts`. The multiselect renders
|
|
725
|
+
* every node expanded (no collapse), so this keeps only the structural fields
|
|
726
|
+
* needed to order nodes and indent them: path/parent/level/children/hasChildren
|
|
727
|
+
* plus the original option `data`. Expand state, drag-drop, checkbox, selection
|
|
728
|
+
* and drop-position fields are all thrown out.
|
|
729
|
+
*/
|
|
730
|
+
declare type NodeId = string | number;
|
|
731
|
+
|
|
529
732
|
/**
|
|
530
733
|
* Context provided to renderOptionContentCallback
|
|
531
734
|
*/
|
|
@@ -584,6 +787,10 @@ export declare class WebMultiSelect<T = any> {
|
|
|
584
787
|
private selectedOptions;
|
|
585
788
|
private allOptions;
|
|
586
789
|
private filteredOptions;
|
|
790
|
+
private tree;
|
|
791
|
+
private treeNodes;
|
|
792
|
+
private cascadeIndex;
|
|
793
|
+
private cascadeCheckedAtoms;
|
|
587
794
|
private hiddenInputs;
|
|
588
795
|
private focusedIndex;
|
|
589
796
|
private matchingIndices;
|
|
@@ -637,14 +844,72 @@ export declare class WebMultiSelect<T = any> {
|
|
|
637
844
|
* text independently. Doesn't fit the extractField shape (no tuple/member layer of its own).
|
|
638
845
|
*/
|
|
639
846
|
private getItemBadgeDisplayValue;
|
|
847
|
+
/**
|
|
848
|
+
* Full title — a fully-qualified label supplied with the data (never computed here). Used by
|
|
849
|
+
* badges when `isBadgeFullTitleShown` is on. Returns undefined when the option has none.
|
|
850
|
+
*/
|
|
851
|
+
private getItemFullTitle;
|
|
640
852
|
private getItemSearchValue;
|
|
641
853
|
private getItemIcon;
|
|
642
854
|
private getItemSubtitle;
|
|
643
855
|
private getItemGroup;
|
|
644
856
|
private getItemDisabled;
|
|
857
|
+
/**
|
|
858
|
+
* Tree mode: whether the visible node at `index` may be selected. Non-selectable
|
|
859
|
+
* nodes (see `isSelectableMember`/`getIsSelectableCallback`) still render — just
|
|
860
|
+
* without a checkbox — but are skipped by focus and cannot be toggled. Always
|
|
861
|
+
* true outside tree mode. `treeNodes` is index-aligned with `filteredOptions`.
|
|
862
|
+
*/
|
|
863
|
+
private isIndexSelectable;
|
|
864
|
+
/** Whether an option may be selected. Always true outside tree mode. */
|
|
865
|
+
private isOptionSelectable;
|
|
645
866
|
constructor(element: HTMLElement, options?: Partial<MultiSelectConfig<T>>);
|
|
646
867
|
private init;
|
|
647
868
|
private parseOptions;
|
|
869
|
+
/** Whether options should be rendered as an (always-expanded) tree. */
|
|
870
|
+
private isTreeMode;
|
|
871
|
+
/** (Re)build the ltree from `allOptions` and derive the visible flat list. */
|
|
872
|
+
private buildTree;
|
|
873
|
+
/**
|
|
874
|
+
* Whether cascade checkbox mode is active: a multi-select tree with
|
|
875
|
+
* `checkbox-mode="cascade"`. Checking a node then toggles its whole subtree
|
|
876
|
+
* and branches show a tristate box.
|
|
877
|
+
*/
|
|
878
|
+
private isCascadeMode;
|
|
879
|
+
private cascadePolicy;
|
|
880
|
+
/** Refresh the derived checked-atom set from the emitted `selectedValues`. */
|
|
881
|
+
private refreshCascadeAtoms;
|
|
882
|
+
/**
|
|
883
|
+
* Toggle a tree node in cascade mode: flip its whole subtree, re-project the
|
|
884
|
+
* checked atoms to emitted values under the active policy, and commit the diff
|
|
885
|
+
* so badges / form / change events reflect the policy (rolled-up branches, etc.).
|
|
886
|
+
*/
|
|
887
|
+
private toggleTreeCascade;
|
|
888
|
+
/**
|
|
889
|
+
* Derive `treeNodes` + `filteredOptions` from the full tree, applying the
|
|
890
|
+
* current search term. Matching nodes keep all their ancestors visible so
|
|
891
|
+
* indentation stays coherent (the tree is always fully expanded).
|
|
892
|
+
*/
|
|
893
|
+
private rebuildTreeVisible;
|
|
894
|
+
/**
|
|
895
|
+
* Reset the visible list to "everything". **Tree-aware**: in tree mode it
|
|
896
|
+
* rebuilds `treeNodes` (kept index-aligned with `filteredOptions`) from the
|
|
897
|
+
* full tree, so the two never drift. A raw `filteredOptions = [...allOptions]`
|
|
898
|
+
* would leave `treeNodes` stale after clearing a search — the virtual list
|
|
899
|
+
* then reserves height for every option but renders blank rows because
|
|
900
|
+
* `treeNodes[index]` is undefined. Always use this to clear the visible list.
|
|
901
|
+
*/
|
|
902
|
+
private resetVisibleToAll;
|
|
903
|
+
/**
|
|
904
|
+
* Tree mode: derive the visible list from an **external** set of matched
|
|
905
|
+
* options — e.g. the results returned by `searchCallback` — keeping each
|
|
906
|
+
* match's ancestors so indentation stays coherent. This is the async-search
|
|
907
|
+
* analogue of `rebuildTreeVisible`: the matching is done by the caller (their
|
|
908
|
+
* own index/engine) instead of a local substring test, but ancestor
|
|
909
|
+
* preservation and `treeNodes`/`filteredOptions` index-alignment still happen
|
|
910
|
+
* here. Pass all options to show the whole tree.
|
|
911
|
+
*/
|
|
912
|
+
private rebuildTreeVisibleFromMatches;
|
|
648
913
|
private buildHTML;
|
|
649
914
|
/**
|
|
650
915
|
* Check if virtual scroll should be used
|
|
@@ -663,8 +928,24 @@ export declare class WebMultiSelect<T = any> {
|
|
|
663
928
|
* Render the Select All / Clear All / custom action buttons row.
|
|
664
929
|
* Returns the empty string if multiple-select is off or no buttons are configured.
|
|
665
930
|
*/
|
|
931
|
+
/**
|
|
932
|
+
* Default enabled/disabled state for the built-in actions, applied only when the consumer hasn't
|
|
933
|
+
* set an explicit `isDisabled` / `getIsDisabledCallback`:
|
|
934
|
+
* - `select-all` is disabled when it would add nothing (every selectable, non-disabled filtered
|
|
935
|
+
* option is already selected — this also covers an empty list).
|
|
936
|
+
* - `clear-all` is disabled when nothing is selected.
|
|
937
|
+
*/
|
|
938
|
+
private getBuiltInActionDisabled;
|
|
666
939
|
private renderActionsHTML;
|
|
667
940
|
private renderOption;
|
|
941
|
+
/**
|
|
942
|
+
* Render a single tree-mode row. Separate from `renderOption`: a tree row is
|
|
943
|
+
* indented by its depth (via the `--ms-tree-depth` custom property) and
|
|
944
|
+
* tagged branch/leaf, but otherwise carries the same selection/checkbox/
|
|
945
|
+
* icon/subtitle content. The tree is always fully expanded, so there is no
|
|
946
|
+
* chevron/toggle — every node is just a normal, selectable option.
|
|
947
|
+
*/
|
|
948
|
+
private renderTreeNode;
|
|
668
949
|
private highlightMatch;
|
|
669
950
|
private groupOptions;
|
|
670
951
|
/** Whether the input currently functions as a usable search field (drives placeholder wording). */
|
|
@@ -701,6 +982,13 @@ export declare class WebMultiSelect<T = any> {
|
|
|
701
982
|
* Returning -1 from `compute` is a no-op (used for empty list / no match).
|
|
702
983
|
*/
|
|
703
984
|
private focusBy;
|
|
985
|
+
/**
|
|
986
|
+
* Given a target index and a preferred direction, return the nearest index
|
|
987
|
+
* whose node is selectable (skipping non-selectable tree nodes). Falls back to
|
|
988
|
+
* the opposite direction, then to -1 if nothing is selectable. No-op outside
|
|
989
|
+
* tree mode.
|
|
990
|
+
*/
|
|
991
|
+
private resolveSelectableIndex;
|
|
704
992
|
private focusNext;
|
|
705
993
|
private focusPrevious;
|
|
706
994
|
private focusFirst;
|
|
@@ -711,6 +999,23 @@ export declare class WebMultiSelect<T = any> {
|
|
|
711
999
|
private focusPreviousMatch;
|
|
712
1000
|
private scrollToFocused;
|
|
713
1001
|
private toggleOption;
|
|
1002
|
+
/**
|
|
1003
|
+
* The single funnel for an interactive (user-initiated) selection. Consults
|
|
1004
|
+
* `beforeSelectCallback` and only mutates state if allowed, so the veto can
|
|
1005
|
+
* never be bypassed by a new UI entry point. Programmatic `setSelected` and
|
|
1006
|
+
* the Select-All button deliberately do not route through here.
|
|
1007
|
+
* Returns true if the option was selected, false if the veto blocked it.
|
|
1008
|
+
*/
|
|
1009
|
+
private interactiveSelect;
|
|
1010
|
+
/**
|
|
1011
|
+
* The single funnel for an interactive (user-initiated) deselection. Every
|
|
1012
|
+
* removal affordance — dropdown toggle, badge × button, selected-items
|
|
1013
|
+
* popover × button, and the "remove hidden" badge — routes through here so
|
|
1014
|
+
* the `beforeDeselectCallback` veto applies uniformly. Programmatic
|
|
1015
|
+
* `setSelected` and the Clear-All button deliberately bypass it.
|
|
1016
|
+
* Returns true if the option was deselected, false if the veto blocked it.
|
|
1017
|
+
*/
|
|
1018
|
+
private interactiveDeselect;
|
|
714
1019
|
private handleAddNew;
|
|
715
1020
|
private selectOption;
|
|
716
1021
|
private deselectOption;
|
|
@@ -719,7 +1024,7 @@ export declare class WebMultiSelect<T = any> {
|
|
|
719
1024
|
/**
|
|
720
1025
|
* Re-render and fire callbacks after a selection state change.
|
|
721
1026
|
* `added` / `removed` drive per-item select/deselect callbacks.
|
|
722
|
-
* `
|
|
1027
|
+
* `onChange` fires once if anything actually changed.
|
|
723
1028
|
*/
|
|
724
1029
|
private commit;
|
|
725
1030
|
private open;
|
|
@@ -803,6 +1108,20 @@ export declare class WebMultiSelect<T = any> {
|
|
|
803
1108
|
/** Build the remove-button tooltip text (callback > format string with {0} > "Remove {name}"). */
|
|
804
1109
|
private buildRemoveButtonTooltipText;
|
|
805
1110
|
private attachBadgeTooltips;
|
|
1111
|
+
/** Build the option tooltip content (callback overrides; default = displayValue + optional subtitle on next line). */
|
|
1112
|
+
private buildOptionTooltipContent;
|
|
1113
|
+
/**
|
|
1114
|
+
* Attach hover tooltips to the currently rendered dropdown options. Prunes existing option
|
|
1115
|
+
* tooltips first, so it's safe to call on every render and on every virtual-scroll range change
|
|
1116
|
+
* (where option DOM is recycled). Each option resolves its source object via `data-index` into
|
|
1117
|
+
* `filteredOptions`, the same global index `renderOption` was given.
|
|
1118
|
+
*/
|
|
1119
|
+
private attachOptionTooltips;
|
|
1120
|
+
/**
|
|
1121
|
+
* Destroy only the option tooltips (prefixed `option-`). Called before re-rendering or
|
|
1122
|
+
* recycling the options list so per-option tooltip state doesn't leak.
|
|
1123
|
+
*/
|
|
1124
|
+
private destroyAllOptionTooltips;
|
|
806
1125
|
private attachActionButtonTooltips;
|
|
807
1126
|
/**
|
|
808
1127
|
* Destroy only the action-button tooltips. Called from `renderDropdown`/`renderDropdownVirtual`
|