@keenmate/web-multiselect 2.0.1 → 2.2.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/README.md +15 -41
- package/component-variables.manifest.json +2 -1
- package/custom-elements.json +391 -28
- package/dist/index.d.ts +197 -14
- package/dist/multiselect.js +1444 -1209
- package/dist/multiselect.umd.js +12 -12
- package/dist/style.css +1 -1
- package/docs/examples.md +69 -0
- package/docs/usage.md +4 -0
- package/package.json +1 -1
- package/src/css/base.css +10 -0
- package/src/css/controls.css +6 -3
- package/src/css/options.css +55 -7
- package/src/css/variables.css +7 -0
- package/vscode.css-custom-data.json +5 -0
- package/vscode.html-custom-data.json +28 -2
- package/web-types.json +90 -11
package/dist/index.d.ts
CHANGED
|
@@ -72,7 +72,7 @@ declare type ActionsPosition = 'top' | 'bottom';
|
|
|
72
72
|
/**
|
|
73
73
|
* Context provided to renderBadgeContentCallback
|
|
74
74
|
*/
|
|
75
|
-
declare interface BadgeContentRenderContext extends PresentationContext {
|
|
75
|
+
export declare interface BadgeContentRenderContext extends PresentationContext {
|
|
76
76
|
/** Current badges display mode */
|
|
77
77
|
displayMode: BadgesDisplayMode;
|
|
78
78
|
/** Whether the badge is being rendered in the selected items popover */
|
|
@@ -114,6 +114,35 @@ export { EnvironmentSnapshot }
|
|
|
114
114
|
|
|
115
115
|
export { getEnvironment }
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Context handed to `renderGroupLabelContentCallback` as its second argument, so a custom group
|
|
119
|
+
* header can reflect the selection — e.g. render a "3 / 8" count next to the title. The fields are
|
|
120
|
+
* populated for every group header; the selection fields are meaningful mainly under
|
|
121
|
+
* `groupSelectMode: 'cascade'` (a flat multi-select grouped list). Under the default rendering
|
|
122
|
+
* (no callback) the component draws the count itself; with a callback, YOU own the content and can
|
|
123
|
+
* render the count however you like from these fields.
|
|
124
|
+
*
|
|
125
|
+
* Like {@link OptionContentRenderContext} / {@link BadgeContentRenderContext}, it extends the
|
|
126
|
+
* shared {@link PresentationContext} (`presentation` / `isFullscreen` / `isModal`), so a group
|
|
127
|
+
* header can also render leaner in the phone fullscreen overlay.
|
|
128
|
+
*/
|
|
129
|
+
export declare interface GroupLabelRenderContext<T = any> extends PresentationContext {
|
|
130
|
+
/** The group name (identical to the callback's first argument). */
|
|
131
|
+
groupName: string;
|
|
132
|
+
/** The group's currently-visible (filtered) members, in render order. */
|
|
133
|
+
members: T[];
|
|
134
|
+
/** The subset of `members` that are currently selected (includes disabled-but-selected). */
|
|
135
|
+
selectedMembers: T[];
|
|
136
|
+
/** `selectedMembers.length` — the number to show "behind the group title". */
|
|
137
|
+
selectedCount: number;
|
|
138
|
+
/** `members.length` — total visible members in the group. */
|
|
139
|
+
memberCount: number;
|
|
140
|
+
/** Visible, non-disabled members — the cascade "select-all" denominator. */
|
|
141
|
+
selectableCount: number;
|
|
142
|
+
/** Tristate roll-up of the group under cascade selection. */
|
|
143
|
+
checkState: 'checked' | 'indeterminate' | 'unchecked';
|
|
144
|
+
}
|
|
145
|
+
|
|
117
146
|
export declare const initLogger: Logger;
|
|
118
147
|
|
|
119
148
|
export declare const interactionLogger: Logger;
|
|
@@ -191,6 +220,25 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
191
220
|
getDisplayValueCallback?: (item: T) => string;
|
|
192
221
|
/** Callback to customize badge display text (defaults to display value if not provided) */
|
|
193
222
|
getBadgeDisplayCallback?: (item: T) => string;
|
|
223
|
+
/**
|
|
224
|
+
* Order of the CURRENTLY-SELECTED items *where they are displayed* — badges, partial mode
|
|
225
|
+
* (i.e. which items sit behind the "+N more" badge), and the selected-items popover. This is a
|
|
226
|
+
* display concern only: `getValue()`, the form output, and `getSelected()` always keep
|
|
227
|
+
* as-selected (insertion) order regardless of this setting, and the options dropdown is never
|
|
228
|
+
* reordered.
|
|
229
|
+
* - `as-selected` (default) — the order items were picked.
|
|
230
|
+
* - `label-asc` / `label-desc` — by the badge label, A→Z / Z→A (locale-aware).
|
|
231
|
+
* - `member` — by the `selectedOrderMember` property (or `getSelectedOrderCallback`); numeric
|
|
232
|
+
* keys sort numerically, everything else with a locale string compare.
|
|
233
|
+
* - `custom` — delegate to `selectedOrderCompareCallback`.
|
|
234
|
+
*/
|
|
235
|
+
selectedOrder?: 'as-selected' | 'label-asc' | 'label-desc' | 'member' | 'custom';
|
|
236
|
+
/** Property name used as the sort key when `selectedOrder === 'member'` (selected-items display only). */
|
|
237
|
+
selectedOrderMember?: string;
|
|
238
|
+
/** Extract the sort key when `selectedOrder === 'member'` (overrides `selectedOrderMember`). */
|
|
239
|
+
getSelectedOrderCallback?: (item: T) => string | number;
|
|
240
|
+
/** Comparator used when `selectedOrder === 'custom'`; standard `(a,b) => number` contract. */
|
|
241
|
+
selectedOrderCompareCallback?: (a: T, b: T) => number;
|
|
194
242
|
/**
|
|
195
243
|
* Member property name for a "full title" — a fully-qualified label that ships with the
|
|
196
244
|
* data (e.g. a breadcrumb like "Fruit / Pome fruit / Apple"). It is never computed by the
|
|
@@ -250,9 +298,10 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
250
298
|
*/
|
|
251
299
|
getIsSelectableCallback?: (node: LTreeNode<T>) => boolean;
|
|
252
300
|
/**
|
|
253
|
-
* Tree checkbox interaction. `
|
|
254
|
-
*
|
|
255
|
-
*
|
|
301
|
+
* Tree checkbox interaction. `cascade` (default) checks a node's whole subtree
|
|
302
|
+
* and shows a tristate (checked / indeterminate / unchecked) box on branches —
|
|
303
|
+
* what most tree-select UIs do. `independent` toggles only the clicked node.
|
|
304
|
+
* Tree + multiple only (no subtree to cascade otherwise). Unset → cascade.
|
|
256
305
|
*/
|
|
257
306
|
checkboxMode?: 'independent' | 'cascade';
|
|
258
307
|
/**
|
|
@@ -270,8 +319,23 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
270
319
|
groupMember?: string;
|
|
271
320
|
/** Callback to extract group from item */
|
|
272
321
|
getGroupCallback?: (item: T) => string;
|
|
273
|
-
/**
|
|
274
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Callback to customize group label content (can return HTML). Receives the group name and a
|
|
324
|
+
* {@link GroupLabelRenderContext} with the group's members and selection (e.g. `selectedCount`),
|
|
325
|
+
* so a custom header can show a per-group count. The second argument is additive — existing
|
|
326
|
+
* one-argument callbacks keep working.
|
|
327
|
+
*/
|
|
328
|
+
renderGroupLabelContentCallback?: (groupName: string, context: GroupLabelRenderContext<T>) => string | HTMLElement;
|
|
329
|
+
/**
|
|
330
|
+
* Group-header selection in a flat (non-tree) grouped, multi-select list.
|
|
331
|
+
* - `none` (default) — group headers are inert labels.
|
|
332
|
+
* - `cascade` — each header shows a **tristate** checkbox that checks/unchecks
|
|
333
|
+
* all of that group's currently-visible members. The group itself is never a
|
|
334
|
+
* selected value (`getValue()`/badges/form carry member values only); a
|
|
335
|
+
* partially-selected group reads indeterminate. Flat + multiple only — no
|
|
336
|
+
* effect in tree mode (use `checkboxMode`) or single-select.
|
|
337
|
+
*/
|
|
338
|
+
groupSelectMode?: 'none' | 'cascade';
|
|
275
339
|
/** Member property name for disabled state extraction */
|
|
276
340
|
disabledMember?: string;
|
|
277
341
|
/** Callback to extract disabled state from item */
|
|
@@ -291,12 +355,22 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
291
355
|
* selected-items popover keeps using renderSelectedItemContentCallback).
|
|
292
356
|
*/
|
|
293
357
|
renderBadgeCallback?: (item: T, context: BadgeContentRenderContext) => string | HTMLElement | null | undefined;
|
|
294
|
-
/**
|
|
295
|
-
|
|
358
|
+
/**
|
|
359
|
+
* Custom renderer for selected item content in the selected-items popover — return HTML string
|
|
360
|
+
* or HTMLElement. Receives a {@link BadgeContentRenderContext} (2nd arg) since a popover item
|
|
361
|
+
* is rendered through the same badge path: `isInPopover` is `true`, plus the shared
|
|
362
|
+
* presentation fields. The second argument is additive; one-argument callbacks keep working.
|
|
363
|
+
*/
|
|
364
|
+
renderSelectedItemContentCallback?: (item: T, context: BadgeContentRenderContext) => string | HTMLElement;
|
|
296
365
|
/** Callback to add custom CSS classes to selected items in popover - return string or array of class names */
|
|
297
366
|
getSelectedItemClassCallback?: (item: T) => string | string[];
|
|
298
|
-
/**
|
|
299
|
-
|
|
367
|
+
/**
|
|
368
|
+
* Custom renderer for the selected item display in single-select mode — return plain text (it
|
|
369
|
+
* becomes the input value). Receives a {@link SelectedContentRenderContext} (2nd arg) carrying
|
|
370
|
+
* the shared presentation fields. The second argument is additive; one-argument callbacks keep
|
|
371
|
+
* working.
|
|
372
|
+
*/
|
|
373
|
+
renderSelectedContentCallback?: (item: T, context: SelectedContentRenderContext) => string;
|
|
300
374
|
/** HTML form field ID/name for hidden input */
|
|
301
375
|
formFieldId?: string;
|
|
302
376
|
/**
|
|
@@ -595,8 +669,22 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
595
669
|
onDeselect?: ((option: T) => void) | null;
|
|
596
670
|
/** Event handler: the selection set changed (fire-and-forget). Mirrors the bubbling `change` CustomEvent on the element. */
|
|
597
671
|
onChange?: ((selectedOptions: T[]) => void) | null;
|
|
598
|
-
/**
|
|
672
|
+
/**
|
|
673
|
+
* Formats the badges-area count/summary text: the `count` mode badge ("N selected") and the
|
|
674
|
+
* partial-mode "+X more" badge (when `moreCount` is provided). NOT the small `[N]` chip — that's
|
|
675
|
+
* {@link getCountLabelCallback}. For i18n/pluralization.
|
|
676
|
+
*/
|
|
599
677
|
getCounterCallback?: ((count: number, moreCount?: number) => string) | null;
|
|
678
|
+
/**
|
|
679
|
+
* Formats the small count CHIP shared by the in-input counter (`show-counter`) and each group
|
|
680
|
+
* header's per-group count. Distinct from {@link getCounterCallback}, which formats the
|
|
681
|
+
* badges-area "N selected" / "+X more" text. Receives `selected` and `total`: for the in-input
|
|
682
|
+
* counter `total` is the whole option list; for a group header it's that group's member count.
|
|
683
|
+
* Return the label as plain text. Default `[selected]` (e.g. `[3]`). Set it to
|
|
684
|
+
* `` (s, t) => `${s}/${t}` `` for an "x / y" style. One callback drives both so they always
|
|
685
|
+
* read the same way.
|
|
686
|
+
*/
|
|
687
|
+
getCountLabelCallback?: ((selected: number, total: number) => string) | null;
|
|
600
688
|
/** Enable tooltips on selected item badges (internal: isBadgeTooltipsEnabled) */
|
|
601
689
|
isBadgeTooltipsEnabled?: boolean;
|
|
602
690
|
/** Callback to generate custom tooltip content for a badge */
|
|
@@ -657,11 +745,15 @@ export declare class MultiSelectElement<T = any> extends BlissElement<MultiSelec
|
|
|
657
745
|
}, {
|
|
658
746
|
readonly name: "add";
|
|
659
747
|
readonly description: "The user chose to create a new option from the typed text (via the \"add new\" prompt or Enter) — requires `allow-add-new`. `detail.value` is the typed text; `detail.option` is the created item when `addNewCallback` produced one.";
|
|
748
|
+
}, {
|
|
749
|
+
readonly name: "ready";
|
|
750
|
+
readonly description: "The picker was built and painted for the first time (once per element lifetime). Fires right after the first build — synchronously during upgrade for a normal element, or when the render gate is released (`el.ready()` / removing `defer`) for a deferred one. No detail.";
|
|
660
751
|
}];
|
|
661
752
|
onSelect: ((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null;
|
|
662
753
|
onDeselect: ((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null;
|
|
663
754
|
onChange: ((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null;
|
|
664
755
|
onAdd: ((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null;
|
|
756
|
+
onReady: ((e: CustomEvent<undefined>) => void) | null;
|
|
665
757
|
constructor();
|
|
666
758
|
/**
|
|
667
759
|
* Called by the browser when the surrounding <form> is reset. Clears the
|
|
@@ -766,6 +858,17 @@ export declare class MultiSelectElement<T = any> extends BlissElement<MultiSelec
|
|
|
766
858
|
get isOpen(): boolean;
|
|
767
859
|
set isOpen(value: boolean);
|
|
768
860
|
destroy(): void;
|
|
861
|
+
/**
|
|
862
|
+
* Release the `defer` render gate: build the picker now (once), with every
|
|
863
|
+
* option, callback and listener wired while deferred already in place. No-op
|
|
864
|
+
* when the element wasn't deferred or is already built. `flush()` first so a
|
|
865
|
+
* synchronous `el.options = …; el.customStylesCallback = …; el.ready()` lands
|
|
866
|
+
* those pending writes in the single build rather than after it. Latched — the
|
|
867
|
+
* gate never re-closes. Fires the `ready` event on the first build.
|
|
868
|
+
*/
|
|
869
|
+
ready(): void;
|
|
870
|
+
/** Whether the picker has been built (the `ready` event has fired). False while a `defer` gate is still held. */
|
|
871
|
+
get isReady(): boolean;
|
|
769
872
|
}
|
|
770
873
|
|
|
771
874
|
/**
|
|
@@ -788,6 +891,7 @@ declare type MultiSelectEvents = {
|
|
|
788
891
|
deselect: MultiSelectEventDetail;
|
|
789
892
|
change: MultiSelectEventDetail;
|
|
790
893
|
add: MultiSelectEventDetail;
|
|
894
|
+
ready: undefined;
|
|
791
895
|
};
|
|
792
896
|
|
|
793
897
|
/**
|
|
@@ -912,7 +1016,7 @@ export { observeViewport }
|
|
|
912
1016
|
* render leaner content in the phone overlay. Reactive: swapping presentation re-renders and
|
|
913
1017
|
* re-invokes the callback with the new value.
|
|
914
1018
|
*/
|
|
915
|
-
declare interface OptionContentRenderContext extends PresentationContext {
|
|
1019
|
+
export declare interface OptionContentRenderContext extends PresentationContext {
|
|
916
1020
|
/** Index of the option in the filtered list */
|
|
917
1021
|
index: number;
|
|
918
1022
|
/** Whether the option is currently selected */
|
|
@@ -998,6 +1102,13 @@ export declare type SearchInputMode = 'normal' | 'readonly' | 'hidden';
|
|
|
998
1102
|
*/
|
|
999
1103
|
export declare type SearchMode = 'filter' | 'navigate';
|
|
1000
1104
|
|
|
1105
|
+
/**
|
|
1106
|
+
* Context handed to `renderSelectedContentCallback` (single-select selected-value display). Carries
|
|
1107
|
+
* only the shared {@link PresentationContext} fields (`presentation` / `isFullscreen` / `isModal`),
|
|
1108
|
+
* so the single-select label can render leaner in the phone fullscreen overlay.
|
|
1109
|
+
*/
|
|
1110
|
+
export declare type SelectedContentRenderContext = PresentationContext;
|
|
1111
|
+
|
|
1001
1112
|
/**
|
|
1002
1113
|
* Set the level of one category. Accepts the full prefixed name
|
|
1003
1114
|
* (`MULTISELECT:UI`) or the bare suffix (`UI`) — both normalize to the category
|
|
@@ -1120,6 +1231,14 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1120
1231
|
*/
|
|
1121
1232
|
private getItemFullTitle;
|
|
1122
1233
|
private getItemSearchValue;
|
|
1234
|
+
/** Sort key for `selectedOrder === 'member'` (member/callback pattern). */
|
|
1235
|
+
private getItemSortKey;
|
|
1236
|
+
/**
|
|
1237
|
+
* Selected options in the order they should be DISPLAYED (badges / partial "+N more" / popover).
|
|
1238
|
+
* Never mutates state — always returns a fresh array. Display concern only: getValue()/form
|
|
1239
|
+
* output/getSelected() keep as-selected (insertion) order. See `selectedOrder`.
|
|
1240
|
+
*/
|
|
1241
|
+
private getOrderedSelectedOptions;
|
|
1123
1242
|
private getItemIcon;
|
|
1124
1243
|
private getItemSubtitle;
|
|
1125
1244
|
private getItemGroup;
|
|
@@ -1142,8 +1261,10 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1142
1261
|
private buildTree;
|
|
1143
1262
|
/**
|
|
1144
1263
|
* Whether cascade checkbox mode is active: a multi-select tree with
|
|
1145
|
-
* `checkbox-mode
|
|
1146
|
-
* and branches show a tristate box.
|
|
1264
|
+
* `checkbox-mode` NOT set to `independent`. Checking a node then toggles its
|
|
1265
|
+
* whole subtree and branches show a tristate box. Cascade is the DEFAULT
|
|
1266
|
+
* (unset → cascade); opt out per-instance with `checkbox-mode="independent"`.
|
|
1267
|
+
* Only ever active in tree + multiple — no subtree to cascade otherwise.
|
|
1147
1268
|
*/
|
|
1148
1269
|
private isCascadeMode;
|
|
1149
1270
|
private cascadePolicy;
|
|
@@ -1234,6 +1355,46 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1234
1355
|
* Check if any options have groups
|
|
1235
1356
|
*/
|
|
1236
1357
|
private hasGroups;
|
|
1358
|
+
/**
|
|
1359
|
+
* Whether the flat-group cascade checkbox is active: a multi-select, grouped,
|
|
1360
|
+
* non-tree list with `group-select-mode="cascade"`. When on, each group header
|
|
1361
|
+
* gets a tristate checkbox that toggles all of that group's visible members.
|
|
1362
|
+
* Tree mode has its own `checkbox-mode` cascade, so this stays flat-only.
|
|
1363
|
+
*/
|
|
1364
|
+
private isGroupCascadeActive;
|
|
1365
|
+
/**
|
|
1366
|
+
* Tristate check-state of a group from its members: `checked` if every
|
|
1367
|
+
* non-disabled member is selected, `unchecked` if none are, else
|
|
1368
|
+
* `indeterminate`. Disabled members are excluded from the denominator so a
|
|
1369
|
+
* group with a stuck-disabled member can still read fully checked. An empty
|
|
1370
|
+
* (or all-disabled) group reads `unchecked`.
|
|
1371
|
+
*/
|
|
1372
|
+
private groupCheckState;
|
|
1373
|
+
/**
|
|
1374
|
+
* Selection roll-up for a flat group's (visible) members: which are selected, how many, and
|
|
1375
|
+
* the tristate check-state. `selectedCount` counts every selected member (including a
|
|
1376
|
+
* disabled-but-selected one) — it's the "N behind the group title". `checkState` excludes
|
|
1377
|
+
* disabled members from its denominator (mirrors the select-all), so a group with a stuck
|
|
1378
|
+
* disabled member can still read fully `checked`. Shared by the header count, the tristate
|
|
1379
|
+
* checkbox, and the `renderGroupLabelContentCallback` context.
|
|
1380
|
+
*/
|
|
1381
|
+
private groupSelectionInfo;
|
|
1382
|
+
/**
|
|
1383
|
+
* Formats the small count chip shared by the in-input counter and the per-group header count.
|
|
1384
|
+
* Default `[selected]` (matches the historical in-input `[N]`); a `getCountLabelCallback` can
|
|
1385
|
+
* switch both to e.g. `selected/total`.
|
|
1386
|
+
*/
|
|
1387
|
+
private formatCountLabel;
|
|
1388
|
+
/** Trailing count chip for a group header — any grouped list (rendered only when >0 selected). */
|
|
1389
|
+
private groupCountHtml;
|
|
1390
|
+
/**
|
|
1391
|
+
* Shared markup for a `.ms__checkbox` input — the single source of truth for option rows, tree
|
|
1392
|
+
* nodes, and group headers. Indeterminate is a pure CSS state (the box is `appearance: none`, so
|
|
1393
|
+
* no native `input.indeterminate` is needed — virtual-scroll-safe) plus `aria-checked="mixed"`.
|
|
1394
|
+
*/
|
|
1395
|
+
private checkboxHtml;
|
|
1396
|
+
/** Group-header tristate checkbox (maps the group's roll-up state onto `checkboxHtml`). */
|
|
1397
|
+
private groupCheckboxHtml;
|
|
1237
1398
|
private renderDropdown;
|
|
1238
1399
|
/**
|
|
1239
1400
|
* Round the OUTER corners of the row at the very top and the row at the very
|
|
@@ -1463,6 +1624,16 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1463
1624
|
private deselectOption;
|
|
1464
1625
|
private selectAll;
|
|
1465
1626
|
clearAll(): void;
|
|
1627
|
+
/**
|
|
1628
|
+
* Flat-group cascade toggle: check or uncheck every (visible) member of a group
|
|
1629
|
+
* in one shot. If the group is fully checked → deselect all its members; else →
|
|
1630
|
+
* select all its non-disabled members. Operates on the currently-filtered
|
|
1631
|
+
* members (same scope as Select-All) and, like Select-All / Clear-All,
|
|
1632
|
+
* batch-mutates then fires a single `commit` — so one render and one `change`
|
|
1633
|
+
* event, and it deliberately bypasses the per-item beforeSelect/beforeDeselect
|
|
1634
|
+
* veto. The group name itself is never added to the selection.
|
|
1635
|
+
*/
|
|
1636
|
+
private toggleGroup;
|
|
1466
1637
|
/**
|
|
1467
1638
|
* Inline clear (✕) handler: wipe the whole selection and any search text, then
|
|
1468
1639
|
* restore focus to the input. clearAll() → commit() → renderBadges() already
|
|
@@ -1481,6 +1652,18 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1481
1652
|
* `onChange` fires once if anything actually changed.
|
|
1482
1653
|
*/
|
|
1483
1654
|
private commit;
|
|
1655
|
+
/**
|
|
1656
|
+
* Shield the trailing document `click` for one tick. A consumer that drives the
|
|
1657
|
+
* dropdown from their OWN button's click handler (`el.open()` / `el.toggle()`, or a
|
|
1658
|
+
* scrollTo* command re-driving the already-open panel) would otherwise have that
|
|
1659
|
+
* same click bubble to our document-level outside-click listener and immediately
|
|
1660
|
+
* close it. Centralizing it here means every entry point — open(), the internal
|
|
1661
|
+
* pointer path, and the public scrollTo* API — is covered. Cleared next tick, so a
|
|
1662
|
+
* genuine later outside-click still closes as normal. Harmless for non-click
|
|
1663
|
+
* callers (typing, programmatic-on-load, server-driven): no trailing click arrives
|
|
1664
|
+
* before it clears.
|
|
1665
|
+
*/
|
|
1666
|
+
private armClickGuard;
|
|
1484
1667
|
/** Open the dropdown (no-op if already open, or if there is nothing to show). */
|
|
1485
1668
|
open(): void;
|
|
1486
1669
|
/** Close the dropdown (no-op if already closed). */
|