@keenmate/web-multiselect 1.12.0-rc07 → 2.0.0-rc01

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/dist/index.d.ts CHANGED
@@ -1,4 +1,8 @@
1
- import { Placement } from '@floating-ui/dom';
1
+ import { BlissElement } from '@keenmate/web-components-core';
2
+ import { InputDef } from '@keenmate/web-components-core';
3
+ import { Logger } from '@keenmate/web-components-core';
4
+ import { LogLevelDesc } from '@keenmate/web-components-core';
5
+ import { Placement } from '@keenmate/web-components-core/positioning';
2
6
 
3
7
  /**
4
8
  * Action button configuration for dropdown actions (Select All, Clear All, custom actions)
@@ -76,47 +80,21 @@ export declare type BadgesPosition = 'top' | 'bottom' | 'left' | 'right';
76
80
  */
77
81
  export declare type BadgesThresholdMode = 'count' | 'partial';
78
82
 
79
- declare const BaseElement: typeof HTMLElement;
83
+ export declare const dataLogger: Logger;
80
84
 
81
- export declare const dataLogger: any;
82
-
83
- /**
84
- * Disable all logging (set to silent level)
85
- */
85
+ /** Disable all logging (silent). */
86
86
  export declare function disableLogging(): void;
87
87
 
88
- /**
89
- * Enable all logging (set to debug level)
90
- */
88
+ /** Enable all logging (debug level). */
91
89
  export declare function enableLogging(): void;
92
90
 
93
- export declare interface GlobalMultiSelectAPI {
94
- version: () => string;
95
- config: {
96
- name: string;
97
- version: string;
98
- author: string;
99
- license: string;
100
- repository: string;
101
- homepage: string;
102
- };
103
- logging: {
104
- enableLogging: () => void;
105
- disableLogging: () => void;
106
- setLogLevel: (level: string) => void;
107
- setCategoryLevel: (category: string, level: string) => void;
108
- getCategories: () => string[];
109
- };
110
- register: () => void;
111
- getInstances: () => HTMLElement[];
112
- }
113
-
114
- export declare const initLogger: any;
91
+ export declare const initLogger: Logger;
115
92
 
116
- export declare const interactionLogger: any;
93
+ export declare const interactionLogger: Logger;
117
94
 
118
95
  /**
119
- * List of all logging categories for introspection
96
+ * Full (namespaced) category names, kept for the `getCategories()` global API
97
+ * and any consumer that introspected the list.
120
98
  */
121
99
  export declare const LOGGING_CATEGORIES: string[];
122
100
 
