@keenmate/web-multiselect 2.0.0-rc10 → 2.0.0-rc11
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 +188 -186
- package/custom-elements.json +187 -75
- package/dist/index.d.ts +40 -3
- package/dist/multiselect.js +1276 -1200
- package/dist/multiselect.umd.js +13 -13
- package/dist/style.css +1 -1
- package/docs/usage.md +5 -0
- package/package.json +1 -1
- package/src/css/controls.css +89 -25
- package/src/css/states.css +6 -5
- package/src/css/variables.css +17 -10
- package/vscode.html-custom-data.json +6 -1
- package/web-types.json +17 -2
package/custom-elements.json
CHANGED
|
@@ -254,11 +254,11 @@
|
|
|
254
254
|
},
|
|
255
255
|
{
|
|
256
256
|
"kind": "field",
|
|
257
|
-
"name": "isOpen",
|
|
257
|
+
"name": "#isOpen",
|
|
258
|
+
"privacy": "private",
|
|
258
259
|
"type": {
|
|
259
260
|
"text": "boolean"
|
|
260
261
|
},
|
|
261
|
-
"privacy": "private",
|
|
262
262
|
"default": "false"
|
|
263
263
|
},
|
|
264
264
|
{
|
|
@@ -738,6 +738,14 @@
|
|
|
738
738
|
},
|
|
739
739
|
"privacy": "private"
|
|
740
740
|
},
|
|
741
|
+
{
|
|
742
|
+
"kind": "field",
|
|
743
|
+
"name": "inputWrapper",
|
|
744
|
+
"type": {
|
|
745
|
+
"text": "HTMLDivElement"
|
|
746
|
+
},
|
|
747
|
+
"privacy": "private"
|
|
748
|
+
},
|
|
741
749
|
{
|
|
742
750
|
"kind": "field",
|
|
743
751
|
"name": "dropdown",
|
|
@@ -770,6 +778,14 @@
|
|
|
770
778
|
},
|
|
771
779
|
"privacy": "private"
|
|
772
780
|
},
|
|
781
|
+
{
|
|
782
|
+
"kind": "field",
|
|
783
|
+
"name": "clearButton",
|
|
784
|
+
"type": {
|
|
785
|
+
"text": "HTMLButtonElement"
|
|
786
|
+
},
|
|
787
|
+
"privacy": "private"
|
|
788
|
+
},
|
|
773
789
|
{
|
|
774
790
|
"kind": "field",
|
|
775
791
|
"name": "hint",
|
|
@@ -823,11 +839,11 @@
|
|
|
823
839
|
{
|
|
824
840
|
"name": "opts",
|
|
825
841
|
"type": {
|
|
826
|
-
"text": "{\
|
|
842
|
+
"text": "{\n member?: string;\n callback?: (item: T) => R;\n tupleIndex?: 0 | 1;\n tupleSkip?: boolean;\n transform?: (raw: any) => R;\n fallback: R | (() => R);\n }"
|
|
827
843
|
}
|
|
828
844
|
}
|
|
829
845
|
],
|
|
830
|
-
"description": "Generic field extractor with the precedence:\
|
|
846
|
+
"description": "Generic field extractor with the precedence:\n tuple short-circuit -> member property -> callback -> fallback\n\nTuple handling:\n - `tupleIndex` (0 | 1): for `[key, value]` items, return that slot.\n - `tupleSkip: true`: for any tuple, skip directly to fallback (used for icon/subtitle/group/disabled —\n fields that don't make sense on a 2-element array).\n - neither: tuples flow through the member/callback/fallback chain as if they were objects.\n\n`transform` is applied to tuple-slot and member-property reads (not to callback returns or the fallback),\nso e.g. you can pass `String` to coerce numeric members to strings while letting a typed callback return its\nown type unchanged."
|
|
831
847
|
},
|
|
832
848
|
{
|
|
833
849
|
"kind": "method",
|
|
@@ -882,7 +898,7 @@
|
|
|
882
898
|
}
|
|
883
899
|
}
|
|
884
900
|
],
|
|
885
|
-
"description": "Badge display falls back to the regular display value rather than '[N/A]', so consumers can override badge\
|
|
901
|
+
"description": "Badge display falls back to the regular display value rather than '[N/A]', so consumers can override badge\ntext independently. Doesn't fit the extractField shape (no tuple/member layer of its own)."
|
|
886
902
|
},
|
|
887
903
|
{
|
|
888
904
|
"kind": "method",
|
|
@@ -901,7 +917,7 @@
|
|
|
901
917
|
}
|
|
902
918
|
}
|
|
903
919
|
],
|
|
904
|
-
"description": "Full title — a fully-qualified label supplied with the data (never computed here). Used by\
|
|
920
|
+
"description": "Full title — a fully-qualified label supplied with the data (never computed here). Used by\nbadges when `isBadgeFullTitleShown` is on. Returns undefined when the option has none."
|
|
905
921
|
},
|
|
906
922
|
{
|
|
907
923
|
"kind": "method",
|
|
@@ -1010,7 +1026,7 @@
|
|
|
1010
1026
|
}
|
|
1011
1027
|
}
|
|
1012
1028
|
],
|
|
1013
|
-
"description": "Tree mode: whether the visible node at `index` may be selected. Non-selectable\
|
|
1029
|
+
"description": "Tree mode: whether the visible node at `index` may be selected. Non-selectable\nnodes (see `isSelectableMember`/`getIsSelectableCallback`) still render — just\nwithout a checkbox — but are skipped by focus and cannot be toggled. Always\ntrue outside tree mode. `treeNodes` is index-aligned with `filteredOptions`."
|
|
1014
1030
|
},
|
|
1015
1031
|
{
|
|
1016
1032
|
"kind": "method",
|
|
@@ -1082,7 +1098,7 @@
|
|
|
1082
1098
|
"text": "boolean"
|
|
1083
1099
|
}
|
|
1084
1100
|
},
|
|
1085
|
-
"description": "Whether cascade checkbox mode is active: a multi-select tree with\
|
|
1101
|
+
"description": "Whether cascade checkbox mode is active: a multi-select tree with\n`checkbox-mode=\"cascade\"`. Checking a node then toggles its whole subtree\nand branches show a tristate box."
|
|
1086
1102
|
},
|
|
1087
1103
|
{
|
|
1088
1104
|
"kind": "method",
|
|
@@ -1122,7 +1138,7 @@
|
|
|
1122
1138
|
}
|
|
1123
1139
|
}
|
|
1124
1140
|
],
|
|
1125
|
-
"description": "Toggle a tree node in cascade mode: flip its whole subtree, re-project the\
|
|
1141
|
+
"description": "Toggle a tree node in cascade mode: flip its whole subtree, re-project the\nchecked atoms to emitted values under the active policy, and commit the diff\nso badges / form / change events reflect the policy (rolled-up branches, etc.)."
|
|
1126
1142
|
},
|
|
1127
1143
|
{
|
|
1128
1144
|
"kind": "method",
|
|
@@ -1141,7 +1157,7 @@
|
|
|
1141
1157
|
}
|
|
1142
1158
|
}
|
|
1143
1159
|
],
|
|
1144
|
-
"description": "Given a checked-atom set, project it to emitted values under the active\
|
|
1160
|
+
"description": "Given a checked-atom set, project it to emitted values under the active\npolicy, diff it against the current selection, and commit. Shared by every\ncascade entry point (node toggle, Select All) so they all emit the same\npolicy-projected shape (e.g. a full subtree rolls up to one value)."
|
|
1145
1161
|
},
|
|
1146
1162
|
{
|
|
1147
1163
|
"kind": "method",
|
|
@@ -1152,7 +1168,7 @@
|
|
|
1152
1168
|
"text": "T[]"
|
|
1153
1169
|
}
|
|
1154
1170
|
},
|
|
1155
|
-
"description": "The \"meaningful selection\" list used by the counter chip — the rolled-up\
|
|
1171
|
+
"description": "The \"meaningful selection\" list used by the counter chip — the rolled-up\nminimal cover, regardless of the active emit policy. In cascade mode\n`leaves`/`all` emit many values for a single branch pick, which made the\ncounter read e.g. `[5]` for what a person experiences as two selections.\nThe counter should count the branches actually chosen, and stay stable when\nthe policy knob flips. Outside cascade this is just the selected options."
|
|
1156
1172
|
},
|
|
1157
1173
|
{
|
|
1158
1174
|
"kind": "method",
|
|
@@ -1182,7 +1198,7 @@
|
|
|
1182
1198
|
"text": "void"
|
|
1183
1199
|
}
|
|
1184
1200
|
},
|
|
1185
|
-
"description": "Derive `treeNodes` + `filteredOptions` from the full tree, applying the\
|
|
1201
|
+
"description": "Derive `treeNodes` + `filteredOptions` from the full tree, applying the\ncurrent search term. Matching nodes keep all their ancestors visible so\nindentation stays coherent (the tree is always fully expanded)."
|
|
1186
1202
|
},
|
|
1187
1203
|
{
|
|
1188
1204
|
"kind": "method",
|
|
@@ -1193,7 +1209,7 @@
|
|
|
1193
1209
|
"text": "void"
|
|
1194
1210
|
}
|
|
1195
1211
|
},
|
|
1196
|
-
"description": "Reset the visible list to \"everything\". **Tree-aware**: in tree mode it\
|
|
1212
|
+
"description": "Reset the visible list to \"everything\". **Tree-aware**: in tree mode it\nrebuilds `treeNodes` (kept index-aligned with `filteredOptions`) from the\nfull tree, so the two never drift. A raw `filteredOptions = [...allOptions]`\nwould leave `treeNodes` stale after clearing a search — the virtual list\nthen reserves height for every option but renders blank rows because\n`treeNodes[index]` is undefined. Always use this to clear the visible list."
|
|
1197
1213
|
},
|
|
1198
1214
|
{
|
|
1199
1215
|
"kind": "method",
|
|
@@ -1212,7 +1228,7 @@
|
|
|
1212
1228
|
}
|
|
1213
1229
|
}
|
|
1214
1230
|
],
|
|
1215
|
-
"description": "Tree mode: derive the visible list from an **external** set of matched\
|
|
1231
|
+
"description": "Tree mode: derive the visible list from an **external** set of matched\noptions — e.g. the results returned by `searchCallback` — keeping each\nmatch's ancestors so indentation stays coherent. This is the async-search\nanalogue of `rebuildTreeVisible`: the matching is done by the caller (their\nown index/engine) instead of a local substring test, but ancestor\npreservation and `treeNodes`/`filteredOptions` index-alignment still happen\nhere. Pass all options to show the whole tree."
|
|
1216
1232
|
},
|
|
1217
1233
|
{
|
|
1218
1234
|
"kind": "method",
|
|
@@ -1223,7 +1239,7 @@
|
|
|
1223
1239
|
"text": "number"
|
|
1224
1240
|
}
|
|
1225
1241
|
},
|
|
1226
|
-
"description": "Tree + `search-mode=\"navigate\"`: keep the ENTIRE tree visible (the tree is always\
|
|
1242
|
+
"description": "Tree + `search-mode=\"navigate\"`: keep the ENTIRE tree visible (the tree is always\nfully expanded, so `flatNodes` is the whole thing) and record which visible rows\nmatch the term in `matchingIndices` — the flat-list navigate behavior, but over\n`treeNodes`. Filter mode collapses the hierarchy to matches + ancestors; navigate\nmode instead leaves the structure intact so the user can jump between matches\n(Ctrl+Arrow on desktop, the fullscreen navigator on touch). Returns the index of\nthe first match, or -1 (no term / no matches), so the caller can set focus."
|
|
1227
1243
|
},
|
|
1228
1244
|
{
|
|
1229
1245
|
"kind": "method",
|
|
@@ -1234,7 +1250,7 @@
|
|
|
1234
1250
|
"text": "void"
|
|
1235
1251
|
}
|
|
1236
1252
|
},
|
|
1237
|
-
"description": "(Re)compute `isRTL` from the host's `dir` (or an RTL ancestor) and derive the\
|
|
1253
|
+
"description": "(Re)compute `isRTL` from the host's `dir` (or an RTL ancestor) and derive the\ndirection-mirrored badges position. Pure state — callers apply the DOM effects\n(class toggle, panel `dir`, badge re-render). In Shadow DOM the `dir` lives on\nthe host element, not the shadow content, so we resolve the host first."
|
|
1238
1254
|
},
|
|
1239
1255
|
{
|
|
1240
1256
|
"kind": "method",
|
|
@@ -1245,7 +1261,7 @@
|
|
|
1245
1261
|
"text": "void"
|
|
1246
1262
|
}
|
|
1247
1263
|
},
|
|
1248
|
-
"description": "Re-read `dir` and re-apply RTL mirroring live. The web-component calls this when\
|
|
1264
|
+
"description": "Re-read `dir` and re-apply RTL mirroring live. The web-component calls this when\nits `dir` attribute changes at runtime (e.g. an app-wide language/direction\nswitch). Most layout follows the inherited CSS `direction` automatically (the\ncomponent is authored with logical properties); this fixes the parts pinned at\nbuild time — the `.ms--rtl` class (badges/count-display placement) and the\nexplicit `dir` on the shadow-root-appended panels (which don't sit under the\n`.ms--rtl` element, so they'd otherwise keep a stale build-time direction)."
|
|
1249
1265
|
},
|
|
1250
1266
|
{
|
|
1251
1267
|
"kind": "method",
|
|
@@ -1307,7 +1323,7 @@
|
|
|
1307
1323
|
"text": "void"
|
|
1308
1324
|
}
|
|
1309
1325
|
},
|
|
1310
|
-
"description": "Round the OUTER corners of the row at the very top and the row at the very\
|
|
1326
|
+
"description": "Round the OUTER corners of the row at the very top and the row at the very\nbottom of the list so a focused/selected row's background — and crucially its\nfocus `outline`, which traces the row's OWN box and follows its border-radius\nbut NOT an ancestor's overflow clip — curves with the panel instead of poking a\nsquare corner past it.\n\nKeyed off DOM order, not option index, so grouping works: when grouped the top\nrow is a `.ms__group-label` (not the first option, which sits below it), so we\nround whichever element is physically first/last. VirtualScroll renders rows in\nindex order into one innerHTML, so DOM order == visual order there too.\n\nLogical corners (`border-start-*` / `border-end-*`) so it mirrors in RTL. A\nspace-taking vertical scrollbar occupies the inline-END gutter, so the END-side\ncorners stay square then (the panel's rounded end corner is the scrollbar\ntrack's). The radius is 0 in the fullscreen sheet (that scope zeroes the var)."
|
|
1311
1327
|
},
|
|
1312
1328
|
{
|
|
1313
1329
|
"kind": "method",
|
|
@@ -1337,7 +1353,7 @@
|
|
|
1337
1353
|
}
|
|
1338
1354
|
}
|
|
1339
1355
|
],
|
|
1340
|
-
"description": "Default enabled/disabled state for the built-in actions, applied only when the consumer hasn't\
|
|
1356
|
+
"description": "Default enabled/disabled state for the built-in actions, applied only when the consumer hasn't\nset an explicit `isDisabled` / `getIsDisabledCallback`:\n- `select-all` is disabled when it would add nothing (every selectable, non-disabled filtered\n option is already selected — this also covers an empty list).\n- `clear-all` is disabled when nothing is selected."
|
|
1341
1357
|
},
|
|
1342
1358
|
{
|
|
1343
1359
|
"kind": "method",
|
|
@@ -1382,7 +1398,7 @@
|
|
|
1382
1398
|
"text": "string"
|
|
1383
1399
|
}
|
|
1384
1400
|
},
|
|
1385
|
-
"description": "Trailing info affordance for an option row, emitted only for the fullscreen\
|
|
1401
|
+
"description": "Trailing info affordance for an option row, emitted only for the fullscreen\noverlay. CSS keeps it hidden until `markTruncatedOptions()` tags the row\n`.ms__option--truncated`, so it appears only when the label is actually clipped.\nTapping it reveals the full label — the touch substitute for the hover option\ntooltip, which never fires on touch (the very devices that get fullscreen).\n`tabindex=\"-1\"` keeps it out of the tab order; the search input owns keyboarding."
|
|
1386
1402
|
},
|
|
1387
1403
|
{
|
|
1388
1404
|
"kind": "method",
|
|
@@ -1407,7 +1423,7 @@
|
|
|
1407
1423
|
}
|
|
1408
1424
|
}
|
|
1409
1425
|
],
|
|
1410
|
-
"description": "Render a single tree-mode row. Separate from `renderOption`: a tree row is\
|
|
1426
|
+
"description": "Render a single tree-mode row. Separate from `renderOption`: a tree row is\nindented by its depth (via the `--ms-tree-depth` custom property) and\ntagged branch/leaf, but otherwise carries the same selection/checkbox/\nicon/subtitle content. The tree is always fully expanded, so there is no\nchevron/toggle — every node is just a normal, selectable option."
|
|
1411
1427
|
},
|
|
1412
1428
|
{
|
|
1413
1429
|
"kind": "method",
|
|
@@ -1470,7 +1486,7 @@
|
|
|
1470
1486
|
"text": "string"
|
|
1471
1487
|
}
|
|
1472
1488
|
},
|
|
1473
|
-
"description": "Resolve the closed-state input placeholder for the current data/search state.\
|
|
1489
|
+
"description": "Resolve the closed-state input placeholder for the current data/search state.\nPriority: explicit no-data placeholder (when the list is empty) → \"pick\" prompt when\nsearch is unusable → the search placeholder."
|
|
1474
1490
|
},
|
|
1475
1491
|
{
|
|
1476
1492
|
"kind": "method",
|
|
@@ -1481,7 +1497,7 @@
|
|
|
1481
1497
|
"text": "string"
|
|
1482
1498
|
}
|
|
1483
1499
|
},
|
|
1484
|
-
"description": "The search field placeholder. An explicit `searchPlaceholder` always wins and stays\
|
|
1500
|
+
"description": "The search field placeholder. An explicit `searchPlaceholder` always wins and stays\nfixed. Otherwise the default is \"Search...\" — except when the in-overlay mode toggle\nis enabled (`isSearchModeToggleShown`), where it becomes mode-aware so the field labels\nthe current behavior: \"Search…\" in navigate mode, \"Filter…\" in filter mode. Refreshed\non a live mode switch (see setSearchModeLive → refreshSearchPlaceholder)."
|
|
1485
1501
|
},
|
|
1486
1502
|
{
|
|
1487
1503
|
"kind": "method",
|
|
@@ -1541,7 +1557,7 @@
|
|
|
1541
1557
|
"text": "void"
|
|
1542
1558
|
}
|
|
1543
1559
|
},
|
|
1544
|
-
"description": "Abort the search request currently in flight, if any. The aborted request's results\
|
|
1560
|
+
"description": "Abort the search request currently in flight, if any. The aborted request's results\nare then ignored (and the consumer's `searchCallback` can short-circuit its fetch via\nthe `AbortSignal` it was handed)."
|
|
1545
1561
|
},
|
|
1546
1562
|
{
|
|
1547
1563
|
"kind": "method",
|
|
@@ -1566,7 +1582,7 @@
|
|
|
1566
1582
|
}
|
|
1567
1583
|
}
|
|
1568
1584
|
],
|
|
1569
|
-
"description": "Invoke the async `searchCallback` and apply its results. Split out of `handleSearch`\
|
|
1585
|
+
"description": "Invoke the async `searchCallback` and apply its results. Split out of `handleSearch`\nso it can be called immediately or after the debounce timer.\n\nAny request still in flight is aborted before a new one starts, so a slow earlier\nrequest can't overwrite a newer one — and consumers that wire the passed `AbortSignal`\ninto their fetch get the request actually cancelled, not just ignored. The\n`aborted` / `searchTerm === value` guards drop superseded or out-of-order responses."
|
|
1570
1586
|
},
|
|
1571
1587
|
{
|
|
1572
1588
|
"kind": "method",
|
|
@@ -1664,7 +1680,7 @@
|
|
|
1664
1680
|
}
|
|
1665
1681
|
}
|
|
1666
1682
|
],
|
|
1667
|
-
"description": "Move focus by computing a new index from (current, total).\
|
|
1683
|
+
"description": "Move focus by computing a new index from (current, total).\nReturning -1 from `compute` is a no-op (used for empty list / no match)."
|
|
1668
1684
|
},
|
|
1669
1685
|
{
|
|
1670
1686
|
"kind": "method",
|
|
@@ -1695,7 +1711,7 @@
|
|
|
1695
1711
|
}
|
|
1696
1712
|
}
|
|
1697
1713
|
],
|
|
1698
|
-
"description": "Given a target index and a preferred direction, return the nearest index\
|
|
1714
|
+
"description": "Given a target index and a preferred direction, return the nearest index\nwhose node is selectable (skipping non-selectable tree nodes). Falls back to\nthe opposite direction, then to -1 if nothing is selectable. No-op outside\ntree mode."
|
|
1699
1715
|
},
|
|
1700
1716
|
{
|
|
1701
1717
|
"kind": "method",
|
|
@@ -1786,7 +1802,7 @@
|
|
|
1786
1802
|
"text": "MultiSelectKeyboardController<T>"
|
|
1787
1803
|
}
|
|
1788
1804
|
},
|
|
1789
|
-
"description": "Lazily build (and cache) the imperative facade passed to `keydownCallback`. Bound to the\
|
|
1805
|
+
"description": "Lazily build (and cache) the imperative facade passed to `keydownCallback`. Bound to the\nsame private actions the built-in key handling uses, so consumer shortcuts behave identically."
|
|
1790
1806
|
},
|
|
1791
1807
|
{
|
|
1792
1808
|
"kind": "method",
|
|
@@ -1797,7 +1813,7 @@
|
|
|
1797
1813
|
"text": "void"
|
|
1798
1814
|
}
|
|
1799
1815
|
},
|
|
1800
|
-
"description": "Clear the search box (both the main input and the fullscreen search) and reset the visible\
|
|
1816
|
+
"description": "Clear the search box (both the main input and the fullscreen search) and reset the visible\nlist. Shared by Escape and the keyboard controller."
|
|
1801
1817
|
},
|
|
1802
1818
|
{
|
|
1803
1819
|
"kind": "method",
|
|
@@ -1844,7 +1860,7 @@
|
|
|
1844
1860
|
}
|
|
1845
1861
|
}
|
|
1846
1862
|
],
|
|
1847
|
-
"description": "The single funnel for an interactive (user-initiated) selection. Consults\
|
|
1863
|
+
"description": "The single funnel for an interactive (user-initiated) selection. Consults\n`beforeSelectCallback` and only mutates state if allowed, so the veto can\nnever be bypassed by a new UI entry point. Programmatic `setSelected` and\nthe Select-All button deliberately do not route through here.\nReturns true if the option was selected, false if the veto blocked it."
|
|
1848
1864
|
},
|
|
1849
1865
|
{
|
|
1850
1866
|
"kind": "method",
|
|
@@ -1863,7 +1879,7 @@
|
|
|
1863
1879
|
}
|
|
1864
1880
|
}
|
|
1865
1881
|
],
|
|
1866
|
-
"description": "The single funnel for an interactive (user-initiated) deselection. Every\
|
|
1882
|
+
"description": "The single funnel for an interactive (user-initiated) deselection. Every\nremoval affordance — dropdown toggle, badge × button, selected-items\npopover × button, and the \"remove hidden\" badge — routes through here so\nthe `beforeDeselectCallback` veto applies uniformly. Programmatic\n`setSelected` and the Clear-All button deliberately bypass it.\nReturns true if the option was deselected, false if the veto blocked it."
|
|
1867
1883
|
},
|
|
1868
1884
|
{
|
|
1869
1885
|
"kind": "method",
|
|
@@ -1939,6 +1955,28 @@
|
|
|
1939
1955
|
}
|
|
1940
1956
|
}
|
|
1941
1957
|
},
|
|
1958
|
+
{
|
|
1959
|
+
"kind": "method",
|
|
1960
|
+
"name": "clearClick",
|
|
1961
|
+
"privacy": "private",
|
|
1962
|
+
"return": {
|
|
1963
|
+
"type": {
|
|
1964
|
+
"text": "void"
|
|
1965
|
+
}
|
|
1966
|
+
},
|
|
1967
|
+
"description": "Inline clear (✕) handler: wipe the whole selection and any search text, then\nrestore focus to the input. clearAll() → commit() → renderBadges() already\nrefreshes this button's visibility (it hides once nothing is selected)."
|
|
1968
|
+
},
|
|
1969
|
+
{
|
|
1970
|
+
"kind": "method",
|
|
1971
|
+
"name": "updateClearButton",
|
|
1972
|
+
"privacy": "private",
|
|
1973
|
+
"return": {
|
|
1974
|
+
"type": {
|
|
1975
|
+
"text": "void"
|
|
1976
|
+
}
|
|
1977
|
+
},
|
|
1978
|
+
"description": "Show the inline clear (✕) only when it is opted in (isClearShown), something is\nselected, and the control is enabled. Called from renderBadges() so it tracks\nevery selection change. Uses inline display like the counter / fullscreen clear."
|
|
1979
|
+
},
|
|
1942
1980
|
{
|
|
1943
1981
|
"kind": "method",
|
|
1944
1982
|
"name": "commit",
|
|
@@ -1956,27 +1994,45 @@
|
|
|
1956
1994
|
}
|
|
1957
1995
|
}
|
|
1958
1996
|
],
|
|
1959
|
-
"description": "Re-render and fire callbacks after a selection state change.\
|
|
1997
|
+
"description": "Re-render and fire callbacks after a selection state change.\n`added` / `removed` drive per-item select/deselect callbacks.\n`onChange` fires once if anything actually changed."
|
|
1960
1998
|
},
|
|
1961
1999
|
{
|
|
1962
2000
|
"kind": "method",
|
|
1963
2001
|
"name": "open",
|
|
1964
|
-
"privacy": "private",
|
|
1965
2002
|
"return": {
|
|
1966
2003
|
"type": {
|
|
1967
2004
|
"text": "void"
|
|
1968
2005
|
}
|
|
1969
|
-
}
|
|
2006
|
+
},
|
|
2007
|
+
"description": "Open the dropdown (no-op if already open, or if there is nothing to show)."
|
|
1970
2008
|
},
|
|
1971
2009
|
{
|
|
1972
2010
|
"kind": "method",
|
|
1973
2011
|
"name": "close",
|
|
1974
|
-
"privacy": "private",
|
|
1975
2012
|
"return": {
|
|
1976
2013
|
"type": {
|
|
1977
2014
|
"text": "void"
|
|
1978
2015
|
}
|
|
1979
|
-
}
|
|
2016
|
+
},
|
|
2017
|
+
"description": "Close the dropdown (no-op if already closed)."
|
|
2018
|
+
},
|
|
2019
|
+
{
|
|
2020
|
+
"kind": "method",
|
|
2021
|
+
"name": "toggle",
|
|
2022
|
+
"return": {
|
|
2023
|
+
"type": {
|
|
2024
|
+
"text": "void"
|
|
2025
|
+
}
|
|
2026
|
+
},
|
|
2027
|
+
"description": "Toggle the dropdown open/closed."
|
|
2028
|
+
},
|
|
2029
|
+
{
|
|
2030
|
+
"kind": "field",
|
|
2031
|
+
"name": "isOpen",
|
|
2032
|
+
"type": {
|
|
2033
|
+
"text": "boolean"
|
|
2034
|
+
},
|
|
2035
|
+
"description": "Whether the dropdown is currently open. Assigning opens/closes it."
|
|
1980
2036
|
},
|
|
1981
2037
|
{
|
|
1982
2038
|
"kind": "method",
|
|
@@ -1997,11 +2053,11 @@
|
|
|
1997
2053
|
{
|
|
1998
2054
|
"name": "opts",
|
|
1999
2055
|
"type": {
|
|
2000
|
-
"text": "{\
|
|
2056
|
+
"text": "{\n getPlacement: () => Placement | null;\n setPlacement: (p: Placement) => void;\n /** When false, never locks (re-flips on every update). Defaults to true. */\n isLocked?: () => boolean;\n applyMaxWidth?: boolean;\n afterPosition?: () => void;\n }"
|
|
2001
2057
|
}
|
|
2002
2058
|
}
|
|
2003
2059
|
],
|
|
2004
|
-
"description": "Anchor a floating panel (dropdown or selected-items popover) below/above the input with\
|
|
2060
|
+
"description": "Anchor a floating panel (dropdown or selected-items popover) below/above the input with\nplacement-locking and width-syncing. Returns the `autoUpdate` cleanup.\n\nBoth panels share: anchor on input, sync width, default to 'bottom-start', flip on first\ncompute then lock the resulting placement, optionally clamp by dropdownMin/MaxWidth."
|
|
2005
2061
|
},
|
|
2006
2062
|
{
|
|
2007
2063
|
"kind": "method",
|
|
@@ -2020,7 +2076,7 @@
|
|
|
2020
2076
|
}
|
|
2021
2077
|
}
|
|
2022
2078
|
],
|
|
2023
|
-
"description": "Surface a multiselect-branded, once-per-instance warning when core's drift check\
|
|
2079
|
+
"description": "Surface a multiselect-branded, once-per-instance warning when core's drift check\n(`anchor`'s `onDrift`) reports the panel didn't land where it was positioned. The\nconsumer has an ancestor that establishes a fixed containing block but isn't on the\nreliable-anchors list (likely `contain: paint|layout|strict` or `container-type`).\nWe can't fix it from inside the library, but we point at the likely culprit. Core\nowns the measurement + culprit-finding + CB-CSS diagnostic (`detectFixedDrift`)."
|
|
2024
2080
|
},
|
|
2025
2081
|
{
|
|
2026
2082
|
"kind": "method",
|
|
@@ -2031,7 +2087,7 @@
|
|
|
2031
2087
|
"text": "void"
|
|
2032
2088
|
}
|
|
2033
2089
|
},
|
|
2034
|
-
"description": "Fullscreen counterpart of warnDrift. The overlay is a `position: fixed`,\
|
|
2090
|
+
"description": "Fullscreen counterpart of warnDrift. The overlay is a `position: fixed`,\nfull-viewport sheet — but if an ancestor of the host establishes a fixed-positioning\ncontaining block (`transform` / `perspective` / `filter` / `backdrop-filter` / a\nqualifying `will-change`), the browser anchors the sheet to THAT ancestor's box instead\nof the viewport, so it no longer covers the screen (offset, clipped, or mis-sized).\n\nUnlike the floating path — where core measures real drift after positioning — nothing\nanchors the sheet, so there's no drift to observe. Instead we ask core's shared\nheuristic (`getFixedPositionOffsetParent`, the same one that feeds the floating platform)\nwhether the sheet's true offset parent is the viewport (`window`) or an element. An\nelement means it WILL be mis-anchored; warn once, pointing at the culprit. We only check\nthe reliably-honoured properties core lists (transform family) — `contain` /\n`container-type` are omitted because browsers don't honour them for fixed positioning,\nso they don't actually break the sheet."
|
|
2035
2091
|
},
|
|
2036
2092
|
{
|
|
2037
2093
|
"kind": "method",
|
|
@@ -2060,7 +2116,7 @@
|
|
|
2060
2116
|
}
|
|
2061
2117
|
}
|
|
2062
2118
|
],
|
|
2063
|
-
"description": "Switch how the open panels are presented. 'floating' anchors them to the input\
|
|
2119
|
+
"description": "Switch how the open panels are presented. 'floating' anchors them to the input\n(the default); 'fullscreen' renders them as full-viewport overlays (the phone\npattern) — the dropdown with its own search header + close, the selected-items\npopover with its existing header + close. Driven by the element's\n`environmentChanged` hook (auto → fullscreen on phones). A no-op when unchanged;\nwhen a panel is already open it re-applies live so an orientation flip / viewport\nresize can swap presentation without a reopen."
|
|
2064
2120
|
},
|
|
2065
2121
|
{
|
|
2066
2122
|
"kind": "method",
|
|
@@ -2071,7 +2127,7 @@
|
|
|
2071
2127
|
"text": "void"
|
|
2072
2128
|
}
|
|
2073
2129
|
},
|
|
2074
|
-
"description": "Lock page scroll behind a fullscreen overlay via the core ref-counted helper.\
|
|
2130
|
+
"description": "Lock page scroll behind a fullscreen overlay via the core ref-counted helper.\nIdempotent per instance: the dropdown and the selected-items popover are mutually\nexclusive (opening one closes the other), so we hold at most one lock at a time,\nand a redundant call is a no-op rather than acquiring a second."
|
|
2075
2131
|
},
|
|
2076
2132
|
{
|
|
2077
2133
|
"kind": "method",
|
|
@@ -2093,7 +2149,7 @@
|
|
|
2093
2149
|
"text": "void"
|
|
2094
2150
|
}
|
|
2095
2151
|
},
|
|
2096
|
-
"description": "Clip the host document's horizontal overflow while a fullscreen sheet is open.\
|
|
2152
|
+
"description": "Clip the host document's horizontal overflow while a fullscreen sheet is open.\n\nA page that overflows horizontally (e.g. an unbreakable-wide token in a heading)\nmakes the mobile browser SHRINK-TO-FIT: it zooms the page out so the overflow fits,\nwhich desyncs the visual viewport from the layout viewport. Our fullscreen sheet is\n`position: fixed` — anchored to the LAYOUT viewport — so under that zoom it no longer\nlands flush against the physical screen edges, and the top slips under the system bar\n(looks like \"the bar covers the sheet\"). This is NOT a safe-area problem; safe-area\ninsets are 0 in that state. Clamping `overflow-x: hidden` on <html>/<body> removes the\noverflow, so the browser drops the zoom and the sheet sits flush. Complements\nlockBodyScroll() (vertical axis); the saved inline value is restored on close.\n\nOnly <html> is touched (not <body>): clipping the root's horizontal overflow is\nenough to collapse the scrollWidth and cancel the shrink-to-fit, and it avoids\nconflicting with core's lockBodyScroll(), which owns <body>'s `overflow`. Idempotent."
|
|
2097
2153
|
},
|
|
2098
2154
|
{
|
|
2099
2155
|
"kind": "method",
|
|
@@ -2115,7 +2171,7 @@
|
|
|
2115
2171
|
"text": "void"
|
|
2116
2172
|
}
|
|
2117
2173
|
},
|
|
2118
|
-
"description": "While the fullscreen dropdown is open, keep it sitting above the soft keyboard.\
|
|
2174
|
+
"description": "While the fullscreen dropdown is open, keep it sitting above the soft keyboard.\nDelegates to core's `observeKeyboardInset` (which tracks `window.visualViewport`\nand pins the panel's height/top so its flex column reflows above the keyboard);\nwe just hold the returned cleanup. No-op where `visualViewport` is unavailable."
|
|
2119
2175
|
},
|
|
2120
2176
|
{
|
|
2121
2177
|
"kind": "method",
|
|
@@ -2137,7 +2193,7 @@
|
|
|
2137
2193
|
"text": "number"
|
|
2138
2194
|
}
|
|
2139
2195
|
},
|
|
2140
|
-
"description": "The fullscreen size multiplier = `--ms-fullscreen-rem ÷ --ms-rem` (both read off\
|
|
2196
|
+
"description": "The fullscreen size multiplier = `--ms-fullscreen-rem ÷ --ms-rem` (both read off\nthe host). CSS scales itself — every size is `calc(N × --ms-rem)` and the panel\noverrides `--ms-rem` — so this exists only for the JS-driven pixel heights that\nCSS can't reach: the virtual/fixed option rows and the popover's virtual badges.\nReturns 1 when floating (or when computed styles aren't readable, e.g. jsdom)."
|
|
2141
2197
|
},
|
|
2142
2198
|
{
|
|
2143
2199
|
"kind": "method",
|
|
@@ -2167,7 +2223,7 @@
|
|
|
2167
2223
|
}
|
|
2168
2224
|
}
|
|
2169
2225
|
],
|
|
2170
|
-
"description": "Size the virtual options scroll container for the current presentation. Applied on\
|
|
2226
|
+
"description": "Size the virtual options scroll container for the current presentation. Applied on\nevery render (the container itself is built once), so a floating⇄fullscreen switch\nre-sizes it: floating = a fixed maxHeight scroll box; fullscreen = flex-fill the\npanel's flex column (no fixed height). Also refreshes --ms-option-height to the\nscaled row height so the CSS row height matches the virtual scroller's itemHeight."
|
|
2171
2227
|
},
|
|
2172
2228
|
{
|
|
2173
2229
|
"kind": "method",
|
|
@@ -2178,7 +2234,7 @@
|
|
|
2178
2234
|
"text": "number"
|
|
2179
2235
|
}
|
|
2180
2236
|
},
|
|
2181
|
-
"description": "Virtual popover badge row height (px). In the fullscreen phone view the rows are\
|
|
2237
|
+
"description": "Virtual popover badge row height (px). In the fullscreen phone view the rows are\nscaled up AND given extra height so a selected item is a comfortable, dropdown-like\ntouch target (the default 36px pill is short for touch). Mirrors the CSS\n`--ms-badge-height` override for the fullscreen popover (floating.css) so the\nvirtual list's fixed height agrees with the non-virtual pills."
|
|
2182
2238
|
},
|
|
2183
2239
|
{
|
|
2184
2240
|
"kind": "method",
|
|
@@ -2197,7 +2253,7 @@
|
|
|
2197
2253
|
}
|
|
2198
2254
|
}
|
|
2199
2255
|
],
|
|
2200
|
-
"description": "Clear the inline geometry that floating-ui's `anchor` writes on a panel\
|
|
2256
|
+
"description": "Clear the inline geometry that floating-ui's `anchor` writes on a panel\n(position/left/top plus our composed max-width/min-width). Inline styles beat\nthe stylesheet, so a panel left over from a floating cycle would otherwise pin\nitself where it last anchored and ignore the fullscreen CSS (position: fixed;\ninset: 0; width: 100vw). Must run when switching a panel floating → fullscreen."
|
|
2201
2257
|
},
|
|
2202
2258
|
{
|
|
2203
2259
|
"kind": "method",
|
|
@@ -2230,7 +2286,7 @@
|
|
|
2230
2286
|
"text": "void"
|
|
2231
2287
|
}
|
|
2232
2288
|
},
|
|
2233
|
-
"description": "Back-gesture handling for the fullscreen sheet. On open we push a history entry\
|
|
2289
|
+
"description": "Back-gesture handling for the fullscreen sheet. On open we push a history entry\n(same URL) and listen for `popstate`; the phone Back gesture/button then pops that\nentry — which we treat as \"close the sheet\" — instead of navigating away from the\npage. A programmatic close (✕, selection, Escape) consumes the entry via\n`history.back()` so the stack is left as it was found."
|
|
2234
2290
|
},
|
|
2235
2291
|
{
|
|
2236
2292
|
"kind": "method",
|
|
@@ -2241,7 +2297,7 @@
|
|
|
2241
2297
|
"text": "void"
|
|
2242
2298
|
}
|
|
2243
2299
|
},
|
|
2244
|
-
"description": "Back gesture/button fired: our pushed entry is already gone, so just close the\
|
|
2300
|
+
"description": "Back gesture/button fired: our pushed entry is already gone, so just close the\nsheet — WITHOUT popping history again (popOverlayHistory becomes a no-op)."
|
|
2245
2301
|
},
|
|
2246
2302
|
{
|
|
2247
2303
|
"kind": "method",
|
|
@@ -2252,7 +2308,7 @@
|
|
|
2252
2308
|
"text": "void"
|
|
2253
2309
|
}
|
|
2254
2310
|
},
|
|
2255
|
-
"description": "Programmatic close: remove the listener and pop the entry we pushed (so the\
|
|
2311
|
+
"description": "Programmatic close: remove the listener and pop the entry we pushed (so the\nhistory stack returns to its pre-open state). No-op if a Back gesture already\nconsumed it (overlayHistoryActive is false by then)."
|
|
2256
2312
|
},
|
|
2257
2313
|
{
|
|
2258
2314
|
"kind": "method",
|
|
@@ -2263,7 +2319,7 @@
|
|
|
2263
2319
|
"text": "void"
|
|
2264
2320
|
}
|
|
2265
2321
|
},
|
|
2266
|
-
"description": "Build the fullscreen overlay header: a search field (proxying to the same\
|
|
2322
|
+
"description": "Build the fullscreen overlay header: a search field (proxying to the same\n`handleSearch`/`handleKeydown` path as the main input, since the overlay covers\nit) plus a close button. Inserted before the scrolling list so it pins to the\ntop of the fixed panel. `renderDropdown()` only rewrites `dropdownInner`, so the\nheader survives re-renders."
|
|
2267
2323
|
},
|
|
2268
2324
|
{
|
|
2269
2325
|
"kind": "method",
|
|
@@ -2274,7 +2330,7 @@
|
|
|
2274
2330
|
"text": "void"
|
|
2275
2331
|
}
|
|
2276
2332
|
},
|
|
2277
|
-
"description": "Build the navigate-mode match navigator (count + prev/next) and append it to the\
|
|
2333
|
+
"description": "Build the navigate-mode match navigator (count + prev/next) and append it to the\nfullscreen header, once. No-op if already built or the header isn't present. The\nnav wraps onto its own full-width row under the search box (header is flex-wrap;\nthe nav takes 100% basis)."
|
|
2278
2334
|
},
|
|
2279
2335
|
{
|
|
2280
2336
|
"kind": "method",
|
|
@@ -2315,7 +2371,7 @@
|
|
|
2315
2371
|
}
|
|
2316
2372
|
}
|
|
2317
2373
|
],
|
|
2318
|
-
"description": "Switch searchMode in place — the overlay's toggle path. The `search-mode` attribute\
|
|
2374
|
+
"description": "Switch searchMode in place — the overlay's toggle path. The `search-mode` attribute\nis reinit-on-change (it rebuilds and closes the overlay); this instead mutates the\nlive config, adds/removes the match navigator to match, and re-projects the current\nterm under the new mode (filter narrows the list / navigate keeps all + highlights),\nall without tearing the open sheet down. Focus stays on the search field."
|
|
2319
2375
|
},
|
|
2320
2376
|
{
|
|
2321
2377
|
"kind": "method",
|
|
@@ -2326,7 +2382,7 @@
|
|
|
2326
2382
|
"text": "void"
|
|
2327
2383
|
}
|
|
2328
2384
|
},
|
|
2329
|
-
"description": "Sync the mode toggle's icon (via data-mode) and labels with the current searchMode.\
|
|
2385
|
+
"description": "Sync the mode toggle's icon (via data-mode) and labels with the current searchMode.\nNo-op when the toggle isn't built (opt-out, floating panel, or search hidden)."
|
|
2330
2386
|
},
|
|
2331
2387
|
{
|
|
2332
2388
|
"kind": "method",
|
|
@@ -2337,7 +2393,7 @@
|
|
|
2337
2393
|
"text": "void"
|
|
2338
2394
|
}
|
|
2339
2395
|
},
|
|
2340
|
-
"description": "Sync the fullscreen match navigator (navigate mode only) with the current search\
|
|
2396
|
+
"description": "Sync the fullscreen match navigator (navigate mode only) with the current search\nstate: hide it until there's a term, then show \"N of M\" while a match is focused\n(or \"M matches\" / \"No matches\"), and disable the prev/next buttons when there's\nnothing to step through. No-op when the navigator isn't built (floating panel,\nfilter mode, or search disabled)."
|
|
2341
2397
|
},
|
|
2342
2398
|
{
|
|
2343
2399
|
"kind": "method",
|
|
@@ -2348,7 +2404,7 @@
|
|
|
2348
2404
|
"text": "void"
|
|
2349
2405
|
}
|
|
2350
2406
|
},
|
|
2351
|
-
"description": "Show the fullscreen search's inline clear (✕) only while the field has text.\
|
|
2407
|
+
"description": "Show the fullscreen search's inline clear (✕) only while the field has text.\nNo-op when the button isn't built (floating panel, readonly/hidden search)."
|
|
2352
2408
|
},
|
|
2353
2409
|
{
|
|
2354
2410
|
"kind": "method",
|
|
@@ -2359,7 +2415,7 @@
|
|
|
2359
2415
|
"text": "void"
|
|
2360
2416
|
}
|
|
2361
2417
|
},
|
|
2362
|
-
"description": "Clear the fullscreen search term via the same path a keystroke takes, then\
|
|
2418
|
+
"description": "Clear the fullscreen search term via the same path a keystroke takes, then\nrefocus the field so the user can keep typing. Touch has no keyboard Escape,\nso this button is the on-screen way to reset a search."
|
|
2363
2419
|
},
|
|
2364
2420
|
{
|
|
2365
2421
|
"kind": "method",
|
|
@@ -2390,7 +2446,7 @@
|
|
|
2390
2446
|
"text": "void"
|
|
2391
2447
|
}
|
|
2392
2448
|
},
|
|
2393
|
-
"description": "Resolve any `selectedValues` entries that don't yet have a matching\
|
|
2449
|
+
"description": "Resolve any `selectedValues` entries that don't yet have a matching\n`selectedOptions` object by looking them up in the current `allOptions`.\nIdempotent; safe to call after init *and* after `options` is replaced\n(e.g., async fetch, `searchCallback` result, or late `element.options =`\nassignment). Without this, `initial-values` declared before options\narrive ends up with phantom values that `getValue()` can never report."
|
|
2394
2450
|
},
|
|
2395
2451
|
{
|
|
2396
2452
|
"kind": "method",
|
|
@@ -2473,7 +2529,7 @@
|
|
|
2473
2529
|
}
|
|
2474
2530
|
}
|
|
2475
2531
|
],
|
|
2476
|
-
"description": "Coerce a render-callback result to an HTML string. Callbacks may return a string\
|
|
2532
|
+
"description": "Coerce a render-callback result to an HTML string. Callbacks may return a string\n(HTML) or an HTMLElement (serialized via `outerHTML`); null/undefined → ''. Used by\nevery \"return string | HTMLElement\" content callback that builds into an innerHTML\nstring. (DOM sinks that hold a live node instead — the reveal/message panels — use\ntextContent/appendChild directly and intentionally don't go through here.)"
|
|
2477
2533
|
},
|
|
2478
2534
|
{
|
|
2479
2535
|
"kind": "method",
|
|
@@ -2492,7 +2548,7 @@
|
|
|
2492
2548
|
}
|
|
2493
2549
|
}
|
|
2494
2550
|
],
|
|
2495
|
-
"description": "Normalize a class callback result (`string | string[] | null`) to a single\
|
|
2551
|
+
"description": "Normalize a class callback result (`string | string[] | null`) to a single\nspace-joined string with falsy entries dropped — e.g. `['a', '', 'b'] → \"a b\"`,\n`null → \"\"`. Callers add their own leading space / base class as needed."
|
|
2496
2552
|
},
|
|
2497
2553
|
{
|
|
2498
2554
|
"kind": "method",
|
|
@@ -2517,7 +2573,7 @@
|
|
|
2517
2573
|
}
|
|
2518
2574
|
}
|
|
2519
2575
|
],
|
|
2520
|
-
"description": "Render a removable badge for a selected option (used by the badges/partial display modes\
|
|
2576
|
+
"description": "Render a removable badge for a selected option (used by the badges/partial display modes\nand by the selected-items popover).\n\n- In the popover, `renderSelectedItemContentCallback` and `getSelectedItemClassCallback` win\n over the regular badge callbacks; that's how consumers customize popover items independently.\n- The `data-value` and aria-label both go through `getItemBadgeDisplayValue` so badge text and\n accessible name stay in sync."
|
|
2521
2577
|
},
|
|
2522
2578
|
{
|
|
2523
2579
|
"kind": "method",
|
|
@@ -2601,7 +2657,7 @@
|
|
|
2601
2657
|
}
|
|
2602
2658
|
}
|
|
2603
2659
|
],
|
|
2604
|
-
"description": "Set the selection programmatically. **Silent by default** — it does not fire\
|
|
2660
|
+
"description": "Set the selection programmatically. **Silent by default** — it does not fire\n`select`/`deselect`/`change` (so restoring saved state, cascade resets, or a\nserver-authoritative correction can't loop back or trip \"user changed it\"\nhandlers). Pass `{ notify: true }` to announce the result as a **single\naggregate `change`** — for a deliberate user gesture (e.g. an action button)\nthat should reach the same listeners a manual pick does, without the per-item\n`select`/`deselect` flood a bulk change would otherwise cause."
|
|
2605
2661
|
},
|
|
2606
2662
|
{
|
|
2607
2663
|
"kind": "method",
|
|
@@ -2620,7 +2676,7 @@
|
|
|
2620
2676
|
}
|
|
2621
2677
|
}
|
|
2622
2678
|
],
|
|
2623
|
-
"description": "Merge a partial config update into the live picker without tearing down the DOM.\
|
|
2679
|
+
"description": "Merge a partial config update into the live picker without tearing down the DOM.\n\nHandles the cheap structural toggles inline (no-checkboxes class, badges-position class,\ninput placeholder, search-input mode) and re-renders dropdown + badges + hidden inputs.\n\nReturns `true` if the change could be applied in place. Returns `false` for changes that\ntruly require rebuilding the DOM scaffolding (currently: adding/removing the `searchHint`\nelement, since it's only created in `buildHTML` if a hint string was provided). The caller\nshould fall back to destroy + re-init in that case."
|
|
2624
2680
|
},
|
|
2625
2681
|
{
|
|
2626
2682
|
"kind": "field",
|
|
@@ -2663,11 +2719,11 @@
|
|
|
2663
2719
|
{
|
|
2664
2720
|
"name": "spec",
|
|
2665
2721
|
"type": {
|
|
2666
|
-
"text": "{\
|
|
2722
|
+
"text": "{\n id: string;\n trigger: HTMLElement;\n content: string | HTMLElement;\n onBeforeShow?: () => void;\n /** Override placement (default: `badgeTooltipPlacement`). */\n placement?: Placement;\n /** Override offset (default: `badgeTooltipOffset`). */\n offsetDistance?: number;\n /** Override show delay (default: `badgeTooltipDelay`). */\n showDelay?: number;\n /** Tooltip element CSS class (default: badge tooltip styling). */\n cssClass?: string;\n /** Visibility-toggle CSS class (default: badge tooltip visible class). */\n visibleClass?: string;\n /** Anchor to and follow the mouse pointer. */\n followCursor?: boolean;\n }"
|
|
2667
2723
|
}
|
|
2668
2724
|
}
|
|
2669
2725
|
],
|
|
2670
|
-
"description": "Create or replace a tracked tooltip with the given id. Replacing destroys the old one,\
|
|
2726
|
+
"description": "Create or replace a tracked tooltip with the given id. Replacing destroys the old one,\nwhich is the normal flow when re-rendering badges/actions."
|
|
2671
2727
|
},
|
|
2672
2728
|
{
|
|
2673
2729
|
"kind": "method",
|
|
@@ -2771,7 +2827,7 @@
|
|
|
2771
2827
|
"text": "void"
|
|
2772
2828
|
}
|
|
2773
2829
|
},
|
|
2774
|
-
"description": "Attach hover tooltips to the currently rendered dropdown options. Prunes existing option\
|
|
2830
|
+
"description": "Attach hover tooltips to the currently rendered dropdown options. Prunes existing option\ntooltips first, so it's safe to call on every render and on every virtual-scroll range change\n(where option DOM is recycled). Each option resolves its source object via `data-index` into\n`filteredOptions`, the same global index `renderOption` was given."
|
|
2775
2831
|
},
|
|
2776
2832
|
{
|
|
2777
2833
|
"kind": "method",
|
|
@@ -2782,7 +2838,7 @@
|
|
|
2782
2838
|
"text": "void"
|
|
2783
2839
|
}
|
|
2784
2840
|
},
|
|
2785
|
-
"description": "Tag each currently-rendered fullscreen option row whose title is horizontally\
|
|
2841
|
+
"description": "Tag each currently-rendered fullscreen option row whose title is horizontally\nclipped with `.ms__option--truncated`, so CSS reveals its info affordance.\nRuns per virtual-scroll render (rows recycle) and on the non-virtual render.\nHorizontal (ellipsis) overflow only — the truncation mode this pairs with;\na wrapping title isn't \"cut\", it grows vertically. No-op unless fullscreen."
|
|
2786
2842
|
},
|
|
2787
2843
|
{
|
|
2788
2844
|
"kind": "method",
|
|
@@ -2801,7 +2857,7 @@
|
|
|
2801
2857
|
}
|
|
2802
2858
|
}
|
|
2803
2859
|
],
|
|
2804
|
-
"description": "Reveal (or dismiss) the full label of a clipped fullscreen row when its info\
|
|
2860
|
+
"description": "Reveal (or dismiss) the full label of a clipped fullscreen row when its info\naffordance is tapped — hover tooltips don't fire on touch, and a hover tooltip's\nsynthetic mouseleave (from the tap itself, under devtools touch emulation) would\nflash it away. So this is a manually-controlled `createPopover` panel, mounted in\nthe shadow root for component styling, that stays until explicitly dismissed:\na second tap on the same button, a list scroll, a re-render, an outside tap, or\nclosing the panel (see hideLabelReveal + its call sites). Tapping the same button\nwhile it's shown toggles it off."
|
|
2805
2861
|
},
|
|
2806
2862
|
{
|
|
2807
2863
|
"kind": "method",
|
|
@@ -2838,7 +2894,7 @@
|
|
|
2838
2894
|
}
|
|
2839
2895
|
}
|
|
2840
2896
|
],
|
|
2841
|
-
"description": "Show a transient message (\"toast\") on top of the component. Its reason for existing:\
|
|
2897
|
+
"description": "Show a transient message (\"toast\") on top of the component. Its reason for existing:\nin the fullscreen overlay the sheet covers the whole page, so a consumer can't surface\nfeedback (a blocked veto, a hint) where the user can see it. This renders above the\npanel in BOTH presentations — anchored under the control when floating, pinned to the\nbottom of the viewport (over the overlay) when fullscreen.\n\nContent is a string (plain text) or an HTMLElement (rich markup). `opts.variant`\n(info | warning | error | success) picks the tone; `opts.duration` sets auto-dismiss\n(0 = sticky). Tapping the message dismisses it. Only one shows at a time — a new call\nreplaces the previous. Also reached automatically when a veto callback returns a string."
|
|
2842
2898
|
},
|
|
2843
2899
|
{
|
|
2844
2900
|
"kind": "method",
|
|
@@ -2860,7 +2916,7 @@
|
|
|
2860
2916
|
"text": "void"
|
|
2861
2917
|
}
|
|
2862
2918
|
},
|
|
2863
|
-
"description": "Hide (don't destroy) every currently-shown option tooltip immediately,\
|
|
2919
|
+
"description": "Hide (don't destroy) every currently-shown option tooltip immediately,\nignoring the hide delay. Wired to dropdown scroll so a tooltip can't trail\nits recycling/scrolling anchor row. Handles stay in the map; a fresh hover\nre-shows them."
|
|
2864
2920
|
},
|
|
2865
2921
|
{
|
|
2866
2922
|
"kind": "method",
|
|
@@ -2871,7 +2927,7 @@
|
|
|
2871
2927
|
"text": "void"
|
|
2872
2928
|
}
|
|
2873
2929
|
},
|
|
2874
|
-
"description": "Destroy only the option tooltips (prefixed `option-`). Called before re-rendering or\
|
|
2930
|
+
"description": "Destroy only the option tooltips (prefixed `option-`). Called before re-rendering or\nrecycling the options list so per-option tooltip state doesn't leak."
|
|
2875
2931
|
},
|
|
2876
2932
|
{
|
|
2877
2933
|
"kind": "method",
|
|
@@ -2892,7 +2948,7 @@
|
|
|
2892
2948
|
"text": "void"
|
|
2893
2949
|
}
|
|
2894
2950
|
},
|
|
2895
|
-
"description": "Destroy only the action-button tooltips. Called from `renderDropdown`/`renderDropdownVirtual`\
|
|
2951
|
+
"description": "Destroy only the action-button tooltips. Called from `renderDropdown`/`renderDropdownVirtual`\nbefore rebuilding the actions row, so per-button tooltip state doesn't leak."
|
|
2896
2952
|
},
|
|
2897
2953
|
{
|
|
2898
2954
|
"kind": "method",
|
|
@@ -2903,7 +2959,7 @@
|
|
|
2903
2959
|
"text": "void"
|
|
2904
2960
|
}
|
|
2905
2961
|
},
|
|
2906
|
-
"description": "Destroy main-badges-container tooltips. Called before re-rendering the badges container.\
|
|
2962
|
+
"description": "Destroy main-badges-container tooltips. Called before re-rendering the badges container.\nPopover tooltips (prefixed `popover-`) survive — they're owned by the popover lifecycle and\ncleaned up in `hideSelectedPopover`. Action-button tooltips (prefixed `action-`) survive too."
|
|
2907
2963
|
},
|
|
2908
2964
|
{
|
|
2909
2965
|
"kind": "method",
|
|
@@ -3393,7 +3449,7 @@
|
|
|
3393
3449
|
"name": "inputs",
|
|
3394
3450
|
"privacy": "protected",
|
|
3395
3451
|
"static": true,
|
|
3396
|
-
"default": "[ // ── Strings (cosmetic → update). Optional ones are nullable: absent → null ─ { configKey: 'searchHint', attribute: 'search-hint', converter: toText({ isNullable: true }), on: 'update', description: 'Small hint text shown beneath the search input.' }, { configKey: 'searchPlaceholder', attribute: 'search-placeholder', converter: toText({ isNullable: true }), on: 'update', description: 'Placeholder text for the search input. When unset it defaults to \"Search...\"; if `show-search-mode-toggle` is on, the default instead becomes mode-aware (\"Search…\" in navigate, \"Filter…\" in filter). An explicit value always wins and stays fixed.' }, { configKey: 'selectPlaceholder', attribute: 'select-placeholder', converter: toText({ default: 'Pick an option...' }), on: 'update', description: 'Placeholder shown on the control when nothing is selected.' }, { configKey: 'noDataPlaceholder', attribute: 'no-data-placeholder', converter: toText({ isNullable: true }), on: 'update', description: 'Text shown when there are no options at all.' }, { configKey: 'dropdownMinWidth', attribute: 'dropdown-min-width', converter: toText({ isNullable: true }), on: 'update', description: 'Minimum width of the dropdown panel (any CSS length).' }, { configKey: 'dropdownMaxWidth', attribute: 'dropdown-max-width', converter: toText({ isNullable: true }), on: 'update', description: 'Maximum width of the dropdown panel (any CSS length).' }, { configKey: 'maxHeight', attribute: 'max-height', converter: toText({ default: '20rem' }), on: 'update', description: 'Maximum height of the dropdown list before it scrolls.' }, { configKey: 'emptyMessage', attribute: 'empty-message', converter: toText({ default: 'No results found' }), on: 'update', description: 'Message shown when a search yields no matches.' }, { configKey: 'loadingMessage', attribute: 'loading-message', converter: toText({ default: 'Loading...' }), on: 'update', description: 'Message shown while options are loading.' }, { configKey: 'removeButtonTooltipText', attribute: 'remove-button-tooltip-text', converter: toText({ isNullable: true }), on: 'update', description: 'Tooltip text for a badge remove (×) button.' }, { configKey: 'formFieldId', attribute: 'name', converter: toText({ isNullable: true }), on: 'reinit', description: 'HTML form field name/id used for the hidden input(s).' }, // ── CSS-var sugar (mirrored to a host style prop in reinit()/update()) ──── { configKey: 'dropdownWidth', attribute: 'dropdown-width', converter: toText({ isNullable: true }), on: 'update', description: 'Fixed dropdown width; mirrored to the `--ms-dropdown-width` CSS variable.' }, { configKey: 'selectedPopoverWidth', attribute: 'selected-popover-width', converter: toText({ isNullable: true }), on: 'update', description: 'Selected-items popover width; mirrored to `--ms-selected-popover-width`.' }, // ── Member properties (structural → reinit; optional → nullable) ───────── { configKey: 'valueMember', attribute: 'value-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name on an option object that holds its value.' }, { configKey: 'displayValueMember', attribute: 'display-value-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that holds an option display label.' }, { configKey: 'searchValueMember', attribute: 'search-value-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name searched against (falls back to the display value).' }, { configKey: 'iconMember', attribute: 'icon-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that holds an option icon.' }, { configKey: 'subtitleMember', attribute: 'subtitle-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that holds an option subtitle.' }, { configKey: 'fullTitleMember', attribute: 'full-title-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that holds an option full/long title.' }, { configKey: 'groupMember', attribute: 'group-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name used to group options under headers.' }, { configKey: 'disabledMember', attribute: 'disabled-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that marks an option disabled.' }, // ── Tree of options (structural → reinit; optional → nullable) ─────────── { configKey: 'pathMember', attribute: 'path-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name holding a node materialized tree path.' }, { configKey: 'parentPathMember', attribute: 'parent-path-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name holding a node parent path.' }, { configKey: 'levelMember', attribute: 'level-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name holding a node depth level.' }, { configKey: 'hasChildrenMember', attribute: 'has-children-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name flagging that a node has children.' }, { configKey: 'isSelectableMember', attribute: 'is-selectable-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name marking whether a node can be selected.' }, { configKey: 'treePathSeparator', attribute: 'tree-path-separator', converter: toText({ default: '.' }), reflect: true, on: 'reinit', description: 'Separator between segments in a materialized tree path.' }, { configKey: 'isTreeEnabled', converter: toBool('tristate'), on: 'reinit', type: 'boolean', description: 'Force tree mode on/off. Property-only; when unset (null) tree mode auto-enables if a path source (path-member / getPathCallback) is present.' }, { configKey: 'checkboxMode', attribute: 'checkbox-mode', converter: toEnum(['independent', 'cascade'] as const, { default: 'independent' }), reflect: true, on: 'update', description: `Tree checkbox interaction. - \\`independent\\` (default) — toggles only the clicked node. - \\`cascade\\` — checks a node whole subtree and shows a tristate (checked / indeterminate / unchecked) box on branches. Tree + multiple only.` }, { configKey: 'cascadeSelectPolicy', attribute: 'cascade-select-policy', converter: toEnum(['rolled-up', 'leaves', 'all'] as const, { default: 'rolled-up' }), reflect: true, on: 'update', description: `In \\`cascade\\` mode, which values a selection emits (badges / form / change): - \\`rolled-up\\` (default) — minimal cover: a fully-selected subtree collapses to its root; partially-selected branches emit their individually-checked descendants. - \\`leaves\\` — only the checked leaf-level nodes. - \\`all\\` — every fully-checked node (branches and leaves).` }, // ── Enums ──────────────────────────────────────────────────────────────── { configKey: 'badgesDisplayMode', attribute: 'badges-display-mode', converter: toEnum(['badges', 'count', 'compact', 'partial', 'none'] as const, { default: 'badges' }), on: 'reinit', description: 'How the current selection is shown in the control.' }, { configKey: 'badgesPosition', attribute: 'badges-position', converter: toEnum(['top', 'bottom', 'left', 'right'] as const, { default: 'bottom' }), on: 'reinit', description: 'Where the badges/selection appear relative to the input.' }, { configKey: 'badgesThresholdMode', attribute: 'badges-threshold-mode', converter: toEnum(['count', 'partial'] as const, { default: 'count' }), on: 'update', description: 'How `badgesThreshold` is interpreted: collapse to a count badge, or keep partial badges + a \"more\" badge.' }, { configKey: 'searchInputMode', attribute: 'search-input-mode', converter: toEnum(['normal', 'readonly', 'hidden'] as const, { default: 'normal' }), on: 'reinit', description: 'Search field mode: editable, read-only, or hidden.' }, { configKey: 'searchMode', attribute: 'search-mode', converter: toEnum(['filter', 'navigate'] as const, { default: 'filter' }), on: 'reinit', description: 'Whether typing filters the list or navigates it.' }, { configKey: 'actionsLayout', attribute: 'actions-layout', converter: toEnum(['nowrap', 'wrap'] as const, { default: 'nowrap' }), on: 'reinit', description: 'Whether the action bar wraps or stays on one line.' }, { configKey: 'actionsPosition', attribute: 'actions-position', converter: toEnum(['top', 'bottom'] as const, { default: 'top' }), on: 'reinit', description: 'Whether the action bar sits above or below the list.' }, { configKey: 'actionsAlign', attribute: 'actions-align', converter: toEnum(['stretch', 'left', 'right', 'center', 'space-between'] as const, { default: 'stretch' }), on: 'update', description: 'Horizontal alignment of the action buttons.' }, { configKey: 'checkboxAlign', attribute: 'checkbox-align', converter: toEnum(['top', 'center', 'bottom'] as const, { default: 'center' }), on: 'update', description: 'Vertical alignment of an option checkbox.' }, { configKey: 'valueFormat', attribute: 'value-format', converter: toEnum(['json', 'csv', 'array'] as const, { default: 'json' }), on: 'reinit', description: 'Serialization format the control emits its value in.' }, { configKey: 'badgeTooltipPlacement', attribute: 'badge-tooltip-placement', converter: toEnum(PLACEMENTS, { default: 'top' }), on: 'update', description: 'Preferred placement of a badge tooltip relative to its badge (floating-ui placement).' }, { configKey: 'optionTooltipPlacement', attribute: 'option-tooltip-placement', converter: toEnum(PLACEMENTS, { default: 'top-start' }), on: 'update', description: 'Preferred placement of an option tooltip (floating-ui placement).' }, { configKey: 'mobilePresentation', attribute: 'mobile-presentation', converter: toEnum(['auto', 'floating', 'fullscreen'] as const, { default: 'auto' }), reflect: true, on: 'update', description: 'How the open dropdown is presented on phones. `auto` (default) keeps the floating panel on desktop/tablet and switches to a full-screen overlay on phone-sized touch devices (touch primary + shorter viewport side < 600px, orientation-robust); `floating` forces the anchored panel everywhere; `fullscreen` forces the full-screen overlay on any device (handy for previews/testing). Resolved reactively from the device/viewport environment.' }, { configKey: 'fullscreenAutofocus', attribute: 'fullscreen-autofocus', converter: toBool('default-false'), on: 'update', description: 'In the phone fullscreen overlay, auto-focus the search field on open (pops the soft keyboard immediately). Default `false`: the sheet opens with the list visible and the keyboard closed, appearing only when the user taps the search. Set `true` to type-to-filter right away. No effect in the floating presentation.' }, // ── Numbers ────────────────────────────────────────────────────────────── { configKey: 'badgesThreshold', attribute: 'badges-threshold', converter: toInt(), on: 'update', description: 'Threshold at which badges collapse to a count/compact view.' }, { configKey: 'badgesMaxVisible', attribute: 'badges-max-visible', converter: toInt(), on: 'update', description: 'Maximum number of badges rendered before overflow.' }, { configKey: 'collapseBadgesBelow', attribute: 'collapse-badges-below', converter: toInt(), on: 'update', description: 'Container-responsive opt-in (off by default). When set to a px width, the control watches its OWN border box (not the window, via the core `resized` hook / a shared ResizeObserver) and collapses `badges-display-mode` to `count` (\"N selected\") while the box is narrower than this — so a picker in a narrow column/sidebar never overflows with pills, even on a wide monitor. Widening past the threshold restores the configured badges mode. Element-only: the override is applied to the live picker, never to your `badges-display-mode` config.' }, { configKey: 'minSearchLength', attribute: 'min-search-length', converter: toInt({ default: 0 }), on: 'update', description: 'Minimum characters before searching/filtering starts.' }, { configKey: 'searchDebounce', attribute: 'search-debounce', converter: toInt({ default: 0 }), on: 'update', description: 'Debounce delay in ms applied to the search input.' }, { configKey: 'virtualScrollThreshold', attribute: 'virtual-scroll-threshold', converter: toInt({ default: 100 }), on: 'reinit', description: 'Option count above which virtual scrolling turns on.' }, { configKey: 'optionHeight', attribute: 'option-height', converter: toInt({ default: 50 }), on: 'update', description: 'Fixed row height in px used by virtual scrolling.' }, { configKey: 'badgeHeight', attribute: 'badge-height', converter: toInt({ default: 36 }), on: 'update', description: 'Fixed badge height in px used for layout/virtualization.' }, { configKey: 'virtualScrollBuffer', attribute: 'virtual-scroll-buffer', converter: toInt({ default: 10 }), on: 'update', description: 'Extra rows rendered above/below the viewport when virtualizing.' }, { configKey: 'badgeTooltipDelay', attribute: 'badge-tooltip-delay', converter: toInt({ default: 100 }), on: 'update', description: 'Delay in ms before a badge tooltip appears.' }, { configKey: 'badgeTooltipOffset', attribute: 'badge-tooltip-offset', converter: toInt({ default: 8 }), on: 'update', description: 'Gap in px between a badge and its tooltip.' }, { configKey: 'optionTooltipDelay', attribute: 'option-tooltip-delay', converter: toInt(), on: 'update', description: 'Delay in ms before an option tooltip appears (falls back to badgeTooltipDelay).' }, { configKey: 'optionTooltipOffset', attribute: 'option-tooltip-offset', converter: toInt(), on: 'update', description: 'Gap in px between an option and its tooltip.' }, // ── Booleans (default true) ────────────────────────────────────────────── { configKey: 'isMultipleEnabled', attribute: 'multiple', converter: toBool('default-true'), on: 'reinit', description: 'Allow selecting multiple options. When off, selecting one replaces the previous.' }, { configKey: 'isGroupsAllowed', attribute: 'allow-groups', converter: toBool('default-true'), on: 'reinit', description: 'Allow grouping options under group headers.' }, { configKey: 'isCheckboxesShown', attribute: 'show-checkboxes', converter: toBool('default-true'), on: 'reinit', description: 'Show a checkbox on each option.' }, { configKey: 'isActionsSticky', attribute: 'sticky-actions', converter: toBool('default-true'), on: 'update', description: 'Keep the action bar pinned while the list scrolls.' }, { configKey: 'isPlacementLocked', attribute: 'lock-placement', converter: toBool('default-true'), on: 'update', description: 'Keep the dropdown initial placement instead of flipping when it fits.' }, { configKey: 'isSearchEnabled', attribute: 'enable-search', converter: toBool('default-true'), on: 'reinit', description: 'Show the search input.' }, { configKey: 'isKeepOptionsOnSearch', attribute: 'keep-options-on-search', converter: toBool('default-true'), on: 'update', description: 'Keep already-selected options visible while filtering.' }, { configKey: 'shouldKeepSearchOnClose', attribute: 'should-keep-search-on-close', converter: toBool('default-true'), on: 'update', description: 'Preserve the search text after the dropdown closes.' }, { configKey: 'isSelectedPopoverEnabled', attribute: 'enable-selected-popover', converter: toBool('default-true'), on: 'update', description: 'Allow the selected-items popover to open (from the count/compact/\"+X more\" badge or the in-input counter). Turn off when you render your own selection UI, so those affordances become inert.' }, // ── Booleans (default false) ───────────────────────────────────────────── { configKey: 'isCloseOnSelect', attribute: 'close-on-select', converter: toBool('default-false'), on: 'update', description: 'Close the dropdown immediately after a selection.' }, { configKey: 'isAddNewAllowed', attribute: 'allow-add-new', converter: toBool('default-false'), on: 'reinit', description: 'Allow adding a new option from the search text.' }, { configKey: 'isCounterShown', attribute: 'show-counter', converter: toBool('default-false'), on: 'update', description: 'Show a selected-count indicator.' }, { configKey: 'isBadgeFullTitleShown', attribute: 'show-badge-full-title', converter: toBool('default-false'), on: 'update', description: 'Show the full title on badges instead of the short label.' }, { configKey: 'isVirtualScrollEnabled', attribute: 'enable-virtual-scroll', converter: toBool('default-false'), on: 'reinit', description: 'Force virtual scrolling on regardless of the threshold.' }, { configKey: 'isBadgeTooltipsEnabled', attribute: 'enable-badge-tooltips', converter: toBool('default-false'), on: 'update', description: 'Enable tooltips on badges.' }, { configKey: 'isOptionTooltipsEnabled', attribute: 'enable-option-tooltips', converter: toBool('default-false'), on: 'update', description: 'Enable tooltips on options.' }, { configKey: 'isOptionTooltipFollowCursor', attribute: 'option-tooltip-follow-cursor', converter: toBool('default-false'), on: 'update', description: 'Make option tooltips follow the pointer.' }, { configKey: 'isSearchModeToggleShown', attribute: 'show-search-mode-toggle', converter: toBool('default-false'), on: 'update', description: 'Show a clickable toggle in the phone fullscreen overlay search header that flips `search-mode` between `filter` and `navigate` live. Fullscreen-only; no effect in the floating presentation or when search is disabled.' }, // ── Special attributes ─────────────────────────────────────────────────── { configKey: 'initialValues', attribute: 'initial-values', converter: toInitialValues(), default: [], on: 'reinit', type: 'Array<string | number>', description: 'Values selected on first render. Accepts a JSON array (`[\"a\",\"b\"]`) or a bare CSV (`a,b,c`).' }, { configKey: 'showDebugInfo', attribute: 'show-debug-info', converter: toBool('default-false'), on: 'update', description: 'Render an in-component debug panel.', deprecated: 'Use per-instance logging (el.enableLogging()) instead.' }, // ── Complex property (data) ────────────────────────────────────────────── { configKey: 'options', converter: toObjectArray(), on: 'reinit', type: 'ReadonlyArray<Record<string, unknown>>', description: 'The array of option objects to render. The JS API — assign `el.options` directly. For HTML authoring use the `data-options` attribute (parsed per `data-options-format`) or declarative <option> children; both feed the same list and take precedence over this property in the order: <option> children > property > data-options.' }, { configKey: 'optionsSource', attribute: 'data-options', converter: toText({ isNullable: true }), on: 'reinit', type: 'string', description: 'HTML-authoring source for the option list, parsed per `data-options-format`. Reactive: changing either attribute re-renders. Prefer the `options` property in JS; a set `options` property and declarative <option> children both win over this.' }, { configKey: 'optionsFormat', attribute: 'data-options-format', converter: toEnum(OPTIONS_FORMATS, { default: 'json' }), on: 'reinit', type: \"'json' | 'csv' | 'plain'\", description: 'How to parse the `data-options` attribute: `json` (a JSON array of objects or [value, label] tuples), `csv` (rows split on `data-options-row-splitter`, cells on `data-options-splitter`; the first row is a header — map columns via *-member), or `plain` (bare values split on both splitters -> [value, label] tuples, value === label). Default `json`.' }, { configKey: 'optionsSplitter', attribute: 'data-options-splitter', converter: toText({ default: ',' }), on: 'reinit', type: 'string', description: 'Field/cell delimiter for the `csv` and `plain` `data-options` formats. Default `,`. Escapes `\\\\t` `\\\\n` `\\\\r` are honoured (e.g. `data-options-splitter=\"\\\\t\"` for TSV). Ignored for `json`.' }, { configKey: 'optionsRowSplitter', attribute: 'data-options-row-splitter', converter: toText({ default: '\\n' }), on: 'reinit', type: 'string', description: 'Row/record delimiter for the `csv` and `plain` `data-options` formats. Default newline. Escapes honoured (e.g. `data-options-row-splitter=\";\"` for single-line data). Ignored for `json`.' }, { configKey: 'actionButtons', converter: toValue({ validate: (v): v is unknown[] => Array.isArray(v) }), on: 'reinit', type: 'Array<Record<string, unknown>>', description: 'Custom action buttons for the dropdown footer/header. Property-only; when unset the default Select-All / Clear buttons apply.' }, // ── Callbacks: data shape (structural → reinit) ────────────────────────── { configKey: 'getValueCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => string | number', description: 'Extract an option value (overrides valueMember).' }, { configKey: 'getPathCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => string', description: 'Extract a node tree path (enables tree mode; overrides pathMember).' }, { configKey: 'getGroupCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => string', description: 'Extract the group name from an option (overrides groupMember).' }, { configKey: 'getDisabledCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => boolean', description: 'Whether an option is disabled (overrides disabledMember).' }, { configKey: 'getIsSelectableCallback', converter: cb(), on: 'reinit', type: '(node: unknown) => boolean', description: 'Whether a tree node can be selected (overrides is-selectable-member).' }, { configKey: 'getSearchValueCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => string', description: 'Text an option is searched against (overrides searchValueMember).' }, { configKey: 'searchCallback', converter: cb(), on: 'reinit', type: '(searchTerm: string, signal?: AbortSignal) => Promise<unknown[]>', description: 'Custom / async search; return the filtered options.' }, // ── Callbacks: display / render (cosmetic → update) ────────────────────── { configKey: 'getDisplayValueCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Compute the display label for an option (overrides displayValueMember).' }, { configKey: 'getBadgeDisplayCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Compute the text shown on an option badge.' }, { configKey: 'getBadgeClassCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | string[]', description: 'Extra CSS class(es) for an option badge.' }, { configKey: 'getIconCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Icon for an option (overrides iconMember).' }, { configKey: 'getSubtitleCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Subtitle for an option (overrides subtitleMember).' }, { configKey: 'getFullTitleCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Full title for an option (used by badges when show-badge-full-title is on).' }, { configKey: 'getCounterCallback', converter: cb(), on: 'update', type: '(count: number, moreCount?: number) => string', description: 'Render the selected-count label.' }, { configKey: 'getValueFormatCallback', converter: cb(), on: 'update', type: '(selectedValues: (string | number)[]) => string', description: 'Serialize the selected values for form submission.' }, { configKey: 'getBadgeTooltipCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | HTMLElement', description: 'Tooltip content for an option badge.' }, { configKey: 'getOptionTooltipCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | HTMLElement', description: 'Tooltip content for an option row.' }, { configKey: 'getRemoveButtonTooltipCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Tooltip text for a badge remove button.' }, { configKey: 'getSelectedItemClassCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | string[]', description: 'Extra CSS class(es) for a selected item.' }, { configKey: 'renderOptionContentCallback', converter: cb(), on: 'update', type: '(item: unknown, context: OptionContentRenderContext) => string | HTMLElement', description: 'Custom render for an option row; may return HTML or an element.' }, { configKey: 'renderBadgeContentCallback', converter: cb(), on: 'update', type: '(item: unknown, context: BadgeContentRenderContext) => string | HTMLElement', description: 'Custom render for a badge content (fills the built-in pill); may return HTML or an element.' }, { configKey: 'renderBadgeCallback', converter: cb(), on: 'update', type: '(item: unknown, context: BadgeContentRenderContext) => string | HTMLElement | null', description: 'Custom render for the WHOLE badge (main area), not just its content — return the entire pill/card. The component wraps it in `.ms__badge.ms__badge--custom` with `data-value` and delegates removal to any inner element with `data-action=\"remove\"` (or `.ms__badge-remove`). Return null/empty to fall back to the default pill for that item.' }, { configKey: 'renderGroupLabelContentCallback', converter: cb(), on: 'update', type: '(groupName: string) => string | HTMLElement', description: 'Customize a group label; may return an HTML string or element.' }, { configKey: 'renderSelectedContentCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Custom render for the whole selected area.' }, { configKey: 'renderSelectedItemContentCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | HTMLElement', description: 'Custom render for one selected item.' }, { configKey: 'customStylesCallback', converter: cb(), on: 'update', type: '() => string', description: 'Returns a CSS string injected into the component via a replaceable style slot (§12.8).' }, // ── Callbacks: before-hooks (behavior-shaping) ─────────────────────────── { configKey: 'beforeSearchCallback', converter: cb(), on: 'update', type: '(searchTerm: string) => string | null', description: 'Runs before a search; return a rewritten term or null to veto.' }, { configKey: 'beforeSelectCallback', converter: cb(), on: 'update', type: '(option: unknown, selectedOptions: unknown[]) => boolean | string | void', description: 'Runs before selecting; return false to veto, or a string to veto and show it as a message.' }, { configKey: 'beforeDeselectCallback', converter: cb(), on: 'update', type: '(option: unknown, selectedOptions: unknown[]) => boolean | string | void', description: 'Runs before deselecting; return false to veto, or a string to veto and show it as a message.' }, { configKey: 'addNewCallback', converter: cb(), on: 'update', type: '(value: string) => unknown | Promise<unknown>', description: 'Create a new option from the typed text.' }, { configKey: 'keydownCallback', converter: cb(), on: 'update', type: '(context: MultiSelectKeydownContext) => boolean | void', description: 'Intercept keydown before built-in handling; return true to suppress the default. Gets the event, current state, and an imperative controller.' }, ]",
|
|
3452
|
+
"default": "[ // ── Strings (cosmetic → update). Optional ones are nullable: absent → null ─ { configKey: 'searchHint', attribute: 'search-hint', converter: toText({ isNullable: true }), on: 'update', description: 'Small hint text shown beneath the search input.' }, { configKey: 'searchPlaceholder', attribute: 'search-placeholder', converter: toText({ isNullable: true }), on: 'update', description: 'Placeholder text for the search input. When unset it defaults to \"Search...\"; if `show-search-mode-toggle` is on, the default instead becomes mode-aware (\"Search…\" in navigate, \"Filter…\" in filter). An explicit value always wins and stays fixed.' }, { configKey: 'selectPlaceholder', attribute: 'select-placeholder', converter: toText({ default: 'Pick an option...' }), on: 'update', description: 'Placeholder shown on the control when nothing is selected.' }, { configKey: 'noDataPlaceholder', attribute: 'no-data-placeholder', converter: toText({ isNullable: true }), on: 'update', description: 'Text shown when there are no options at all.' }, { configKey: 'dropdownMinWidth', attribute: 'dropdown-min-width', converter: toText({ isNullable: true }), on: 'update', description: 'Minimum width of the dropdown panel (any CSS length).' }, { configKey: 'dropdownMaxWidth', attribute: 'dropdown-max-width', converter: toText({ isNullable: true }), on: 'update', description: 'Maximum width of the dropdown panel (any CSS length).' }, { configKey: 'maxHeight', attribute: 'max-height', converter: toText({ default: '20rem' }), on: 'update', description: 'Maximum height of the dropdown list before it scrolls.' }, { configKey: 'emptyMessage', attribute: 'empty-message', converter: toText({ default: 'No results found' }), on: 'update', description: 'Message shown when a search yields no matches.' }, { configKey: 'loadingMessage', attribute: 'loading-message', converter: toText({ default: 'Loading...' }), on: 'update', description: 'Message shown while options are loading.' }, { configKey: 'removeButtonTooltipText', attribute: 'remove-button-tooltip-text', converter: toText({ isNullable: true }), on: 'update', description: 'Tooltip text for a badge remove (×) button.' }, { configKey: 'formFieldId', attribute: 'name', converter: toText({ isNullable: true }), on: 'reinit', description: 'HTML form field name/id used for the hidden input(s).' }, // ── CSS-var sugar (mirrored to a host style prop in reinit()/update()) ──── { configKey: 'dropdownWidth', attribute: 'dropdown-width', converter: toText({ isNullable: true }), on: 'update', description: 'Fixed dropdown width; mirrored to the `--ms-dropdown-width` CSS variable.' }, { configKey: 'selectedPopoverWidth', attribute: 'selected-popover-width', converter: toText({ isNullable: true }), on: 'update', description: 'Selected-items popover width; mirrored to `--ms-selected-popover-width`.' }, // ── Member properties (structural → reinit; optional → nullable) ───────── { configKey: 'valueMember', attribute: 'value-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name on an option object that holds its value.' }, { configKey: 'displayValueMember', attribute: 'display-value-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that holds an option display label.' }, { configKey: 'searchValueMember', attribute: 'search-value-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name searched against (falls back to the display value).' }, { configKey: 'iconMember', attribute: 'icon-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that holds an option icon.' }, { configKey: 'subtitleMember', attribute: 'subtitle-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that holds an option subtitle.' }, { configKey: 'fullTitleMember', attribute: 'full-title-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that holds an option full/long title.' }, { configKey: 'groupMember', attribute: 'group-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name used to group options under headers.' }, { configKey: 'disabledMember', attribute: 'disabled-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name that marks an option disabled.' }, // ── Tree of options (structural → reinit; optional → nullable) ─────────── { configKey: 'pathMember', attribute: 'path-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name holding a node materialized tree path.' }, { configKey: 'parentPathMember', attribute: 'parent-path-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name holding a node parent path.' }, { configKey: 'levelMember', attribute: 'level-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name holding a node depth level.' }, { configKey: 'hasChildrenMember', attribute: 'has-children-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name flagging that a node has children.' }, { configKey: 'isSelectableMember', attribute: 'is-selectable-member', converter: toText({ isNullable: true }), reflect: true, on: 'reinit', description: 'Property name marking whether a node can be selected.' }, { configKey: 'treePathSeparator', attribute: 'tree-path-separator', converter: toText({ default: '.' }), reflect: true, on: 'reinit', description: 'Separator between segments in a materialized tree path.' }, { configKey: 'isTreeEnabled', converter: toBool('tristate'), on: 'reinit', type: 'boolean', description: 'Force tree mode on/off. Property-only; when unset (null) tree mode auto-enables if a path source (path-member / getPathCallback) is present.' }, { configKey: 'checkboxMode', attribute: 'checkbox-mode', converter: toEnum(['independent', 'cascade'] as const, { default: 'independent' }), reflect: true, on: 'update', description: `Tree checkbox interaction. - \\`independent\\` (default) — toggles only the clicked node. - \\`cascade\\` — checks a node whole subtree and shows a tristate (checked / indeterminate / unchecked) box on branches. Tree + multiple only.` }, { configKey: 'cascadeSelectPolicy', attribute: 'cascade-select-policy', converter: toEnum(['rolled-up', 'leaves', 'all'] as const, { default: 'rolled-up' }), reflect: true, on: 'update', description: `In \\`cascade\\` mode, which values a selection emits (badges / form / change): - \\`rolled-up\\` (default) — minimal cover: a fully-selected subtree collapses to its root; partially-selected branches emit their individually-checked descendants. - \\`leaves\\` — only the checked leaf-level nodes. - \\`all\\` — every fully-checked node (branches and leaves).` }, // ── Enums ──────────────────────────────────────────────────────────────── { configKey: 'badgesDisplayMode', attribute: 'badges-display-mode', converter: toEnum(['badges', 'count', 'compact', 'partial', 'none'] as const, { default: 'badges' }), on: 'reinit', description: 'How the current selection is shown in the control.' }, { configKey: 'badgesPosition', attribute: 'badges-position', converter: toEnum(['top', 'bottom', 'left', 'right'] as const, { default: 'bottom' }), on: 'reinit', description: 'Where the badges/selection appear relative to the input.' }, { configKey: 'badgesThresholdMode', attribute: 'badges-threshold-mode', converter: toEnum(['count', 'partial'] as const, { default: 'count' }), on: 'update', description: 'How `badgesThreshold` is interpreted: collapse to a count badge, or keep partial badges + a \"more\" badge.' }, { configKey: 'searchInputMode', attribute: 'search-input-mode', converter: toEnum(['normal', 'readonly', 'hidden'] as const, { default: 'normal' }), on: 'reinit', description: 'Search field mode: editable, read-only, or hidden.' }, { configKey: 'searchMode', attribute: 'search-mode', converter: toEnum(['filter', 'navigate'] as const, { default: 'filter' }), on: 'reinit', description: 'Whether typing filters the list or navigates it.' }, { configKey: 'actionsLayout', attribute: 'actions-layout', converter: toEnum(['nowrap', 'wrap'] as const, { default: 'nowrap' }), on: 'reinit', description: 'Whether the action bar wraps or stays on one line.' }, { configKey: 'actionsPosition', attribute: 'actions-position', converter: toEnum(['top', 'bottom'] as const, { default: 'top' }), on: 'reinit', description: 'Whether the action bar sits above or below the list.' }, { configKey: 'actionsAlign', attribute: 'actions-align', converter: toEnum(['stretch', 'left', 'right', 'center', 'space-between'] as const, { default: 'stretch' }), on: 'update', description: 'Horizontal alignment of the action buttons.' }, { configKey: 'checkboxAlign', attribute: 'checkbox-align', converter: toEnum(['top', 'center', 'bottom'] as const, { default: 'center' }), on: 'update', description: 'Vertical alignment of an option checkbox.' }, { configKey: 'valueFormat', attribute: 'value-format', converter: toEnum(['json', 'csv', 'array'] as const, { default: 'json' }), on: 'reinit', description: 'Serialization format the control emits its value in.' }, { configKey: 'badgeTooltipPlacement', attribute: 'badge-tooltip-placement', converter: toEnum(PLACEMENTS, { default: 'top' }), on: 'update', description: 'Preferred placement of a badge tooltip relative to its badge (floating-ui placement).' }, { configKey: 'optionTooltipPlacement', attribute: 'option-tooltip-placement', converter: toEnum(PLACEMENTS, { default: 'top-start' }), on: 'update', description: 'Preferred placement of an option tooltip (floating-ui placement).' }, { configKey: 'mobilePresentation', attribute: 'mobile-presentation', converter: toEnum(['auto', 'floating', 'fullscreen'] as const, { default: 'auto' }), reflect: true, on: 'update', description: 'How the open dropdown is presented on phones. `auto` (default) keeps the floating panel on desktop/tablet and switches to a full-screen overlay on phone-sized touch devices (touch primary + shorter viewport side < 600px, orientation-robust); `floating` forces the anchored panel everywhere; `fullscreen` forces the full-screen overlay on any device (handy for previews/testing). Resolved reactively from the device/viewport environment.' }, { configKey: 'fullscreenAutofocus', attribute: 'fullscreen-autofocus', converter: toBool('default-false'), on: 'update', description: 'In the phone fullscreen overlay, auto-focus the search field on open (pops the soft keyboard immediately). Default `false`: the sheet opens with the list visible and the keyboard closed, appearing only when the user taps the search. Set `true` to type-to-filter right away. No effect in the floating presentation.' }, // ── Numbers ────────────────────────────────────────────────────────────── { configKey: 'badgesThreshold', attribute: 'badges-threshold', converter: toInt(), on: 'update', description: 'Threshold at which badges collapse to a count/compact view.' }, { configKey: 'badgesMaxVisible', attribute: 'badges-max-visible', converter: toInt(), on: 'update', description: 'Maximum number of badges rendered before overflow.' }, { configKey: 'collapseBadgesBelow', attribute: 'collapse-badges-below', converter: toInt(), on: 'update', description: 'Container-responsive opt-in (off by default). When set to a px width, the control watches its OWN border box (not the window, via the core `resized` hook / a shared ResizeObserver) and collapses `badges-display-mode` to `count` (\"N selected\") while the box is narrower than this — so a picker in a narrow column/sidebar never overflows with pills, even on a wide monitor. Widening past the threshold restores the configured badges mode. Element-only: the override is applied to the live picker, never to your `badges-display-mode` config.' }, { configKey: 'minSearchLength', attribute: 'min-search-length', converter: toInt({ default: 0 }), on: 'update', description: 'Minimum characters before searching/filtering starts.' }, { configKey: 'searchDebounce', attribute: 'search-debounce', converter: toInt({ default: 0 }), on: 'update', description: 'Debounce delay in ms applied to the search input.' }, { configKey: 'virtualScrollThreshold', attribute: 'virtual-scroll-threshold', converter: toInt({ default: 100 }), on: 'reinit', description: 'Option count above which virtual scrolling turns on.' }, { configKey: 'optionHeight', attribute: 'option-height', converter: toInt({ default: 50 }), on: 'update', description: 'Fixed row height in px used by virtual scrolling.' }, { configKey: 'badgeHeight', attribute: 'badge-height', converter: toInt({ default: 36 }), on: 'update', description: 'Fixed badge height in px used for layout/virtualization.' }, { configKey: 'virtualScrollBuffer', attribute: 'virtual-scroll-buffer', converter: toInt({ default: 10 }), on: 'update', description: 'Extra rows rendered above/below the viewport when virtualizing.' }, { configKey: 'badgeTooltipDelay', attribute: 'badge-tooltip-delay', converter: toInt({ default: 100 }), on: 'update', description: 'Delay in ms before a badge tooltip appears.' }, { configKey: 'badgeTooltipOffset', attribute: 'badge-tooltip-offset', converter: toInt({ default: 8 }), on: 'update', description: 'Gap in px between a badge and its tooltip.' }, { configKey: 'optionTooltipDelay', attribute: 'option-tooltip-delay', converter: toInt(), on: 'update', description: 'Delay in ms before an option tooltip appears (falls back to badgeTooltipDelay).' }, { configKey: 'optionTooltipOffset', attribute: 'option-tooltip-offset', converter: toInt(), on: 'update', description: 'Gap in px between an option and its tooltip.' }, // ── Booleans (default true) ────────────────────────────────────────────── { configKey: 'isMultipleEnabled', attribute: 'multiple', converter: toBool('default-true'), on: 'reinit', description: 'Allow selecting multiple options. When off, selecting one replaces the previous.' }, { configKey: 'isGroupsAllowed', attribute: 'allow-groups', converter: toBool('default-true'), on: 'reinit', description: 'Allow grouping options under group headers.' }, { configKey: 'isCheckboxesShown', attribute: 'show-checkboxes', converter: toBool('default-true'), on: 'reinit', description: 'Show a checkbox on each option.' }, { configKey: 'isActionsSticky', attribute: 'sticky-actions', converter: toBool('default-true'), on: 'update', description: 'Keep the action bar pinned while the list scrolls.' }, { configKey: 'isPlacementLocked', attribute: 'lock-placement', converter: toBool('default-true'), on: 'update', description: 'Keep the dropdown initial placement instead of flipping when it fits.' }, { configKey: 'isSearchEnabled', attribute: 'enable-search', converter: toBool('default-true'), on: 'reinit', description: 'Show the search input.' }, { configKey: 'isKeepOptionsOnSearch', attribute: 'keep-options-on-search', converter: toBool('default-true'), on: 'update', description: 'Keep already-selected options visible while filtering.' }, { configKey: 'shouldKeepSearchOnClose', attribute: 'should-keep-search-on-close', converter: toBool('default-true'), on: 'update', description: 'Preserve the search text after the dropdown closes.' }, { configKey: 'isSelectedPopoverEnabled', attribute: 'enable-selected-popover', converter: toBool('default-true'), on: 'update', description: 'Allow the selected-items popover to open (from the count/compact/\"+X more\" badge or the in-input counter). Turn off when you render your own selection UI, so those affordances become inert.' }, // ── Booleans (default false) ───────────────────────────────────────────── { configKey: 'isCloseOnSelect', attribute: 'close-on-select', converter: toBool('default-false'), on: 'update', description: 'Close the dropdown immediately after a selection.' }, { configKey: 'isAddNewAllowed', attribute: 'allow-add-new', converter: toBool('default-false'), on: 'reinit', description: 'Allow adding a new option from the search text.' }, { configKey: 'isCounterShown', attribute: 'show-counter', converter: toBool('default-false'), on: 'update', description: 'Show a selected-count indicator.' }, { configKey: 'isClearShown', attribute: 'show-clear', converter: toBool('default-false'), on: 'update', description: 'Show an inline clear (✕) button inside the input that wipes the whole selection. Appears only while something is selected and the control is enabled; clicking it clears the selection and any search text, fires `change`, and refocuses.' }, { configKey: 'isBadgeFullTitleShown', attribute: 'show-badge-full-title', converter: toBool('default-false'), on: 'update', description: 'Show the full title on badges instead of the short label.' }, { configKey: 'isVirtualScrollEnabled', attribute: 'enable-virtual-scroll', converter: toBool('default-false'), on: 'reinit', description: 'Force virtual scrolling on regardless of the threshold.' }, { configKey: 'isBadgeTooltipsEnabled', attribute: 'enable-badge-tooltips', converter: toBool('default-false'), on: 'update', description: 'Enable tooltips on badges.' }, { configKey: 'isOptionTooltipsEnabled', attribute: 'enable-option-tooltips', converter: toBool('default-false'), on: 'update', description: 'Enable tooltips on options.' }, { configKey: 'isOptionTooltipFollowCursor', attribute: 'option-tooltip-follow-cursor', converter: toBool('default-false'), on: 'update', description: 'Make option tooltips follow the pointer.' }, { configKey: 'isSearchModeToggleShown', attribute: 'show-search-mode-toggle', converter: toBool('default-false'), on: 'update', description: 'Show a clickable toggle in the phone fullscreen overlay search header that flips `search-mode` between `filter` and `navigate` live. Fullscreen-only; no effect in the floating presentation or when search is disabled.' }, // ── Special attributes ─────────────────────────────────────────────────── { configKey: 'initialValues', attribute: 'initial-values', converter: toInitialValues(), default: [], on: 'reinit', type: 'Array<string | number>', description: 'Values selected on first render. Accepts a JSON array (`[\"a\",\"b\"]`) or a bare CSV (`a,b,c`).' }, { configKey: 'showDebugInfo', attribute: 'show-debug-info', converter: toBool('default-false'), on: 'update', description: 'Render an in-component debug panel.', deprecated: 'Use per-instance logging (el.enableLogging()) instead.' }, // ── Complex property (data) ────────────────────────────────────────────── { configKey: 'options', converter: toObjectArray(), on: 'reinit', type: 'ReadonlyArray<Record<string, unknown>>', description: 'The array of option objects to render. The JS API — assign `el.options` directly. For HTML authoring use the `data-options` attribute (parsed per `data-options-format`) or declarative <option> children; both feed the same list and take precedence over this property in the order: <option> children > property > data-options.' }, { configKey: 'optionsSource', attribute: 'data-options', converter: toText({ isNullable: true }), on: 'reinit', type: 'string', description: 'HTML-authoring source for the option list, parsed per `data-options-format`. Reactive: changing either attribute re-renders. Prefer the `options` property in JS; a set `options` property and declarative <option> children both win over this.' }, { configKey: 'optionsFormat', attribute: 'data-options-format', converter: toEnum(OPTIONS_FORMATS, { default: 'json' }), on: 'reinit', type: \"'json' | 'csv' | 'plain'\", description: 'How to parse the `data-options` attribute: `json` (a JSON array of objects or [value, label] tuples), `csv` (rows split on `data-options-row-splitter`, cells on `data-options-splitter`; the first row is a header — map columns via *-member), or `plain` (bare values split on both splitters -> [value, label] tuples, value === label). Default `json`.' }, { configKey: 'optionsSplitter', attribute: 'data-options-splitter', converter: toText({ default: ',' }), on: 'reinit', type: 'string', description: 'Field/cell delimiter for the `csv` and `plain` `data-options` formats. Default `,`. Escapes `\\\\t` `\\\\n` `\\\\r` are honoured (e.g. `data-options-splitter=\"\\\\t\"` for TSV). Ignored for `json`.' }, { configKey: 'optionsRowSplitter', attribute: 'data-options-row-splitter', converter: toText({ default: '\\n' }), on: 'reinit', type: 'string', description: 'Row/record delimiter for the `csv` and `plain` `data-options` formats. Default newline. Escapes honoured (e.g. `data-options-row-splitter=\";\"` for single-line data). Ignored for `json`.' }, { configKey: 'actionButtons', converter: toValue({ validate: (v): v is unknown[] => Array.isArray(v) }), on: 'reinit', type: 'Array<Record<string, unknown>>', description: 'Custom action buttons for the dropdown footer/header. Property-only; when unset the default Select-All / Clear buttons apply.' }, // ── Callbacks: data shape (structural → reinit) ────────────────────────── { configKey: 'getValueCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => string | number', description: 'Extract an option value (overrides valueMember).' }, { configKey: 'getPathCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => string', description: 'Extract a node tree path (enables tree mode; overrides pathMember).' }, { configKey: 'getGroupCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => string', description: 'Extract the group name from an option (overrides groupMember).' }, { configKey: 'getDisabledCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => boolean', description: 'Whether an option is disabled (overrides disabledMember).' }, { configKey: 'getIsSelectableCallback', converter: cb(), on: 'reinit', type: '(node: unknown) => boolean', description: 'Whether a tree node can be selected (overrides is-selectable-member).' }, { configKey: 'getSearchValueCallback', converter: cb(), on: 'reinit', type: '(item: unknown) => string', description: 'Text an option is searched against (overrides searchValueMember).' }, { configKey: 'searchCallback', converter: cb(), on: 'reinit', type: '(searchTerm: string, signal?: AbortSignal) => Promise<unknown[]>', description: 'Custom / async search; return the filtered options.' }, // ── Callbacks: display / render (cosmetic → update) ────────────────────── { configKey: 'getDisplayValueCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Compute the display label for an option (overrides displayValueMember).' }, { configKey: 'getBadgeDisplayCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Compute the text shown on an option badge.' }, { configKey: 'getBadgeClassCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | string[]', description: 'Extra CSS class(es) for an option badge.' }, { configKey: 'getIconCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Icon for an option (overrides iconMember).' }, { configKey: 'getSubtitleCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Subtitle for an option (overrides subtitleMember).' }, { configKey: 'getFullTitleCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Full title for an option (used by badges when show-badge-full-title is on).' }, { configKey: 'getCounterCallback', converter: cb(), on: 'update', type: '(count: number, moreCount?: number) => string', description: 'Render the selected-count label.' }, { configKey: 'getValueFormatCallback', converter: cb(), on: 'update', type: '(selectedValues: (string | number)[]) => string', description: 'Serialize the selected values for form submission.' }, { configKey: 'getBadgeTooltipCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | HTMLElement', description: 'Tooltip content for an option badge.' }, { configKey: 'getOptionTooltipCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | HTMLElement', description: 'Tooltip content for an option row.' }, { configKey: 'getRemoveButtonTooltipCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Tooltip text for a badge remove button.' }, { configKey: 'getSelectedItemClassCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | string[]', description: 'Extra CSS class(es) for a selected item.' }, { configKey: 'renderOptionContentCallback', converter: cb(), on: 'update', type: '(item: unknown, context: OptionContentRenderContext) => string | HTMLElement', description: 'Custom render for an option row; may return HTML or an element.' }, { configKey: 'renderBadgeContentCallback', converter: cb(), on: 'update', type: '(item: unknown, context: BadgeContentRenderContext) => string | HTMLElement', description: 'Custom render for a badge content (fills the built-in pill); may return HTML or an element.' }, { configKey: 'renderBadgeCallback', converter: cb(), on: 'update', type: '(item: unknown, context: BadgeContentRenderContext) => string | HTMLElement | null', description: 'Custom render for the WHOLE badge (main area), not just its content — return the entire pill/card. The component wraps it in `.ms__badge.ms__badge--custom` with `data-value` and delegates removal to any inner element with `data-action=\"remove\"` (or `.ms__badge-remove`). Return null/empty to fall back to the default pill for that item.' }, { configKey: 'renderGroupLabelContentCallback', converter: cb(), on: 'update', type: '(groupName: string) => string | HTMLElement', description: 'Customize a group label; may return an HTML string or element.' }, { configKey: 'renderSelectedContentCallback', converter: cb(), on: 'update', type: '(item: unknown) => string', description: 'Custom render for the whole selected area.' }, { configKey: 'renderSelectedItemContentCallback', converter: cb(), on: 'update', type: '(item: unknown) => string | HTMLElement', description: 'Custom render for one selected item.' }, { configKey: 'customStylesCallback', converter: cb(), on: 'update', type: '() => string', description: 'Returns a CSS string injected into the component via a replaceable style slot (§12.8).' }, // ── Callbacks: before-hooks (behavior-shaping) ─────────────────────────── { configKey: 'beforeSearchCallback', converter: cb(), on: 'update', type: '(searchTerm: string) => string | null', description: 'Runs before a search; return a rewritten term or null to veto.' }, { configKey: 'beforeSelectCallback', converter: cb(), on: 'update', type: '(option: unknown, selectedOptions: unknown[]) => boolean | string | void', description: 'Runs before selecting; return false to veto, or a string to veto and show it as a message.' }, { configKey: 'beforeDeselectCallback', converter: cb(), on: 'update', type: '(option: unknown, selectedOptions: unknown[]) => boolean | string | void', description: 'Runs before deselecting; return false to veto, or a string to veto and show it as a message.' }, { configKey: 'addNewCallback', converter: cb(), on: 'update', type: '(value: string) => unknown | Promise<unknown>', description: 'Create a new option from the typed text.' }, { configKey: 'keydownCallback', converter: cb(), on: 'update', type: '(context: MultiSelectKeydownContext) => boolean | void', description: 'Intercept keydown before built-in handling; return true to suppress the default. Gets the event, current state, and an imperative controller.' }, ]",
|
|
3397
3453
|
"type": {
|
|
3398
3454
|
"text": "readonly InputDef[]"
|
|
3399
3455
|
}
|
|
@@ -3982,6 +4038,44 @@
|
|
|
3982
4038
|
},
|
|
3983
4039
|
"description": "Dismiss the transient message shown by showMessage, if any."
|
|
3984
4040
|
},
|
|
4041
|
+
{
|
|
4042
|
+
"kind": "method",
|
|
4043
|
+
"name": "open",
|
|
4044
|
+
"return": {
|
|
4045
|
+
"type": {
|
|
4046
|
+
"text": "void"
|
|
4047
|
+
}
|
|
4048
|
+
},
|
|
4049
|
+
"description": "Open the dropdown."
|
|
4050
|
+
},
|
|
4051
|
+
{
|
|
4052
|
+
"kind": "method",
|
|
4053
|
+
"name": "close",
|
|
4054
|
+
"return": {
|
|
4055
|
+
"type": {
|
|
4056
|
+
"text": "void"
|
|
4057
|
+
}
|
|
4058
|
+
},
|
|
4059
|
+
"description": "Close the dropdown."
|
|
4060
|
+
},
|
|
4061
|
+
{
|
|
4062
|
+
"kind": "method",
|
|
4063
|
+
"name": "toggle",
|
|
4064
|
+
"return": {
|
|
4065
|
+
"type": {
|
|
4066
|
+
"text": "void"
|
|
4067
|
+
}
|
|
4068
|
+
},
|
|
4069
|
+
"description": "Toggle the dropdown open/closed."
|
|
4070
|
+
},
|
|
4071
|
+
{
|
|
4072
|
+
"kind": "field",
|
|
4073
|
+
"name": "isOpen",
|
|
4074
|
+
"type": {
|
|
4075
|
+
"text": "boolean"
|
|
4076
|
+
},
|
|
4077
|
+
"description": "Whether the dropdown is currently open. Assigning opens/closes it."
|
|
4078
|
+
},
|
|
3985
4079
|
{
|
|
3986
4080
|
"kind": "method",
|
|
3987
4081
|
"name": "destroy",
|
|
@@ -4725,6 +4819,16 @@
|
|
|
4725
4819
|
"attribute": "show-counter",
|
|
4726
4820
|
"description": "Show a selected-count indicator."
|
|
4727
4821
|
},
|
|
4822
|
+
{
|
|
4823
|
+
"kind": "field",
|
|
4824
|
+
"name": "isClearShown",
|
|
4825
|
+
"privacy": "public",
|
|
4826
|
+
"type": {
|
|
4827
|
+
"text": "boolean"
|
|
4828
|
+
},
|
|
4829
|
+
"attribute": "show-clear",
|
|
4830
|
+
"description": "Show an inline clear (✕) button inside the input that wipes the whole selection. Appears only while something is selected and the control is enabled; clicking it clears the selection and any search text, fires `change`, and refocuses."
|
|
4831
|
+
},
|
|
4728
4832
|
{
|
|
4729
4833
|
"kind": "field",
|
|
4730
4834
|
"name": "isBadgeFullTitleShown",
|
|
@@ -5725,6 +5829,14 @@
|
|
|
5725
5829
|
},
|
|
5726
5830
|
"description": "Show a selected-count indicator."
|
|
5727
5831
|
},
|
|
5832
|
+
{
|
|
5833
|
+
"name": "show-clear",
|
|
5834
|
+
"fieldName": "isClearShown",
|
|
5835
|
+
"type": {
|
|
5836
|
+
"text": "boolean"
|
|
5837
|
+
},
|
|
5838
|
+
"description": "Show an inline clear (✕) button inside the input that wipes the whole selection. Appears only while something is selected and the control is enabled; clicking it clears the selection and any search text, fires `change`, and refocuses."
|
|
5839
|
+
},
|
|
5728
5840
|
{
|
|
5729
5841
|
"name": "show-badge-full-title",
|
|
5730
5842
|
"fieldName": "isBadgeFullTitleShown",
|