@keenmate/web-multiselect 2.0.0-rc11 → 2.0.0
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 +35 -15
- package/component-variables.manifest.json +23 -1
- package/custom-elements.json +497 -9
- package/dist/index.d.ts +195 -5
- package/dist/multiselect.js +1415 -1140
- package/dist/multiselect.umd.js +12 -12
- package/dist/style.css +1 -1
- package/docs/usage.md +1 -0
- package/package.json +104 -104
- package/src/css/animations.css +6 -1
- package/src/css/badges.css +14 -0
- package/src/css/controls.css +11 -5
- package/src/css/floating.css +15 -4
- package/src/css/options.css +81 -17
- package/src/css/variables.css +110 -35
- package/vscode.css-custom-data.json +15 -0
- package/vscode.html-custom-data.json +16 -1
- package/web-types.json +68 -4
package/custom-elements.json
CHANGED
|
@@ -250,7 +250,7 @@
|
|
|
250
250
|
"text": "MultiSelectConfig<T>"
|
|
251
251
|
},
|
|
252
252
|
"privacy": "private",
|
|
253
|
-
"default": "{ // String options searchHint: element.dataset.searchHint || '', searchPlaceholder: element.dataset.searchPlaceholder || undefined, selectPlaceholder: element.dataset.selectPlaceholder || 'Pick an option...', noDataPlaceholder: element.dataset.noDataPlaceholder || undefined, dropdownMinWidth: element.dataset.dropdownMinWidth || undefined, dropdownMaxWidth: element.dataset.dropdownMaxWidth || undefined, badgesDisplayMode: (element.dataset.badgesDisplayMode as any) || 'badges', badgesPosition: (element.dataset.badgesPosition as BadgesPosition) || 'bottom', badgesThresholdMode: (element.dataset.badgesThresholdMode as any) || 'count', maxHeight: element.dataset.maxHeight || '20rem', emptyMessage: element.dataset.emptyMessage || 'No results found', loadingMessage: element.dataset.loadingMessage || 'Loading...', searchInputMode: (element.dataset.searchInputMode as SearchInputMode) || 'normal', searchMode: (element.dataset.searchMode as SearchMode) || 'filter', // Number options badgesThreshold: element.dataset.badgesThreshold ? parseInt(element.dataset.badgesThreshold) : undefined, minSearchLength: parseInt(element.dataset.minSearchLength || '0') || 0, searchDebounce: parseInt(element.dataset.searchDebounce || '0') || 0, // Boolean options (internal names with 'is' prefix) isMultipleEnabled: element.dataset.multiple !== 'false', isGroupsAllowed: element.dataset.allowGroups !== 'false', isCheckboxesShown: element.dataset.showCheckboxes !== 'false', isActionsSticky: element.dataset.stickyActions !== 'false', isCloseOnSelect: element.dataset.closeOnSelect === 'true', isPlacementLocked: element.dataset.lockPlacement !== 'false', isSearchEnabled: element.dataset.enableSearch !== 'false', isAddNewAllowed: element.dataset.allowAddNew === 'true', isCounterShown: element.dataset.showCounter === 'true', isSelectedPopoverEnabled: element.dataset.enableSelectedPopover !== 'false', isSearchModeToggleShown: element.dataset.showSearchModeToggle === 'true', isKeepOptionsOnSearch: element.dataset.keepOptionsOnSearch !== 'false', shouldKeepSearchOnClose: element.dataset.keepSearchOnClose !== 'false', // Data and callbacks options: [], container: undefined, // Override with provided options ...options }"
|
|
253
|
+
"default": "{ // String options searchHint: element.dataset.searchHint || '', searchPlaceholder: element.dataset.searchPlaceholder || undefined, selectPlaceholder: element.dataset.selectPlaceholder || 'Pick an option...', noDataPlaceholder: element.dataset.noDataPlaceholder || undefined, dropdownMinWidth: element.dataset.dropdownMinWidth || undefined, dropdownMaxWidth: element.dataset.dropdownMaxWidth || undefined, badgesDisplayMode: (element.dataset.badgesDisplayMode as any) || 'badges', badgesPosition: (element.dataset.badgesPosition as BadgesPosition) || 'bottom', badgesThresholdMode: (element.dataset.badgesThresholdMode as any) || 'count', maxHeight: element.dataset.maxHeight || '20rem', emptyMessage: element.dataset.emptyMessage || 'No results found', addNewText: element.dataset.addNewText || undefined, addNewPendingText: element.dataset.addNewPendingText || undefined, loadingMessage: element.dataset.loadingMessage || 'Loading...', searchInputMode: (element.dataset.searchInputMode as SearchInputMode) || 'normal', searchMode: (element.dataset.searchMode as SearchMode) || 'filter', // Number options badgesThreshold: element.dataset.badgesThreshold ? parseInt(element.dataset.badgesThreshold) : undefined, minSearchLength: parseInt(element.dataset.minSearchLength || '0') || 0, searchDebounce: parseInt(element.dataset.searchDebounce || '0') || 0, // Boolean options (internal names with 'is' prefix) isMultipleEnabled: element.dataset.multiple !== 'false', isGroupsAllowed: element.dataset.allowGroups !== 'false', isCheckboxesShown: element.dataset.showCheckboxes !== 'false', isActionsSticky: element.dataset.stickyActions !== 'false', isCloseOnSelect: element.dataset.closeOnSelect === 'true', isPlacementLocked: element.dataset.lockPlacement !== 'false', isSearchEnabled: element.dataset.enableSearch !== 'false', isAddNewAllowed: element.dataset.allowAddNew === 'true', isCounterShown: element.dataset.showCounter === 'true', isSelectedPopoverEnabled: element.dataset.enableSelectedPopover !== 'false', isSearchModeToggleShown: element.dataset.showSearchModeToggle === 'true', isKeepOptionsOnSearch: element.dataset.keepOptionsOnSearch !== 'false', shouldKeepSearchOnClose: element.dataset.keepSearchOnClose !== 'false', // Data and callbacks options: [], container: undefined, // Override with provided options ...options }"
|
|
254
254
|
},
|
|
255
255
|
{
|
|
256
256
|
"kind": "field",
|
|
@@ -372,6 +372,26 @@
|
|
|
372
372
|
"privacy": "private",
|
|
373
373
|
"default": "''"
|
|
374
374
|
},
|
|
375
|
+
{
|
|
376
|
+
"kind": "field",
|
|
377
|
+
"name": "addNewFocused",
|
|
378
|
+
"type": {
|
|
379
|
+
"text": "boolean"
|
|
380
|
+
},
|
|
381
|
+
"privacy": "private",
|
|
382
|
+
"default": "false",
|
|
383
|
+
"description": "Keyboard focus sits on the empty-state \"add new\" prompt (arrow-navigated)."
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"kind": "field",
|
|
387
|
+
"name": "addNewPending",
|
|
388
|
+
"type": {
|
|
389
|
+
"text": "boolean"
|
|
390
|
+
},
|
|
391
|
+
"privacy": "private",
|
|
392
|
+
"default": "false",
|
|
393
|
+
"description": "An async addNewCallback is in flight — the prompt shows a spinner + pending text."
|
|
394
|
+
},
|
|
375
395
|
{
|
|
376
396
|
"kind": "field",
|
|
377
397
|
"name": "isLoading",
|
|
@@ -820,6 +840,15 @@
|
|
|
820
840
|
"privacy": "private",
|
|
821
841
|
"default": "null"
|
|
822
842
|
},
|
|
843
|
+
{
|
|
844
|
+
"kind": "field",
|
|
845
|
+
"name": "overlayCoord",
|
|
846
|
+
"type": {
|
|
847
|
+
"text": "OverlayHandle | null"
|
|
848
|
+
},
|
|
849
|
+
"privacy": "private",
|
|
850
|
+
"default": "null"
|
|
851
|
+
},
|
|
823
852
|
{
|
|
824
853
|
"kind": "method",
|
|
825
854
|
"name": "extractField",
|
|
@@ -1425,6 +1454,85 @@
|
|
|
1425
1454
|
],
|
|
1426
1455
|
"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."
|
|
1427
1456
|
},
|
|
1457
|
+
{
|
|
1458
|
+
"kind": "method",
|
|
1459
|
+
"name": "renderEmptyStateHTML",
|
|
1460
|
+
"privacy": "private",
|
|
1461
|
+
"return": {
|
|
1462
|
+
"type": {
|
|
1463
|
+
"text": "string"
|
|
1464
|
+
}
|
|
1465
|
+
},
|
|
1466
|
+
"description": "Empty-dropdown content. When \"add new\" is enabled (isAddNewAllowed) AND the user has typed\na non-empty search term, show a clickable \"add new\" prompt instead of the plain emptyMessage —\nchoosing it (click via handleDropdownClick, or Enter via the keydown handler) runs handleAddNew.\nOtherwise fall back to the emptyMessage."
|
|
1467
|
+
},
|
|
1468
|
+
{
|
|
1469
|
+
"kind": "method",
|
|
1470
|
+
"name": "isAddNewPromptShown",
|
|
1471
|
+
"privacy": "private",
|
|
1472
|
+
"return": {
|
|
1473
|
+
"type": {
|
|
1474
|
+
"text": "boolean"
|
|
1475
|
+
}
|
|
1476
|
+
},
|
|
1477
|
+
"description": "True when the empty dropdown is currently showing the clickable \"add new\" prompt."
|
|
1478
|
+
},
|
|
1479
|
+
{
|
|
1480
|
+
"kind": "method",
|
|
1481
|
+
"name": "getAddNewText",
|
|
1482
|
+
"privacy": "private",
|
|
1483
|
+
"return": {
|
|
1484
|
+
"type": {
|
|
1485
|
+
"text": "string"
|
|
1486
|
+
}
|
|
1487
|
+
},
|
|
1488
|
+
"parameters": [
|
|
1489
|
+
{
|
|
1490
|
+
"name": "value",
|
|
1491
|
+
"type": {
|
|
1492
|
+
"text": "string"
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
],
|
|
1496
|
+
"description": "Resolve the \"add new\" prompt label for the typed text. Priority: getAddNewTextCallback\n(returns plain text — fully escaped here) → addNewText template (trusted config string;\nonly the `{value}` substitution is escaped) → the default `Add \"{value}\"`."
|
|
1497
|
+
},
|
|
1498
|
+
{
|
|
1499
|
+
"kind": "method",
|
|
1500
|
+
"name": "getAddNewPendingText",
|
|
1501
|
+
"privacy": "private",
|
|
1502
|
+
"return": {
|
|
1503
|
+
"type": {
|
|
1504
|
+
"text": "string"
|
|
1505
|
+
}
|
|
1506
|
+
},
|
|
1507
|
+
"parameters": [
|
|
1508
|
+
{
|
|
1509
|
+
"name": "value",
|
|
1510
|
+
"type": {
|
|
1511
|
+
"text": "string"
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
],
|
|
1515
|
+
"description": "Pending-prompt label shown (with a spinner) while an async addNewCallback runs."
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
"kind": "method",
|
|
1519
|
+
"name": "escapeHtml",
|
|
1520
|
+
"privacy": "private",
|
|
1521
|
+
"return": {
|
|
1522
|
+
"type": {
|
|
1523
|
+
"text": "string"
|
|
1524
|
+
}
|
|
1525
|
+
},
|
|
1526
|
+
"parameters": [
|
|
1527
|
+
{
|
|
1528
|
+
"name": "value",
|
|
1529
|
+
"type": {
|
|
1530
|
+
"text": "string"
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
],
|
|
1534
|
+
"description": "Minimal HTML entity escape for untrusted text spliced into an innerHTML string."
|
|
1535
|
+
},
|
|
1428
1536
|
{
|
|
1429
1537
|
"kind": "method",
|
|
1430
1538
|
"name": "highlightMatch",
|
|
@@ -1773,6 +1881,17 @@
|
|
|
1773
1881
|
}
|
|
1774
1882
|
}
|
|
1775
1883
|
},
|
|
1884
|
+
{
|
|
1885
|
+
"kind": "method",
|
|
1886
|
+
"name": "focusAddNewPrompt",
|
|
1887
|
+
"privacy": "private",
|
|
1888
|
+
"return": {
|
|
1889
|
+
"type": {
|
|
1890
|
+
"text": "void"
|
|
1891
|
+
}
|
|
1892
|
+
},
|
|
1893
|
+
"description": "Move keyboard focus onto the empty-state \"add new\" prompt (the only actionable row)."
|
|
1894
|
+
},
|
|
1776
1895
|
{
|
|
1777
1896
|
"kind": "method",
|
|
1778
1897
|
"name": "focusNextMatch",
|
|
@@ -1807,13 +1926,32 @@
|
|
|
1807
1926
|
{
|
|
1808
1927
|
"kind": "method",
|
|
1809
1928
|
"name": "clearSearch",
|
|
1810
|
-
"privacy": "
|
|
1929
|
+
"privacy": "public",
|
|
1811
1930
|
"return": {
|
|
1812
1931
|
"type": {
|
|
1813
1932
|
"text": "void"
|
|
1814
1933
|
}
|
|
1815
1934
|
},
|
|
1816
|
-
"description": "Clear the search box (
|
|
1935
|
+
"description": "Clear the search box and restore the full option list (resets the visible/matched sets and\ndrops keyboard focus). Public building block: pair it with `scrollToValue()` to reveal then\nscroll to an option the current search had filtered out — `el.clearSearch(); el.scrollToValue(v)`.\nDoes not touch the selection (use `clearAll()` for that)."
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
"kind": "method",
|
|
1939
|
+
"name": "search",
|
|
1940
|
+
"privacy": "public",
|
|
1941
|
+
"return": {
|
|
1942
|
+
"type": {
|
|
1943
|
+
"text": "void"
|
|
1944
|
+
}
|
|
1945
|
+
},
|
|
1946
|
+
"parameters": [
|
|
1947
|
+
{
|
|
1948
|
+
"name": "term",
|
|
1949
|
+
"type": {
|
|
1950
|
+
"text": "string"
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
],
|
|
1954
|
+
"description": "Programmatically set the search text and filter — exactly as if the user typed it, so\n`beforeSearchCallback`, `minSearchLength` and async `searchCallback` all apply the same way.\nReflects into the search box (and the fullscreen sheet's field). Does NOT open the dropdown —\ncall `open()` if you want it visible. Passing `''` clears (equivalent to `clearSearch()`)."
|
|
1817
1955
|
},
|
|
1818
1956
|
{
|
|
1819
1957
|
"kind": "method",
|
|
@@ -1825,6 +1963,140 @@
|
|
|
1825
1963
|
}
|
|
1826
1964
|
}
|
|
1827
1965
|
},
|
|
1966
|
+
{
|
|
1967
|
+
"kind": "method",
|
|
1968
|
+
"name": "applyScrollIntoView",
|
|
1969
|
+
"privacy": "private",
|
|
1970
|
+
"return": {
|
|
1971
|
+
"type": {
|
|
1972
|
+
"text": "void"
|
|
1973
|
+
}
|
|
1974
|
+
},
|
|
1975
|
+
"parameters": [
|
|
1976
|
+
{
|
|
1977
|
+
"name": "el",
|
|
1978
|
+
"type": {
|
|
1979
|
+
"text": "HTMLElement"
|
|
1980
|
+
}
|
|
1981
|
+
},
|
|
1982
|
+
{
|
|
1983
|
+
"name": "opts",
|
|
1984
|
+
"optional": true,
|
|
1985
|
+
"type": {
|
|
1986
|
+
"text": "{ block?: ScrollLogicalPosition }"
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
],
|
|
1990
|
+
"description": "scrollIntoView with the fullscreen-safe default. In the fullscreen sheet the soft keyboard\ncovers the lower viewport, so `block:'nearest'` can bottom-align a match BEHIND the keyboard;\ncentre it instead and scroll INSTANTLY (a smooth animation kicked off per-keystroke is torn\ndown by the next re-render and never settles — the \"list jumps every letter\" bug). Floating\nscrolls the nearest edge smoothly. The caller may override `block`."
|
|
1991
|
+
},
|
|
1992
|
+
{
|
|
1993
|
+
"kind": "method",
|
|
1994
|
+
"name": "scrollToIndex",
|
|
1995
|
+
"privacy": "public",
|
|
1996
|
+
"return": {
|
|
1997
|
+
"type": {
|
|
1998
|
+
"text": "boolean"
|
|
1999
|
+
}
|
|
2000
|
+
},
|
|
2001
|
+
"parameters": [
|
|
2002
|
+
{
|
|
2003
|
+
"name": "index",
|
|
2004
|
+
"type": {
|
|
2005
|
+
"text": "number"
|
|
2006
|
+
}
|
|
2007
|
+
},
|
|
2008
|
+
{
|
|
2009
|
+
"name": "opts",
|
|
2010
|
+
"optional": true,
|
|
2011
|
+
"type": {
|
|
2012
|
+
"text": "{ block?: ScrollLogicalPosition }"
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
],
|
|
2016
|
+
"description": "Scroll the open dropdown so the option at `index` (into the current `filteredOptions`) is\nvisible. Works in floating, fullscreen (mobile), virtual-scroll and tree modes. Returns\nfalse if the dropdown is closed or the index is out of range. The scroll is deferred a frame\nwhen the list isn't rendered yet (e.g. right after `open()` in virtual mode / the fullscreen\nsheet build), so `el.open(); el.scrollToIndex(i)` works."
|
|
2017
|
+
},
|
|
2018
|
+
{
|
|
2019
|
+
"kind": "method",
|
|
2020
|
+
"name": "scrollToValue",
|
|
2021
|
+
"privacy": "public",
|
|
2022
|
+
"return": {
|
|
2023
|
+
"type": {
|
|
2024
|
+
"text": "boolean"
|
|
2025
|
+
}
|
|
2026
|
+
},
|
|
2027
|
+
"parameters": [
|
|
2028
|
+
{
|
|
2029
|
+
"name": "value",
|
|
2030
|
+
"type": {
|
|
2031
|
+
"text": "string | number"
|
|
2032
|
+
}
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
"name": "opts",
|
|
2036
|
+
"optional": true,
|
|
2037
|
+
"type": {
|
|
2038
|
+
"text": "{ block?: ScrollLogicalPosition }"
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
],
|
|
2042
|
+
"description": "Scroll to the option whose value matches `value` (resolved within the current\n`filteredOptions`). Returns false if it isn't in the currently visible list — e.g. filtered\nout by a search, or (tree) under a collapsed ancestor. Call `clearSearch()` (or expand the\nbranch) first to reveal it, then scroll."
|
|
2043
|
+
},
|
|
2044
|
+
{
|
|
2045
|
+
"kind": "method",
|
|
2046
|
+
"name": "scrollToGroup",
|
|
2047
|
+
"privacy": "public",
|
|
2048
|
+
"return": {
|
|
2049
|
+
"type": {
|
|
2050
|
+
"text": "boolean"
|
|
2051
|
+
}
|
|
2052
|
+
},
|
|
2053
|
+
"parameters": [
|
|
2054
|
+
{
|
|
2055
|
+
"name": "name",
|
|
2056
|
+
"type": {
|
|
2057
|
+
"text": "string"
|
|
2058
|
+
}
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
"name": "opts",
|
|
2062
|
+
"optional": true,
|
|
2063
|
+
"type": {
|
|
2064
|
+
"text": "{ block?: ScrollLogicalPosition }"
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
],
|
|
2068
|
+
"description": "Scroll to a group. In standard rendering the group's header (`.ms__group-label`) is brought\ninto view; in virtual-scroll mode (which renders no headers) it scrolls to the group's FIRST\noption instead. Returns false in tree mode (groups don't apply) or if the group has no\noptions in the current filtered list."
|
|
2069
|
+
},
|
|
2070
|
+
{
|
|
2071
|
+
"kind": "method",
|
|
2072
|
+
"name": "scrollToRenderedIndex",
|
|
2073
|
+
"privacy": "private",
|
|
2074
|
+
"return": {
|
|
2075
|
+
"type": {
|
|
2076
|
+
"text": "void"
|
|
2077
|
+
}
|
|
2078
|
+
},
|
|
2079
|
+
"parameters": [
|
|
2080
|
+
{
|
|
2081
|
+
"name": "index",
|
|
2082
|
+
"type": {
|
|
2083
|
+
"text": "number"
|
|
2084
|
+
}
|
|
2085
|
+
},
|
|
2086
|
+
{
|
|
2087
|
+
"name": "opts",
|
|
2088
|
+
"optional": true,
|
|
2089
|
+
"type": {
|
|
2090
|
+
"text": "{ block?: ScrollLogicalPosition }"
|
|
2091
|
+
}
|
|
2092
|
+
},
|
|
2093
|
+
{
|
|
2094
|
+
"name": "retried",
|
|
2095
|
+
"default": "false"
|
|
2096
|
+
}
|
|
2097
|
+
],
|
|
2098
|
+
"description": "Shared scroll worker for the public scrollTo* methods. Virtual mode uses the fixed-height\nmath (works even if the row isn't currently rendered); otherwise scrolls the\n`.ms__option[data-index]` element into view. Defers one frame if the list isn't ready yet\n(post-open virtual init / fullscreen sheet build), then retries once."
|
|
2099
|
+
},
|
|
1828
2100
|
{
|
|
1829
2101
|
"kind": "method",
|
|
1830
2102
|
"name": "toggleOption",
|
|
@@ -1897,7 +2169,8 @@
|
|
|
1897
2169
|
"text": "string"
|
|
1898
2170
|
}
|
|
1899
2171
|
}
|
|
1900
|
-
]
|
|
2172
|
+
],
|
|
2173
|
+
"description": "Commit the \"add new\" affordance for the typed text. Two modes:\n - `addNewCallback` set → create the option, append it, select it, clear the search.\n - no callback → the consumer owns creation; we only notify (via the `add` event) so they\n can open a modal / POST / add the option imperatively.\nThe `add` event fires in BOTH modes (with `option` present only when one was created)."
|
|
1901
2174
|
},
|
|
1902
2175
|
{
|
|
1903
2176
|
"kind": "method",
|
|
@@ -2687,6 +2960,16 @@
|
|
|
2687
2960
|
"privacy": "public",
|
|
2688
2961
|
"readonly": true
|
|
2689
2962
|
},
|
|
2963
|
+
{
|
|
2964
|
+
"kind": "field",
|
|
2965
|
+
"name": "searchText",
|
|
2966
|
+
"type": {
|
|
2967
|
+
"text": "string"
|
|
2968
|
+
},
|
|
2969
|
+
"privacy": "public",
|
|
2970
|
+
"description": "The current search box text (empty string when nothing is typed). Read-only; clear it with `clearSearch()`.",
|
|
2971
|
+
"readonly": true
|
|
2972
|
+
},
|
|
2690
2973
|
{
|
|
2691
2974
|
"kind": "field",
|
|
2692
2975
|
"name": "selectedValue",
|
|
@@ -3326,6 +3609,13 @@
|
|
|
3326
3609
|
"type": {
|
|
3327
3610
|
"text": "number"
|
|
3328
3611
|
}
|
|
3612
|
+
},
|
|
3613
|
+
{
|
|
3614
|
+
"name": "block",
|
|
3615
|
+
"default": "'start'",
|
|
3616
|
+
"type": {
|
|
3617
|
+
"text": "'start' | 'center' | 'nearest'"
|
|
3618
|
+
}
|
|
3329
3619
|
}
|
|
3330
3620
|
],
|
|
3331
3621
|
"description": "Scroll to make item at index visible (like scrollIntoView with block: 'nearest')\nOnly scrolls if item is outside visible area, and scrolls minimally"
|
|
@@ -3449,7 +3739,7 @@
|
|
|
3449
3739
|
"name": "inputs",
|
|
3450
3740
|
"privacy": "protected",
|
|
3451
3741
|
"static": true,
|
|
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.' }, ]",
|
|
3742
|
+
"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: 'addNewText', attribute: 'add-new-text', converter: toText({ isNullable: true }), on: 'update', description: 'Template for the clickable \"add new\" prompt shown (when `allow-add-new` is on) in place of the empty message once a search yields no matches. `{value}` is replaced with the typed text. Default: `Add \"{value}\"`. A `getAddNewTextCallback` wins.' }, { configKey: 'addNewPendingText', attribute: 'add-new-pending-text', converter: toText({ isNullable: true }), on: 'update', description: 'Template for the pending prompt (spinner + text) shown while an async `addNewCallback` runs. `{value}` is replaced with the typed text. Default: `Adding \"{value}\"…`.' }, { 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: 'overlayGroup', attribute: 'overlay-group', converter: toText({ isNullable: true }), on: 'reinit', description: 'Scope the \"one overlay open at a time\" coordination to a named group. Overlays (multiselects, datepickers, external popovers) sharing a group dismiss each other when one opens; different groups are independent. Unset = the default (ungrouped) group.' }, { 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 | null | undefined | Promise<unknown | null | undefined>', description: 'Create a new option from the typed text. May return a rich option object (renders via the same get*/render* callbacks as any option). Async + cancelable: return null/undefined to abort (no add, no `add` event). Omit entirely to handle creation yourself via the `add` event.' }, { configKey: 'getAddNewTextCallback', converter: cb(), on: 'update', type: '(value: string) => string', description: 'Dynamically compute the \"add new\" prompt label from the typed text (returns plain text). Takes precedence over `add-new-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.' }, ]",
|
|
3453
3743
|
"type": {
|
|
3454
3744
|
"text": "readonly InputDef[]"
|
|
3455
3745
|
}
|
|
@@ -3459,9 +3749,9 @@
|
|
|
3459
3749
|
"name": "events",
|
|
3460
3750
|
"privacy": "protected",
|
|
3461
3751
|
"static": true,
|
|
3462
|
-
"default": "[ { name: 'select', description: 'An option was selected. `detail.option` is the selected option; `detail.selectedOptions`/`detail.selectedValues` are the full selection.' }, { name: 'deselect', description: 'An option was removed from the selection. `detail.option` is that option.' }, { name: 'change', description: 'The selection changed. `detail.selectedOptions`/`detail.selectedValues` are the full selection.' }, ]",
|
|
3752
|
+
"default": "[ { name: 'select', description: 'An option was selected. `detail.option` is the selected option; `detail.selectedOptions`/`detail.selectedValues` are the full selection.' }, { name: 'deselect', description: 'An option was removed from the selection. `detail.option` is that option.' }, { name: 'change', description: 'The selection changed. `detail.selectedOptions`/`detail.selectedValues` are the full selection.' }, { name: 'add', description: 'The user chose to create a new option from the typed text (via the \"add new\" prompt or Enter) — requires `allow-add-new`. `detail.value` is the typed text; `detail.option` is the created item when `addNewCallback` produced one.' }, ]",
|
|
3463
3753
|
"type": {
|
|
3464
|
-
"text": "[\r\n { name: 'select', description: 'An option was selected. `detail.option` is the selected option; `detail.selectedOptions`/`detail.selectedValues` are the full selection.' },\r\n { name: 'deselect', description: 'An option was removed from the selection. `detail.option` is that option.' },\r\n { name: 'change', description: 'The selection changed. `detail.selectedOptions`/`detail.selectedValues` are the full selection.' },\r\n]"
|
|
3754
|
+
"text": "[\r\n { name: 'select', description: 'An option was selected. `detail.option` is the selected option; `detail.selectedOptions`/`detail.selectedValues` are the full selection.' },\r\n { name: 'deselect', description: 'An option was removed from the selection. `detail.option` is that option.' },\r\n { name: 'change', description: 'The selection changed. `detail.selectedOptions`/`detail.selectedValues` are the full selection.' },\r\n { name: 'add', description: 'The user chose to create a new option from the typed text (via the \"add new\" prompt or Enter) — requires `allow-add-new`. `detail.value` is the typed text; `detail.option` is the created item when `addNewCallback` produced one.' },\r\n]"
|
|
3465
3755
|
}
|
|
3466
3756
|
},
|
|
3467
3757
|
{
|
|
@@ -3485,6 +3775,13 @@
|
|
|
3485
3775
|
"text": "((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null"
|
|
3486
3776
|
}
|
|
3487
3777
|
},
|
|
3778
|
+
{
|
|
3779
|
+
"kind": "field",
|
|
3780
|
+
"name": "onAdd",
|
|
3781
|
+
"type": {
|
|
3782
|
+
"text": "((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null"
|
|
3783
|
+
}
|
|
3784
|
+
},
|
|
3488
3785
|
{
|
|
3489
3786
|
"kind": "field",
|
|
3490
3787
|
"name": "#shadow",
|
|
@@ -4038,6 +4335,118 @@
|
|
|
4038
4335
|
},
|
|
4039
4336
|
"description": "Dismiss the transient message shown by showMessage, if any."
|
|
4040
4337
|
},
|
|
4338
|
+
{
|
|
4339
|
+
"kind": "method",
|
|
4340
|
+
"name": "clearSearch",
|
|
4341
|
+
"return": {
|
|
4342
|
+
"type": {
|
|
4343
|
+
"text": "void"
|
|
4344
|
+
}
|
|
4345
|
+
},
|
|
4346
|
+
"description": "Clear the search box and restore the full option list (does not touch the selection — use\r\nclearAll for that). Pair with scrollToValue to reveal then scroll to an option\r\na search had filtered out: `el.clearSearch(); el.scrollToValue(v)`."
|
|
4347
|
+
},
|
|
4348
|
+
{
|
|
4349
|
+
"kind": "field",
|
|
4350
|
+
"name": "searchText",
|
|
4351
|
+
"type": {
|
|
4352
|
+
"text": "string"
|
|
4353
|
+
},
|
|
4354
|
+
"description": "The current search box text (empty string when nothing is typed). Read via this getter, write with search.",
|
|
4355
|
+
"readonly": true
|
|
4356
|
+
},
|
|
4357
|
+
{
|
|
4358
|
+
"kind": "method",
|
|
4359
|
+
"name": "search",
|
|
4360
|
+
"return": {
|
|
4361
|
+
"type": {
|
|
4362
|
+
"text": "void"
|
|
4363
|
+
}
|
|
4364
|
+
},
|
|
4365
|
+
"parameters": [
|
|
4366
|
+
{
|
|
4367
|
+
"name": "term",
|
|
4368
|
+
"type": {
|
|
4369
|
+
"text": "string"
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
],
|
|
4373
|
+
"description": "Programmatically set the search text and filter, as if the user typed it (runs\r\n`beforeSearchCallback` / `minSearchLength` / async `searchCallback`). Does not open the dropdown\r\n— call open if you want it visible. Pass `''` to clear (same as clearSearch)."
|
|
4374
|
+
},
|
|
4375
|
+
{
|
|
4376
|
+
"kind": "method",
|
|
4377
|
+
"name": "scrollToIndex",
|
|
4378
|
+
"return": {
|
|
4379
|
+
"type": {
|
|
4380
|
+
"text": "boolean"
|
|
4381
|
+
}
|
|
4382
|
+
},
|
|
4383
|
+
"parameters": [
|
|
4384
|
+
{
|
|
4385
|
+
"name": "index",
|
|
4386
|
+
"type": {
|
|
4387
|
+
"text": "number"
|
|
4388
|
+
}
|
|
4389
|
+
},
|
|
4390
|
+
{
|
|
4391
|
+
"name": "opts",
|
|
4392
|
+
"optional": true,
|
|
4393
|
+
"type": {
|
|
4394
|
+
"text": "{ block?: ScrollLogicalPosition }"
|
|
4395
|
+
}
|
|
4396
|
+
}
|
|
4397
|
+
],
|
|
4398
|
+
"description": "Scroll the open dropdown to the option at `index` (into the current filtered list). Returns\r\nfalse if closed or out of range. Deferred internally so `el.open(); el.scrollToIndex(i)` works."
|
|
4399
|
+
},
|
|
4400
|
+
{
|
|
4401
|
+
"kind": "method",
|
|
4402
|
+
"name": "scrollToValue",
|
|
4403
|
+
"return": {
|
|
4404
|
+
"type": {
|
|
4405
|
+
"text": "boolean"
|
|
4406
|
+
}
|
|
4407
|
+
},
|
|
4408
|
+
"parameters": [
|
|
4409
|
+
{
|
|
4410
|
+
"name": "value",
|
|
4411
|
+
"type": {
|
|
4412
|
+
"text": "string | number"
|
|
4413
|
+
}
|
|
4414
|
+
},
|
|
4415
|
+
{
|
|
4416
|
+
"name": "opts",
|
|
4417
|
+
"optional": true,
|
|
4418
|
+
"type": {
|
|
4419
|
+
"text": "{ block?: ScrollLogicalPosition }"
|
|
4420
|
+
}
|
|
4421
|
+
}
|
|
4422
|
+
],
|
|
4423
|
+
"description": "Scroll the open dropdown to the option with this `value`. Returns false if it isn't in the\r\ncurrently visible list (filtered out by search, or under a collapsed tree branch) — call\r\nclearSearch / expand first."
|
|
4424
|
+
},
|
|
4425
|
+
{
|
|
4426
|
+
"kind": "method",
|
|
4427
|
+
"name": "scrollToGroup",
|
|
4428
|
+
"return": {
|
|
4429
|
+
"type": {
|
|
4430
|
+
"text": "boolean"
|
|
4431
|
+
}
|
|
4432
|
+
},
|
|
4433
|
+
"parameters": [
|
|
4434
|
+
{
|
|
4435
|
+
"name": "name",
|
|
4436
|
+
"type": {
|
|
4437
|
+
"text": "string"
|
|
4438
|
+
}
|
|
4439
|
+
},
|
|
4440
|
+
{
|
|
4441
|
+
"name": "opts",
|
|
4442
|
+
"optional": true,
|
|
4443
|
+
"type": {
|
|
4444
|
+
"text": "{ block?: ScrollLogicalPosition }"
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
],
|
|
4448
|
+
"description": "Scroll to a group: its header in standard rendering, or the group's first option in\r\nvirtual-scroll mode (no headers there). Returns false in tree mode or if the group is empty\r\nin the current filtered list."
|
|
4449
|
+
},
|
|
4041
4450
|
{
|
|
4042
4451
|
"kind": "method",
|
|
4043
4452
|
"name": "open",
|
|
@@ -4168,6 +4577,26 @@
|
|
|
4168
4577
|
"attribute": "empty-message",
|
|
4169
4578
|
"description": "Message shown when a search yields no matches."
|
|
4170
4579
|
},
|
|
4580
|
+
{
|
|
4581
|
+
"kind": "field",
|
|
4582
|
+
"name": "addNewText",
|
|
4583
|
+
"privacy": "public",
|
|
4584
|
+
"type": {
|
|
4585
|
+
"text": "string | null"
|
|
4586
|
+
},
|
|
4587
|
+
"attribute": "add-new-text",
|
|
4588
|
+
"description": "Template for the clickable \"add new\" prompt shown (when `allow-add-new` is on) in place of the empty message once a search yields no matches. `{value}` is replaced with the typed text. Default: `Add \"{value}\"`. A `getAddNewTextCallback` wins."
|
|
4589
|
+
},
|
|
4590
|
+
{
|
|
4591
|
+
"kind": "field",
|
|
4592
|
+
"name": "addNewPendingText",
|
|
4593
|
+
"privacy": "public",
|
|
4594
|
+
"type": {
|
|
4595
|
+
"text": "string | null"
|
|
4596
|
+
},
|
|
4597
|
+
"attribute": "add-new-pending-text",
|
|
4598
|
+
"description": "Template for the pending prompt (spinner + text) shown while an async `addNewCallback` runs. `{value}` is replaced with the typed text. Default: `Adding \"{value}\"…`."
|
|
4599
|
+
},
|
|
4171
4600
|
{
|
|
4172
4601
|
"kind": "field",
|
|
4173
4602
|
"name": "loadingMessage",
|
|
@@ -4462,6 +4891,16 @@
|
|
|
4462
4891
|
"attribute": "search-mode",
|
|
4463
4892
|
"description": "Whether typing filters the list or navigates it."
|
|
4464
4893
|
},
|
|
4894
|
+
{
|
|
4895
|
+
"kind": "field",
|
|
4896
|
+
"name": "overlayGroup",
|
|
4897
|
+
"privacy": "public",
|
|
4898
|
+
"type": {
|
|
4899
|
+
"text": "string | null"
|
|
4900
|
+
},
|
|
4901
|
+
"attribute": "overlay-group",
|
|
4902
|
+
"description": "Scope the \"one overlay open at a time\" coordination to a named group. Overlays (multiselects, datepickers, external popovers) sharing a group dismiss each other when one opens; different groups are independent. Unset = the default (ungrouped) group."
|
|
4903
|
+
},
|
|
4465
4904
|
{
|
|
4466
4905
|
"kind": "field",
|
|
4467
4906
|
"name": "actionsLayout",
|
|
@@ -5238,9 +5677,18 @@
|
|
|
5238
5677
|
"name": "addNewCallback",
|
|
5239
5678
|
"privacy": "public",
|
|
5240
5679
|
"type": {
|
|
5241
|
-
"text": "(value: string) => unknown | Promise<unknown>"
|
|
5680
|
+
"text": "(value: string) => unknown | null | undefined | Promise<unknown | null | undefined>"
|
|
5681
|
+
},
|
|
5682
|
+
"description": "Create a new option from the typed text. May return a rich option object (renders via the same get*/render* callbacks as any option). Async + cancelable: return null/undefined to abort (no add, no `add` event). Omit entirely to handle creation yourself via the `add` event."
|
|
5683
|
+
},
|
|
5684
|
+
{
|
|
5685
|
+
"kind": "field",
|
|
5686
|
+
"name": "getAddNewTextCallback",
|
|
5687
|
+
"privacy": "public",
|
|
5688
|
+
"type": {
|
|
5689
|
+
"text": "(value: string) => string"
|
|
5242
5690
|
},
|
|
5243
|
-
"description": "
|
|
5691
|
+
"description": "Dynamically compute the \"add new\" prompt label from the typed text (returns plain text). Takes precedence over `add-new-text`."
|
|
5244
5692
|
},
|
|
5245
5693
|
{
|
|
5246
5694
|
"kind": "field",
|
|
@@ -5324,6 +5772,22 @@
|
|
|
5324
5772
|
"default": "'No results found'",
|
|
5325
5773
|
"description": "Message shown when a search yields no matches."
|
|
5326
5774
|
},
|
|
5775
|
+
{
|
|
5776
|
+
"name": "add-new-text",
|
|
5777
|
+
"fieldName": "addNewText",
|
|
5778
|
+
"type": {
|
|
5779
|
+
"text": "string | null"
|
|
5780
|
+
},
|
|
5781
|
+
"description": "Template for the clickable \"add new\" prompt shown (when `allow-add-new` is on) in place of the empty message once a search yields no matches. `{value}` is replaced with the typed text. Default: `Add \"{value}\"`. A `getAddNewTextCallback` wins."
|
|
5782
|
+
},
|
|
5783
|
+
{
|
|
5784
|
+
"name": "add-new-pending-text",
|
|
5785
|
+
"fieldName": "addNewPendingText",
|
|
5786
|
+
"type": {
|
|
5787
|
+
"text": "string | null"
|
|
5788
|
+
},
|
|
5789
|
+
"description": "Template for the pending prompt (spinner + text) shown while an async `addNewCallback` runs. `{value}` is replaced with the typed text. Default: `Adding \"{value}\"…`."
|
|
5790
|
+
},
|
|
5327
5791
|
{
|
|
5328
5792
|
"name": "loading-message",
|
|
5329
5793
|
"fieldName": "loadingMessage",
|
|
@@ -5541,6 +6005,14 @@
|
|
|
5541
6005
|
"default": "'filter'",
|
|
5542
6006
|
"description": "Whether typing filters the list or navigates it."
|
|
5543
6007
|
},
|
|
6008
|
+
{
|
|
6009
|
+
"name": "overlay-group",
|
|
6010
|
+
"fieldName": "overlayGroup",
|
|
6011
|
+
"type": {
|
|
6012
|
+
"text": "string | null"
|
|
6013
|
+
},
|
|
6014
|
+
"description": "Scope the \"one overlay open at a time\" coordination to a named group. Overlays (multiselects, datepickers, external popovers) sharing a group dismiss each other when one opens; different groups are independent. Unset = the default (ungrouped) group."
|
|
6015
|
+
},
|
|
5544
6016
|
{
|
|
5545
6017
|
"name": "actions-layout",
|
|
5546
6018
|
"fieldName": "actionsLayout",
|
|
@@ -5951,6 +6423,10 @@
|
|
|
5951
6423
|
{
|
|
5952
6424
|
"name": "change",
|
|
5953
6425
|
"description": "The selection changed. `detail.selectedOptions`/`detail.selectedValues` are the full selection."
|
|
6426
|
+
},
|
|
6427
|
+
{
|
|
6428
|
+
"name": "add",
|
|
6429
|
+
"description": "The user chose to create a new option from the typed text (via the \"add new\" prompt or Enter) — requires `allow-add-new`. `detail.value` is the typed text; `detail.option` is the created item when `addNewCallback` produced one."
|
|
5954
6430
|
}
|
|
5955
6431
|
],
|
|
5956
6432
|
"tagName": "web-multiselect",
|
|
@@ -6780,6 +7256,18 @@
|
|
|
6780
7256
|
"name": "--ms-icon-remove",
|
|
6781
7257
|
"description": "Remove icon as CSS url() to a mask-friendly SVG; color comes from currentColor"
|
|
6782
7258
|
},
|
|
7259
|
+
{
|
|
7260
|
+
"name": "--ms-icon-filter",
|
|
7261
|
+
"description": "Funnel glyph (fullscreen search-mode toggle); chains to --base-icon-filter"
|
|
7262
|
+
},
|
|
7263
|
+
{
|
|
7264
|
+
"name": "--ms-icon-check",
|
|
7265
|
+
"description": "Checkmark glyph (mask) for a checked checkbox/option; chains to --base-icon-check"
|
|
7266
|
+
},
|
|
7267
|
+
{
|
|
7268
|
+
"name": "--ms-icon-indeterminate",
|
|
7269
|
+
"description": "Dash glyph (mask) for a tri-state/partial checkbox; chains to --base-icon-indeterminate"
|
|
7270
|
+
},
|
|
6783
7271
|
{
|
|
6784
7272
|
"name": "--ms-badge-counter-bg",
|
|
6785
7273
|
"description": "Counter badge background"
|