@keenmate/web-multiselect 2.1.0 → 2.2.0-rc02
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 -9
- package/custom-elements.json +335 -26
- package/dist/index.d.ts +192 -14
- package/dist/multiselect.js +1417 -1212
- package/dist/multiselect.umd.js +12 -12
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/css/controls.css +6 -3
- package/src/css/options.css +49 -0
- package/src/css/variables.css +2 -0
- package/vscode.html-custom-data.json +27 -1
- package/web-types.json +68 -10
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
|
|
@@ -204,6 +252,13 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
204
252
|
getBadgeClassCallback?: (item: T) => string | string[];
|
|
205
253
|
/** Callback to inject custom CSS into Shadow DOM - return CSS string for styling custom classes */
|
|
206
254
|
customStylesCallback?: () => string;
|
|
255
|
+
/**
|
|
256
|
+
* Static CSS string injected into the Shadow DOM (attribute alternative to
|
|
257
|
+
* `customStylesCallback`, via the `custom-styles` attribute). The value is a
|
|
258
|
+
* raw stylesheet — selectors and all — dropped verbatim into the same
|
|
259
|
+
* replaceable style slot. `customStylesCallback` wins when both are set.
|
|
260
|
+
*/
|
|
261
|
+
customStyles?: string;
|
|
207
262
|
/** Member property name for search value extraction */
|
|
208
263
|
searchValueMember?: string;
|
|
209
264
|
/** Callback to extract search value from item */
|
|
@@ -250,9 +305,10 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
250
305
|
*/
|
|
251
306
|
getIsSelectableCallback?: (node: LTreeNode<T>) => boolean;
|
|
252
307
|
/**
|
|
253
|
-
* Tree checkbox interaction. `
|
|
254
|
-
*
|
|
255
|
-
*
|
|
308
|
+
* Tree checkbox interaction. `cascade` (default) checks a node's whole subtree
|
|
309
|
+
* and shows a tristate (checked / indeterminate / unchecked) box on branches —
|
|
310
|
+
* what most tree-select UIs do. `independent` toggles only the clicked node.
|
|
311
|
+
* Tree + multiple only (no subtree to cascade otherwise). Unset → cascade.
|
|
256
312
|
*/
|
|
257
313
|
checkboxMode?: 'independent' | 'cascade';
|
|
258
314
|
/**
|
|
@@ -270,8 +326,23 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
270
326
|
groupMember?: string;
|
|
271
327
|
/** Callback to extract group from item */
|
|
272
328
|
getGroupCallback?: (item: T) => string;
|
|
273
|
-
/**
|
|
274
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Callback to customize group label content (can return HTML). Receives the group name and a
|
|
331
|
+
* {@link GroupLabelRenderContext} with the group's members and selection (e.g. `selectedCount`),
|
|
332
|
+
* so a custom header can show a per-group count. The second argument is additive — existing
|
|
333
|
+
* one-argument callbacks keep working.
|
|
334
|
+
*/
|
|
335
|
+
renderGroupLabelContentCallback?: (groupName: string, context: GroupLabelRenderContext<T>) => string | HTMLElement;
|
|
336
|
+
/**
|
|
337
|
+
* Group-header selection in a flat (non-tree) grouped, multi-select list.
|
|
338
|
+
* - `none` (default) — group headers are inert labels.
|
|
339
|
+
* - `cascade` — each header shows a **tristate** checkbox that checks/unchecks
|
|
340
|
+
* all of that group's currently-visible members. The group itself is never a
|
|
341
|
+
* selected value (`getValue()`/badges/form carry member values only); a
|
|
342
|
+
* partially-selected group reads indeterminate. Flat + multiple only — no
|
|
343
|
+
* effect in tree mode (use `checkboxMode`) or single-select.
|
|
344
|
+
*/
|
|
345
|
+
groupSelectMode?: 'none' | 'cascade';
|
|
275
346
|
/** Member property name for disabled state extraction */
|
|
276
347
|
disabledMember?: string;
|
|
277
348
|
/** Callback to extract disabled state from item */
|
|
@@ -291,12 +362,22 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
291
362
|
* selected-items popover keeps using renderSelectedItemContentCallback).
|
|
292
363
|
*/
|
|
293
364
|
renderBadgeCallback?: (item: T, context: BadgeContentRenderContext) => string | HTMLElement | null | undefined;
|
|
294
|
-
/**
|
|
295
|
-
|
|
365
|
+
/**
|
|
366
|
+
* Custom renderer for selected item content in the selected-items popover — return HTML string
|
|
367
|
+
* or HTMLElement. Receives a {@link BadgeContentRenderContext} (2nd arg) since a popover item
|
|
368
|
+
* is rendered through the same badge path: `isInPopover` is `true`, plus the shared
|
|
369
|
+
* presentation fields. The second argument is additive; one-argument callbacks keep working.
|
|
370
|
+
*/
|
|
371
|
+
renderSelectedItemContentCallback?: (item: T, context: BadgeContentRenderContext) => string | HTMLElement;
|
|
296
372
|
/** Callback to add custom CSS classes to selected items in popover - return string or array of class names */
|
|
297
373
|
getSelectedItemClassCallback?: (item: T) => string | string[];
|
|
298
|
-
/**
|
|
299
|
-
|
|
374
|
+
/**
|
|
375
|
+
* Custom renderer for the selected item display in single-select mode — return plain text (it
|
|
376
|
+
* becomes the input value). Receives a {@link SelectedContentRenderContext} (2nd arg) carrying
|
|
377
|
+
* the shared presentation fields. The second argument is additive; one-argument callbacks keep
|
|
378
|
+
* working.
|
|
379
|
+
*/
|
|
380
|
+
renderSelectedContentCallback?: (item: T, context: SelectedContentRenderContext) => string;
|
|
300
381
|
/** HTML form field ID/name for hidden input */
|
|
301
382
|
formFieldId?: string;
|
|
302
383
|
/**
|
|
@@ -595,8 +676,22 @@ declare interface MultiSelectConfig<T = any> {
|
|
|
595
676
|
onDeselect?: ((option: T) => void) | null;
|
|
596
677
|
/** Event handler: the selection set changed (fire-and-forget). Mirrors the bubbling `change` CustomEvent on the element. */
|
|
597
678
|
onChange?: ((selectedOptions: T[]) => void) | null;
|
|
598
|
-
/**
|
|
679
|
+
/**
|
|
680
|
+
* Formats the badges-area count/summary text: the `count` mode badge ("N selected") and the
|
|
681
|
+
* partial-mode "+X more" badge (when `moreCount` is provided). NOT the small `[N]` chip — that's
|
|
682
|
+
* {@link getCountLabelCallback}. For i18n/pluralization.
|
|
683
|
+
*/
|
|
599
684
|
getCounterCallback?: ((count: number, moreCount?: number) => string) | null;
|
|
685
|
+
/**
|
|
686
|
+
* Formats the small count CHIP shared by the in-input counter (`show-counter`) and each group
|
|
687
|
+
* header's per-group count. Distinct from {@link getCounterCallback}, which formats the
|
|
688
|
+
* badges-area "N selected" / "+X more" text. Receives `selected` and `total`: for the in-input
|
|
689
|
+
* counter `total` is the whole option list; for a group header it's that group's member count.
|
|
690
|
+
* Return the label as plain text. Default `[selected]` (e.g. `[3]`). Set it to
|
|
691
|
+
* `` (s, t) => `${s}/${t}` `` for an "x / y" style. One callback drives both so they always
|
|
692
|
+
* read the same way.
|
|
693
|
+
*/
|
|
694
|
+
getCountLabelCallback?: ((selected: number, total: number) => string) | null;
|
|
600
695
|
/** Enable tooltips on selected item badges (internal: isBadgeTooltipsEnabled) */
|
|
601
696
|
isBadgeTooltipsEnabled?: boolean;
|
|
602
697
|
/** Callback to generate custom tooltip content for a badge */
|
|
@@ -928,7 +1023,7 @@ export { observeViewport }
|
|
|
928
1023
|
* render leaner content in the phone overlay. Reactive: swapping presentation re-renders and
|
|
929
1024
|
* re-invokes the callback with the new value.
|
|
930
1025
|
*/
|
|
931
|
-
declare interface OptionContentRenderContext extends PresentationContext {
|
|
1026
|
+
export declare interface OptionContentRenderContext extends PresentationContext {
|
|
932
1027
|
/** Index of the option in the filtered list */
|
|
933
1028
|
index: number;
|
|
934
1029
|
/** Whether the option is currently selected */
|
|
@@ -1014,6 +1109,13 @@ export declare type SearchInputMode = 'normal' | 'readonly' | 'hidden';
|
|
|
1014
1109
|
*/
|
|
1015
1110
|
export declare type SearchMode = 'filter' | 'navigate';
|
|
1016
1111
|
|
|
1112
|
+
/**
|
|
1113
|
+
* Context handed to `renderSelectedContentCallback` (single-select selected-value display). Carries
|
|
1114
|
+
* only the shared {@link PresentationContext} fields (`presentation` / `isFullscreen` / `isModal`),
|
|
1115
|
+
* so the single-select label can render leaner in the phone fullscreen overlay.
|
|
1116
|
+
*/
|
|
1117
|
+
export declare type SelectedContentRenderContext = PresentationContext;
|
|
1118
|
+
|
|
1017
1119
|
/**
|
|
1018
1120
|
* Set the level of one category. Accepts the full prefixed name
|
|
1019
1121
|
* (`MULTISELECT:UI`) or the bare suffix (`UI`) — both normalize to the category
|
|
@@ -1136,6 +1238,14 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1136
1238
|
*/
|
|
1137
1239
|
private getItemFullTitle;
|
|
1138
1240
|
private getItemSearchValue;
|
|
1241
|
+
/** Sort key for `selectedOrder === 'member'` (member/callback pattern). */
|
|
1242
|
+
private getItemSortKey;
|
|
1243
|
+
/**
|
|
1244
|
+
* Selected options in the order they should be DISPLAYED (badges / partial "+N more" / popover).
|
|
1245
|
+
* Never mutates state — always returns a fresh array. Display concern only: getValue()/form
|
|
1246
|
+
* output/getSelected() keep as-selected (insertion) order. See `selectedOrder`.
|
|
1247
|
+
*/
|
|
1248
|
+
private getOrderedSelectedOptions;
|
|
1139
1249
|
private getItemIcon;
|
|
1140
1250
|
private getItemSubtitle;
|
|
1141
1251
|
private getItemGroup;
|
|
@@ -1158,8 +1268,10 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1158
1268
|
private buildTree;
|
|
1159
1269
|
/**
|
|
1160
1270
|
* Whether cascade checkbox mode is active: a multi-select tree with
|
|
1161
|
-
* `checkbox-mode
|
|
1162
|
-
* and branches show a tristate box.
|
|
1271
|
+
* `checkbox-mode` NOT set to `independent`. Checking a node then toggles its
|
|
1272
|
+
* whole subtree and branches show a tristate box. Cascade is the DEFAULT
|
|
1273
|
+
* (unset → cascade); opt out per-instance with `checkbox-mode="independent"`.
|
|
1274
|
+
* Only ever active in tree + multiple — no subtree to cascade otherwise.
|
|
1163
1275
|
*/
|
|
1164
1276
|
private isCascadeMode;
|
|
1165
1277
|
private cascadePolicy;
|
|
@@ -1250,6 +1362,46 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1250
1362
|
* Check if any options have groups
|
|
1251
1363
|
*/
|
|
1252
1364
|
private hasGroups;
|
|
1365
|
+
/**
|
|
1366
|
+
* Whether the flat-group cascade checkbox is active: a multi-select, grouped,
|
|
1367
|
+
* non-tree list with `group-select-mode="cascade"`. When on, each group header
|
|
1368
|
+
* gets a tristate checkbox that toggles all of that group's visible members.
|
|
1369
|
+
* Tree mode has its own `checkbox-mode` cascade, so this stays flat-only.
|
|
1370
|
+
*/
|
|
1371
|
+
private isGroupCascadeActive;
|
|
1372
|
+
/**
|
|
1373
|
+
* Tristate check-state of a group from its members: `checked` if every
|
|
1374
|
+
* non-disabled member is selected, `unchecked` if none are, else
|
|
1375
|
+
* `indeterminate`. Disabled members are excluded from the denominator so a
|
|
1376
|
+
* group with a stuck-disabled member can still read fully checked. An empty
|
|
1377
|
+
* (or all-disabled) group reads `unchecked`.
|
|
1378
|
+
*/
|
|
1379
|
+
private groupCheckState;
|
|
1380
|
+
/**
|
|
1381
|
+
* Selection roll-up for a flat group's (visible) members: which are selected, how many, and
|
|
1382
|
+
* the tristate check-state. `selectedCount` counts every selected member (including a
|
|
1383
|
+
* disabled-but-selected one) — it's the "N behind the group title". `checkState` excludes
|
|
1384
|
+
* disabled members from its denominator (mirrors the select-all), so a group with a stuck
|
|
1385
|
+
* disabled member can still read fully `checked`. Shared by the header count, the tristate
|
|
1386
|
+
* checkbox, and the `renderGroupLabelContentCallback` context.
|
|
1387
|
+
*/
|
|
1388
|
+
private groupSelectionInfo;
|
|
1389
|
+
/**
|
|
1390
|
+
* Formats the small count chip shared by the in-input counter and the per-group header count.
|
|
1391
|
+
* Default `[selected]` (matches the historical in-input `[N]`); a `getCountLabelCallback` can
|
|
1392
|
+
* switch both to e.g. `selected/total`.
|
|
1393
|
+
*/
|
|
1394
|
+
private formatCountLabel;
|
|
1395
|
+
/** Trailing count chip for a group header — any grouped list (rendered only when >0 selected). */
|
|
1396
|
+
private groupCountHtml;
|
|
1397
|
+
/**
|
|
1398
|
+
* Shared markup for a `.ms__checkbox` input — the single source of truth for option rows, tree
|
|
1399
|
+
* nodes, and group headers. Indeterminate is a pure CSS state (the box is `appearance: none`, so
|
|
1400
|
+
* no native `input.indeterminate` is needed — virtual-scroll-safe) plus `aria-checked="mixed"`.
|
|
1401
|
+
*/
|
|
1402
|
+
private checkboxHtml;
|
|
1403
|
+
/** Group-header tristate checkbox (maps the group's roll-up state onto `checkboxHtml`). */
|
|
1404
|
+
private groupCheckboxHtml;
|
|
1253
1405
|
private renderDropdown;
|
|
1254
1406
|
/**
|
|
1255
1407
|
* Round the OUTER corners of the row at the very top and the row at the very
|
|
@@ -1479,6 +1631,16 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1479
1631
|
private deselectOption;
|
|
1480
1632
|
private selectAll;
|
|
1481
1633
|
clearAll(): void;
|
|
1634
|
+
/**
|
|
1635
|
+
* Flat-group cascade toggle: check or uncheck every (visible) member of a group
|
|
1636
|
+
* in one shot. If the group is fully checked → deselect all its members; else →
|
|
1637
|
+
* select all its non-disabled members. Operates on the currently-filtered
|
|
1638
|
+
* members (same scope as Select-All) and, like Select-All / Clear-All,
|
|
1639
|
+
* batch-mutates then fires a single `commit` — so one render and one `change`
|
|
1640
|
+
* event, and it deliberately bypasses the per-item beforeSelect/beforeDeselect
|
|
1641
|
+
* veto. The group name itself is never added to the selection.
|
|
1642
|
+
*/
|
|
1643
|
+
private toggleGroup;
|
|
1482
1644
|
/**
|
|
1483
1645
|
* Inline clear (✕) handler: wipe the whole selection and any search text, then
|
|
1484
1646
|
* restore focus to the input. clearAll() → commit() → renderBadges() already
|
|
@@ -1552,6 +1714,22 @@ export declare class WebMultiSelect<T = any> {
|
|
|
1552
1714
|
* so they don't actually break the sheet.
|
|
1553
1715
|
*/
|
|
1554
1716
|
private warnFullscreenContainingBlock;
|
|
1717
|
+
/**
|
|
1718
|
+
* Re-anchor an already-open floating dropdown from scratch so a frozen placement
|
|
1719
|
+
* is re-evaluated against the panel's CURRENT height.
|
|
1720
|
+
*
|
|
1721
|
+
* Why it's needed: an async `searchCallback` opens the panel while it's still
|
|
1722
|
+
* empty / showing the loader — short, so it fits below the input and (with the
|
|
1723
|
+
* default `lock-placement`) freezes to `bottom`. When results arrive the panel
|
|
1724
|
+
* grows to full height, but the frozen placement pins it below the input, so it
|
|
1725
|
+
* overflows the viewport bottom instead of flipping above into the free space.
|
|
1726
|
+
* `renderDropdown()` only rewrites the inner HTML; it never re-anchors. Tearing
|
|
1727
|
+
* down and recreating the anchor re-runs core's flip-on-first-compute against the
|
|
1728
|
+
* new height (picking the side that fits), then re-freezes — so `lock-placement`
|
|
1729
|
+
* still holds for the common case (panels that open already-populated, e.g. local
|
|
1730
|
+
* filtering, never hit this path). No-op unless a floating dropdown is open.
|
|
1731
|
+
*/
|
|
1732
|
+
private repositionDropdown;
|
|
1555
1733
|
private positionDropdown;
|
|
1556
1734
|
/**
|
|
1557
1735
|
* Switch how the open panels are presented. 'floating' anchors them to the input
|