@@ -227,7 +205,8 @@ declare interface MultiSelectConfig<T = any> {
227
205
  */
228
206
  checkboxMode?: 'independent' | 'cascade';
229
207
  /**
230
- * In `cascade` mode, which values a selection emits (badges / form / change):
208
+ * In `cascade` mode, which values a selection emits (badges / form / change).
209
+ *
231
210
  * - `rolled-up` (default) — minimal cover: a fully-selected subtree collapses
232
211
  * to its root ("complete node"); partially-selected branches emit their
233
212
  * individually-checked descendants. Rolls to the nearest selectable
@@ -258,7 +237,13 @@ declare interface MultiSelectConfig<T = any> {
258
237
  renderSelectedContentCallback?: (item: T) => string;
259
238
  /** HTML form field ID/name for hidden input */
260
239
  formFieldId?: string;
261
- /** Format for value serialization (forms and callbacks) */
240
+ /**
241
+ * Format for value serialization (hidden form inputs and callbacks). Default: `json`.
242
+ *
243
+ * - `json` — a JSON array string, e.g. `["a","b"]`
244
+ * - `csv` — comma-separated values, e.g. `a,b`
245
+ * - `array` — one hidden input per value (`name[]` entries)
246
+ */
262
247
  valueFormat?: ValueFormat;
263
248
  /** Custom callback to format value */
264
249
  getValueFormatCallback?: (selectedValues: (string | number)[]) => string;
@@ -294,7 +279,13 @@ declare interface MultiSelectConfig<T = any> {
294
279
  shouldKeepSearchOnClose?: boolean;
295
280
  /** Enable virtual scrolling for large datasets (internal: isVirtualScrollEnabled) */
296
281
  isVirtualScrollEnabled?: boolean;
297
- /** Vertical alignment of checkboxes relative to option content */
282
+ /**
283
+ * Vertical alignment of checkboxes relative to option content. Default: `center`.
284
+ *
285
+ * - `top` — align to the top of the row
286
+ * - `center` — vertically centered
287
+ * - `bottom` — align to the bottom of the row
288
+ */
298
289
  checkboxAlign?: 'top' | 'center' | 'bottom';
299
290
  /** Hint text shown above the input while the dropdown is open. */
300
291
  searchHint?: string;
@@ -316,11 +307,31 @@ declare interface MultiSelectConfig<T = any> {
316
307
  dropdownMinWidth?: string | null;
317
308
  /** Maximum width for the dropdown (e.g., '40rem', '500px') */
318
309
  dropdownMaxWidth?: string | null;
319
- /** Display mode for selected items in badges area */
310
+ /**
311
+ * Display mode for selected items in the badges area. Default: `badges`.
312
+ *
313
+ * - `badges` — one removable badge per selected option
314
+ * - `count` — a single "N selected" count badge
315
+ * - `compact` — condensed badges (first few, tighter spacing)
316
+ * - `partial` — a limited number of badges plus a "+X more" badge
317
+ * - `none` — hide the badges area entirely
318
+ */
320
319
  badgesDisplayMode?: BadgesDisplayMode;
321
- /** Position of badges container */
320
+ /**
321
+ * Position of the badges container relative to the input. Default: `bottom`.
322
+ *
323
+ * - `top` — above the input
324
+ * - `bottom` — below the input
325
+ * - `left` — to the left of the input
326
+ * - `right` — to the right of the input
327
+ */
322
328
  badgesPosition?: BadgesPosition;
323
- /** Threshold behavior mode: 'count' shows count badge, 'partial' shows limited badges + more badge */
329
+ /**
330
+ * How the display switches once `badgesThreshold` is exceeded. Default: `count`.
331
+ *
332
+ * - `count` — collapse all selections into a single count badge
333
+ * - `partial` — keep up to `badgesMaxVisible` badges and add a "+X more" badge
334
+ */
324
335
  badgesThresholdMode?: BadgesThresholdMode;
325
336
  /** Maximum height for dropdown */
326
337
  maxHeight?: string;
@@ -328,15 +339,44 @@ declare interface MultiSelectConfig<T = any> {
328
339
  emptyMessage?: string;
329
340
  /** Message shown while loading async data */
330
341
  loadingMessage?: string;
331
- /** Search input display mode */
342
+ /**
343
+ * How the search input behaves. Default: `normal`.
344
+ *
345
+ * - `normal` — editable search box
346
+ * - `readonly` — visible but not editable (acts as a picker; uses `selectPlaceholder`)
347
+ * - `hidden` — no search box at all
348
+ */
332
349
  searchInputMode?: SearchInputMode;
333
- /** Search behavior mode: 'filter' (hide non-matches) or 'navigate' (jump to matches, keep all visible) */
350
+ /**
351
+ * Search behavior mode. Default: `filter`.
352
+ *
353
+ * - `filter` — hide options that don't match
354
+ * - `navigate` — keep all options visible and jump focus to matches
355
+ */
334
356
  searchMode?: SearchMode;
335
- /** Layout mode for action buttons: 'nowrap' (default) or 'wrap' for multi-row */
357
+ /**
358
+ * Layout mode for the action buttons. Default: `nowrap`.
359
+ *
360
+ * - `nowrap` — buttons stay on a single row
361
+ * - `wrap` — buttons wrap onto multiple rows
362
+ */
336
363
  actionsLayout?: ActionsLayout;
337
- /** Where the action-buttons block sits in the dropdown: 'top' (default) or 'bottom' (sticky footer). */
364
+ /**
365
+ * Where the action-buttons block sits in the dropdown. Default: `top`.
366
+ *
367
+ * - `top` — above the options list
368
+ * - `bottom` — sticky footer below the options list
369
+ */
338
370
  actionsPosition?: ActionsPosition;
339
- /** Horizontal arrangement of buttons within a row: 'stretch' (default, full-width), 'left', 'right', 'center', or 'space-between'. */
371
+ /**
372
+ * Horizontal arrangement of buttons within a row. Default: `stretch`.
373
+ *
374
+ * - `stretch` — full-width, evenly divided
375
+ * - `left` — packed to the start
376
+ * - `right` — packed to the end
377
+ * - `center` — centered
378
+ * - `space-between` — spread to the edges with gaps between
379
+ */
340
380
  actionsAlign?: ActionsAlign;
341
381
  /** Auto-switch from badges to count when threshold is exceeded */
342
382
  badgesThreshold?: number | null;
@@ -403,7 +443,12 @@ declare interface MultiSelectConfig<T = any> {
403
443
  getRemoveButtonTooltipCallback?: ((item: T) => string) | null;
404
444
  /** Format string for remove button tooltip text. Use {0} as placeholder for item name. Default: "Remove {0}" */
405
445
  removeButtonTooltipText?: string;
406
- /** Tooltip placement relative to badge */
446
+ /**
447
+ * Tooltip placement relative to the badge (Floating UI `Placement`). Default: `top`.
448
+ *
449
+ * One of: `top`, `top-start`, `top-end`, `bottom`, `bottom-start`, `bottom-end`,
450
+ * `left`, `left-start`, `left-end`, `right`, `right-start`, `right-end`.
451
+ */
407
452
  badgeTooltipPlacement?: Placement;
408
453
  /** Delay before showing tooltip in milliseconds */
409
454
  badgeTooltipDelay?: number;
@@ -413,7 +458,14 @@ declare interface MultiSelectConfig<T = any> {
413
458
  isOptionTooltipsEnabled?: boolean;
414
459
  /** Callback to generate custom tooltip content for a dropdown option. Default: display value, plus subtitle on the next line when present. */
415
460
  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. */
461
+ /**
462
+ * Option tooltip placement (Floating UI `Placement`). Default `top-start`
463
+ * (anchored to the row's start edge, so it doesn't center on a full-width row).
464
+ * Use `left`/`right` (or their start/end variants) for a narrow multiselect.
465
+ *
466
+ * One of: `top`, `top-start`, `top-end`, `bottom`, `bottom-start`, `bottom-end`,
467
+ * `left`, `left-start`, `left-end`, `right`, `right-start`, `right-end`.
468
+ */
417
469
  optionTooltipPlacement?: Placement;
418
470
  /** Delay before showing an option tooltip (ms). Falls back to `badgeTooltipDelay`, then `100`. */
419
471
  optionTooltipDelay?: number;
@@ -427,243 +479,40 @@ declare interface MultiSelectConfig<T = any> {
427
479
  hostElement?: HTMLElement;
428
480
  }
429
481
 
430
- export declare class MultiSelectElement<T = any> extends BaseElement {
482
+ export declare class MultiSelectElement<T = any> extends BlissElement<MultiSelectEvents> {
483
+ #private;
431
484
  static formAssociated: boolean;
432
- private picker?;
433
- private containerElement?;
434
- private shadow;
435
- private internals?;
436
- private _options?;
437
- private _hasDeclarativeOptions;
438
- private _valueMember?;
439
- private _getValueCallback?;
440
- private _displayValueMember?;
441
- private _getDisplayValueCallback?;
442
- private _getBadgeDisplayCallback?;
443
- private _getBadgeClassCallback?;
444
- private _customStylesCallback?;
445
- private _searchValueMember?;
446
- private _getSearchValueCallback?;
447
- private _iconMember?;
448
- private _getIconCallback?;
449
- private _subtitleMember?;
450
- private _getSubtitleCallback?;
451
- private _getFullTitleCallback?;
452
- private _groupMember?;
453
- private _getGroupCallback?;
454
- private _renderGroupLabelContentCallback?;
455
- private _disabledMember?;
456
- private _getDisabledCallback?;
457
- private _getPathCallback?;
458
- private _isTreeEnabled?;
459
- private _getIsSelectableCallback?;
460
- private _getValueFormatCallback?;
461
- private _getBadgeTooltipCallback?;
462
- private _getOptionTooltipCallback?;
463
- private _getRemoveButtonTooltipCallback?;
464
- private _renderOptionContentCallback?;
465
- private _renderBadgeContentCallback?;
466
- private _renderSelectedItemContentCallback?;
467
- private _getSelectedItemClassCallback?;
468
- private _renderSelectedContentCallback?;
469
- private _getCounterCallback?;
470
- private _actionButtons?;
471
- private _batchDepth;
472
- private _batchPartial;
473
- private _batchNeedsReinit;
474
- private _beforeSearchCallback?;
475
- private _beforeSelectCallback?;
476
- private _beforeDeselectCallback?;
477
- private _searchCallback?;
478
- private _addNewCallback?;
479
- private _onSelect?;
480
- private _onDeselect?;
481
- private _onChange?;
482
- static get observedAttributes(): string[];
485
+ protected static inputs: readonly InputDef<unknown>[];
486
+ protected static events: readonly [{
487
+ readonly name: "select";
488
+ readonly description: "An option was selected. `detail.option` is the selected option; `detail.selectedOptions`/`detail.selectedValues` are the full selection.";
489
+ }, {
490
+ readonly name: "deselect";
491
+ readonly description: "An option was removed from the selection. `detail.option` is that option.";
492
+ }, {
493
+ readonly name: "change";
494
+ readonly description: "The selection changed. `detail.selectedOptions`/`detail.selectedValues` are the full selection.";
495
+ }];
496
+ onSelect: ((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null;
497
+ onDeselect: ((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null;
498
+ onChange: ((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null;
483
499
  constructor();
484
500
  /**
485
501
  * Called by the browser when the surrounding <form> is reset. Clears the
486
- * picker's selection so the multiselect actually participates in the
487
- * standard reset lifecycle. (Before form-association, reset was a no-op
488
- * because the hidden inputs were re-stamped from internal state on every
489
- * render.)
502
+ * picker's selection so the control participates in the standard reset.
490
503
  */
491
504
  formResetCallback(): void;
492
- connectedCallback(): void;
493
- disconnectedCallback(): void;
494
- attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
495
- /**
496
- * Set several attributes in one in-place update a single re-render instead of one per
497
- * attribute (and a single reinit at most if any change is structural). Keys are attribute
498
- * names in kebab-case, exactly as `setAttribute`. A value of `null`/`undefined`/`false`
499
- * removes the attribute; `true` sets it to an empty string; anything else is stringified.
500
- *
501
- * @example
502
- * el.setAttributes({
503
- * 'search-placeholder': t('search'),
504
- * 'select-placeholder': t('pick'),
505
- * 'no-data-placeholder': t('noData'),
506
- * });
507
- */
508
- setAttributes(attrs: Record<string, string | number | boolean | null | undefined>): void;
509
- private render;
510
- private renderDebugInfo;
511
- private updateDebugInfo;
512
- /**
513
- * Parse declarative <option> and <optgroup> elements from Light DOM
514
- * Returns array of options in the format expected by the picker
515
- */
516
- private parseDeclarativeOptions;
517
- private _declarativeSelectedValues?;
518
- /** Parse all observed attributes via ATTRIBUTE_TABLE into a partial config object. */
519
- private parseAttributesFromTable;
520
- private initializePicker;
521
- private reinitialize;
522
- /**
523
- * Apply a partial config update to the live picker. Falls back to a full reinit if the
524
- * picker can't apply the change in place (e.g. adding/removing the `searchHint` element).
525
- * No-op if the picker hasn't been initialized yet — the next `initializePicker` will pick
526
- * up the new programmatic state.
527
- */
528
- private updatePicker;
529
- /** Normalize the picker's getValue() return into the array form expected by event detail. */
530
- private collectSelectedValues;
531
- get options(): T[] | undefined;
532
- set options(value: T[] | undefined);
533
- set valueMember(value: string | null);
534
- get valueMember(): string | null;
535
- set displayValueMember(value: string | null);
536
- get displayValueMember(): string | null;
537
- set searchValueMember(value: string | null);
538
- get searchValueMember(): string | null;
539
- set iconMember(value: string | null);
540
- get iconMember(): string | null;
541
- set subtitleMember(value: string | null);
542
- get subtitleMember(): string | null;
543
- set fullTitleMember(value: string | null);
544
- get fullTitleMember(): string | null;
545
- set groupMember(value: string | null);
546
- get groupMember(): string | null;
547
- set disabledMember(value: string | null);
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;
565
- set getValueCallback(callback: ((item: T) => string | number) | undefined);
566
- get getValueCallback(): ((item: T) => string | number) | undefined;
567
- set getDisplayValueCallback(callback: ((item: T) => string) | undefined);
568
- get getDisplayValueCallback(): ((item: T) => string) | undefined;
569
- set getBadgeDisplayCallback(callback: ((item: T) => string) | undefined);
570
- get getBadgeDisplayCallback(): ((item: T) => string) | undefined;
571
- set getBadgeClassCallback(callback: ((item: T) => string | string[]) | undefined);
572
- get getBadgeClassCallback(): ((item: T) => string | string[]) | undefined;
573
- set customStylesCallback(value: (() => string) | undefined);
574
- get customStylesCallback(): (() => string) | undefined;
575
- set getSearchValueCallback(callback: ((item: T) => string) | undefined);
576
- get getSearchValueCallback(): ((item: T) => string) | undefined;
577
- set getIconCallback(callback: ((item: T) => string) | undefined);
578
- get getIconCallback(): ((item: T) => string) | undefined;
579
- set getSubtitleCallback(callback: ((item: T) => string) | undefined);
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;
584
- set getGroupCallback(callback: ((item: T) => string) | undefined);
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;
599
- set renderGroupLabelContentCallback(callback: ((groupName: string) => string | HTMLElement) | undefined);
600
- get renderGroupLabelContentCallback(): ((groupName: string) => string | HTMLElement) | undefined;
601
- set getDisabledCallback(callback: ((item: T) => boolean) | undefined);
602
- get getDisabledCallback(): ((item: T) => boolean) | undefined;
603
- set renderOptionContentCallback(callback: ((item: T, context: OptionContentRenderContext) => string | HTMLElement) | undefined);
604
- get renderOptionContentCallback(): ((item: T, context: OptionContentRenderContext) => string | HTMLElement) | undefined;
605
- set renderBadgeContentCallback(callback: ((item: T, context: BadgeContentRenderContext) => string | HTMLElement) | undefined);
606
- get renderBadgeContentCallback(): ((item: T, context: BadgeContentRenderContext) => string | HTMLElement) | undefined;
607
- set renderSelectedItemContentCallback(callback: ((item: T) => string | HTMLElement) | undefined);
608
- get renderSelectedItemContentCallback(): ((item: T) => string | HTMLElement) | undefined;
609
- set getSelectedItemClassCallback(callback: ((item: T) => string | string[]) | undefined);
610
- get getSelectedItemClassCallback(): ((item: T) => string | string[]) | undefined;
611
- set renderSelectedContentCallback(callback: ((item: T) => string) | undefined);
612
- get renderSelectedContentCallback(): ((item: T) => string) | undefined;
613
- set name(value: string | null);
505
+ /** Structural change (or first connect): mirror CSS vars, then (re)build the picker. */
506
+ protected reinit(): void;
507
+ /** Cosmetic change: mirror CSS vars / custom styles / debug, patch the picker in place. */
508
+ protected update(partial: Record<string, unknown>): void;
509
+ /** Activate: ensure the picker exists (a DOM move destroyed it in disconnect()). */
510
+ protected connect(): void;
511
+ /** Deactivate: tear the picker down (rebuilt on the next connect). */
512
+ protected disconnect(): void;
513
+ /** Form field name (mirrors the `name` attribute → `formFieldId`). */
614
514
  get name(): string | null;
615
- set valueFormat(value: 'json' | 'csv' | 'array' | null);
616
- get valueFormat(): string | null;
617
- set getValueFormatCallback(callback: ((values: (string | number)[]) => string) | undefined);
618
- get getValueFormatCallback(): ((values: (string | number)[]) => string) | undefined;
619
- set thresholdMode(value: 'count' | 'partial' | null);
620
- get thresholdMode(): string | null;
621
- set badgesMaxVisible(value: number | null);
622
- get badgesMaxVisible(): number | null;
623
- set checkboxAlign(value: 'top' | 'center' | 'bottom' | null);
624
- get checkboxAlign(): string | null;
625
- set enableBadgeTooltips(value: boolean);
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;
639
- set badgeTooltipPlacement(value: string | null);
640
- get badgeTooltipPlacement(): string | null;
641
- set getBadgeTooltipCallback(callback: ((item: T) => string | HTMLElement) | undefined);
642
- get getBadgeTooltipCallback(): ((item: T) => string | HTMLElement) | undefined;
643
- set getRemoveButtonTooltipCallback(callback: ((item: T) => string) | undefined);
644
- get getRemoveButtonTooltipCallback(): ((item: T) => string) | undefined;
645
- set removeButtonTooltipText(value: string | null);
646
- get removeButtonTooltipText(): string | null;
647
- set getCounterCallback(callback: ((count: number, moreCount?: number) => string) | undefined);
648
- get getCounterCallback(): ((count: number, moreCount?: number) => string) | undefined;
649
- get beforeSearchCallback(): ((searchTerm: string) => string | null) | undefined;
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);
655
- get searchCallback(): ((searchTerm: string, signal?: AbortSignal) => Promise<T[]>) | undefined;
656
- set searchCallback(callback: ((searchTerm: string, signal?: AbortSignal) => Promise<T[]>) | undefined);
657
- get addNewCallback(): ((value: string) => T | Promise<T>) | undefined;
658
- set addNewCallback(callback: ((value: string) => T | Promise<T>) | undefined);
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);
665
- get actionButtons(): any[] | undefined;
666
- set actionButtons(value: any[] | undefined);
515
+ set name(value: string | null);
667
516
  get selectedValue(): string | number | (string | number)[] | null;
668
517
  get selectedItem(): T | null;
669
518
  getSelected(): T[];
@@ -687,6 +536,12 @@ export declare interface MultiSelectEventDetail<T = any> {
687
536
  option?: T;
688
537
  }
689
538
 
539
+ declare type MultiSelectEvents = {
540
+ select: MultiSelectEventDetail;
541
+ deselect: MultiSelectEventDetail;
542
+ change: MultiSelectEventDetail;
543
+ };
544
+
690
545
  /**
691
546
  * Legacy interface for backward reference
692
547
  * Note: New code should use generic types with member/callback properties
@@ -745,6 +600,61 @@ declare interface OptionContentRenderContext {
745
600
  isMatched: boolean;
746
601
  /** Whether the option is disabled */
747
602
  isDisabled: boolean;
603
+ /** True when this row is a tree node (path-member / tree mode). Absent/false for flat options. */
604
+ isTreeNode?: boolean;
605
+ /** Tree only: the node has children (a branch). */
606
+ isBranch?: boolean;
607
+ /** Tree only: the node has no children (a leaf). */
608
+ isLeaf?: boolean;
609
+ /** Tree only: number of direct children (0 for a leaf). */
610
+ childCount?: number;
611
+ /** Tree only: 1-based depth level as derived from the path (top level = 1). */
612
+ level?: number;
613
+ /** Tree only: 0-based indentation depth (`level - 1`), matching `--ms-tree-depth`. */
614
+ depth?: number;
615
+ /** Tree only: the node's materialized path (e.g. "1.1.2"). */
616
+ path?: string;
617
+ /** Tree only: the node is selectable (branches marked non-selectable are `false`). */
618
+ isSelectable?: boolean;
619
+ /** Tree only: cascade tristate — a partially-checked branch (some but not all descendants). */
620
+ isIndeterminate?: boolean;
621
+ }
622
+
623
+ /**
624
+ * `data-options` payload parsers. The `data-options-format` attribute selects
625
+ * one; each turns the raw attribute string into an options array the picker
626
+ * understands. Pure + total (never throws) so they unit-test in isolation and a
627
+ * malformed payload degrades to `[]` with a describable error rather than
628
+ * breaking reinit.
629
+ */
630
+ export declare const OPTIONS_FORMATS: readonly ["json", "csv", "plain"];
631
+
632
+ export declare type OptionsFormat = (typeof OPTIONS_FORMATS)[number];
633
+
634
+ export declare interface ParsedOptions {
635
+ /** Parsed options: objects for `json`/`csv`, `[value, label]` tuples for `plain`. */
636
+ options: unknown[];
637
+ /** A human-readable reason when the payload was malformed (`options` is then `[]`). */
638
+ error?: string;
639
+ }
640
+
641
+ /**
642
+ * Parse a `data-options` payload per `format`:
643
+ * - `json` — a JSON array of option objects or `[value, label]` tuples.
644
+ * (`splitter`/`rowSplitter` do not apply.)
645
+ * - `csv` — rows split on `rowSplitter`, cells on `splitter`; the first row is a
646
+ * header and each later row becomes an object keyed by the header cells
647
+ * (map columns via `*-member`). RFC-4180-ish quoting on the cell splitter.
648
+ * - `plain` — bare values split on `splitter` and `rowSplitter` -> `[value, label]`
649
+ * tuples (value === label), so it renders with no member config.
650
+ */
651
+ export declare function parseOptionsData(raw: string | null | undefined, format: OptionsFormat, opts?: ParseOptionsOptions): ParsedOptions;
652
+
653
+ declare interface ParseOptionsOptions {
654
+ /** Field/cell delimiter for `csv` and `plain` (default `,`). Escapes `\t \n \r \\` are honoured. */
655
+ splitter?: string;
656
+ /** Row/record delimiter for `csv` and `plain` (default newline). Escapes honoured. */
657
+ rowSplitter?: string;
748
658
  }
749
659
 
750
660
  /**
@@ -760,20 +670,16 @@ export declare type SearchInputMode = 'normal' | 'readonly' | 'hidden';
760
670
  export declare type SearchMode = 'filter' | 'navigate';
761
671
 
762
672
  /**
763
- * Set log level for a specific category. Accepts either the full prefixed name
764
- * (e.g. `MULTISELECT:UI`) or the bare suffix (`UI`) for convenience.
765
- * @param category Category logger name; bare names (UI/DATA/INIT/INTERACTION) are normalized to the prefixed form.
766
- * @param level Log level ('trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent')
673
+ * Set the level of one category. Accepts the full prefixed name
674
+ * (`MULTISELECT:UI`) or the bare suffix (`UI`) both normalize to the category
675
+ * key the core bundle expects.
767
676
  */
768
- export declare function setCategoryLevel(category: string, level: string): void;
677
+ export declare function setCategoryLevel(category: string, level: LogLevelDesc): void;
769
678
 
770
- /**
771
- * Set log level for all loggers
772
- * @param level Log level to set ('trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent')
773
- */
774
- export declare function setLogLevel(level: string): void;
679
+ /** Set the same level on every category. */
680
+ export declare function setLogLevel(level: LogLevelDesc): void;
775
681
 
776
- export declare const uiLogger: any;
682
+ export declare const uiLogger: Logger;
777
683
 
778
684
  /**
779
685
  * Value format for serialization (forms and callbacks)
@@ -811,6 +717,7 @@ export declare class WebMultiSelect<T = any> {
811
717
  private hintCleanup;
812
718
  private selectedPopoverCleanup;
813
719
  private tooltips;
720
+ private readonly onDropdownScroll;
814
721
  private virtualScroll;
815
722
  private optionsContainer;
816
723
  private selectedPopoverVirtualScroll;
@@ -894,6 +801,17 @@ export declare class WebMultiSelect<T = any> {
894
801
  * policy-projected shape (e.g. a full subtree rolls up to one value).
895
802
  */
896
803
  private commitCascadeAtoms;
804
+ /**
805
+ * The "meaningful selection" list used by the counter chip — the rolled-up
806
+ * minimal cover, regardless of the active emit policy. In cascade mode
807
+ * `leaves`/`all` emit many values for a single branch pick, which made the
808
+ * counter read e.g. `[5]` for what a person experiences as two selections.
809
+ * The counter should count the branches actually chosen, and stay stable when
810
+ * the policy knob flips. Outside cascade this is just the selected options.
811
+ */
812
+ private counterSelection;
813
+ /** Native `title` for the counter chip: the picked items, capped so it can't grow unbounded. */
814
+ private buildCounterTooltip;
897
815
  /**
898
816
  * Derive `treeNodes` + `filteredOptions` from the full tree, applying the
899
817
  * current search term. Matching nodes keep all their ancestors visible so
@@ -1047,17 +965,14 @@ export declare class WebMultiSelect<T = any> {
1047
965
  */
1048
966
  private anchorFloatingPanel;
1049
967
  /**
1050
- * Sanity-check that the browser placed the panel where we told it to. With `position: fixed`
1051
- * and no transformed/perspective/filter ancestor, `left: ${x}px` must render at viewport-x = x.
1052
- * If the rendered position drifts, the consumer has an ancestor that establishes a fixed
1053
- * containing block but isn't on our reliable-anchors list (likely `contain: paint|layout|strict`
1054
- * or `container-type` which the spec says creates a CB but the browser's actual behavior
1055
- * varies across shadow-DOM scenarios). We can't fix it from inside the library, but we can
1056
- * surface a clear warning so the developer knows where to look.
1057
- *
1058
- * Fires at most once per multiselect instance to avoid flooding the console during autoUpdate.
968
+ * Surface a multiselect-branded, once-per-instance warning when core's drift check
969
+ * (`anchor`'s `onDrift`) reports the panel didn't land where it was positioned. The
970
+ * consumer has an ancestor that establishes a fixed containing block but isn't on the
971
+ * reliable-anchors list (likely `contain: paint|layout|strict` or `container-type`).
972
+ * We can't fix it from inside the library, but we point at the likely culprit. Core
973
+ * owns the measurement + culprit-finding + CB-CSS diagnostic (`detectFixedDrift`).
1059
974
  */
1060
- private verifyPanelLanded;
975
+ private warnDrift;
1061
976
  private positionDropdown;
1062
977
  private positionHint;
1063
978
  private parseInitialSelection;
@@ -1137,6 +1052,13 @@ export declare class WebMultiSelect<T = any> {
1137
1052
  * `filteredOptions`, the same global index `renderOption` was given.
1138
1053
  */
1139
1054
  private attachOptionTooltips;
1055
+ /**
1056
+ * Hide (don't destroy) every currently-shown option tooltip immediately,
1057
+ * ignoring the hide delay. Wired to dropdown scroll so a tooltip can't trail
1058
+ * its recycling/scrolling anchor row. Handles stay in the map; a fresh hover
1059
+ * re-shows them.
1060
+ */
1061
+ private hideOptionTooltips;
1140
1062
  /**
1141
1063
  * Destroy only the option tooltips (prefixed `option-`). Called before re-rendering or
1142
1064
  * recycling the options list so per-option tooltip state doesn't leak.