@keenmate/web-multiselect 2.0.0-rc12 → 2.0.1
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 +201 -186
- package/component-variables.manifest.json +26 -30
- package/custom-elements.json +470 -109
- package/dist/index.d.ts +187 -5
- package/dist/multiselect.js +968 -732
- package/dist/multiselect.umd.js +11 -11
- package/dist/style.css +1 -1
- package/docs/theming.md +7 -7
- package/package.json +5 -3
- package/src/css/animations.css +6 -1
- package/src/css/badges.css +14 -0
- package/src/css/options.css +85 -17
- package/src/css/variables.css +964 -919
- package/vscode.css-custom-data.json +15 -125
- package/vscode.html-custom-data.json +11 -1
- package/web-types.json +58 -86
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",
|
|
@@ -1434,6 +1454,85 @@
|
|
|
1434
1454
|
],
|
|
1435
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."
|
|
1436
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
|
+
},
|
|
1437
1536
|
{
|
|
1438
1537
|
"kind": "method",
|
|
1439
1538
|
"name": "highlightMatch",
|
|
@@ -1782,6 +1881,17 @@
|
|
|
1782
1881
|
}
|
|
1783
1882
|
}
|
|
1784
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
|
+
},
|
|
1785
1895
|
{
|
|
1786
1896
|
"kind": "method",
|
|
1787
1897
|
"name": "focusNextMatch",
|
|
@@ -1816,13 +1926,32 @@
|
|
|
1816
1926
|
{
|
|
1817
1927
|
"kind": "method",
|
|
1818
1928
|
"name": "clearSearch",
|
|
1819
|
-
"privacy": "
|
|
1929
|
+
"privacy": "public",
|
|
1820
1930
|
"return": {
|
|
1821
1931
|
"type": {
|
|
1822
1932
|
"text": "void"
|
|
1823
1933
|
}
|
|
1824
1934
|
},
|
|
1825
|
-
"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()`)."
|
|
1826
1955
|
},
|
|
1827
1956
|
{
|
|
1828
1957
|
"kind": "method",
|
|
@@ -1834,6 +1963,140 @@
|
|
|
1834
1963
|
}
|
|
1835
1964
|
}
|
|
1836
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
|
+
},
|
|
1837
2100
|
{
|
|
1838
2101
|
"kind": "method",
|
|
1839
2102
|
"name": "toggleOption",
|
|
@@ -1906,7 +2169,8 @@
|
|
|
1906
2169
|
"text": "string"
|
|
1907
2170
|
}
|
|
1908
2171
|
}
|
|
1909
|
-
]
|
|
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)."
|
|
1910
2174
|
},
|
|
1911
2175
|
{
|
|
1912
2176
|
"kind": "method",
|
|
@@ -2696,6 +2960,16 @@
|
|
|
2696
2960
|
"privacy": "public",
|
|
2697
2961
|
"readonly": true
|
|
2698
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
|
+
},
|
|
2699
2973
|
{
|
|
2700
2974
|
"kind": "field",
|
|
2701
2975
|
"name": "selectedValue",
|
|
@@ -3335,6 +3609,13 @@
|
|
|
3335
3609
|
"type": {
|
|
3336
3610
|
"text": "number"
|
|
3337
3611
|
}
|
|
3612
|
+
},
|
|
3613
|
+
{
|
|
3614
|
+
"name": "block",
|
|
3615
|
+
"default": "'start'",
|
|
3616
|
+
"type": {
|
|
3617
|
+
"text": "'start' | 'center' | 'nearest'"
|
|
3618
|
+
}
|
|
3338
3619
|
}
|
|
3339
3620
|
],
|
|
3340
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"
|
|
@@ -3458,7 +3739,7 @@
|
|
|
3458
3739
|
"name": "inputs",
|
|
3459
3740
|
"privacy": "protected",
|
|
3460
3741
|
"static": true,
|
|
3461
|
-
"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: '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 | 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.' }, ]",
|
|
3462
3743
|
"type": {
|
|
3463
3744
|
"text": "readonly InputDef[]"
|
|
3464
3745
|
}
|
|
@@ -3468,9 +3749,9 @@
|
|
|
3468
3749
|
"name": "events",
|
|
3469
3750
|
"privacy": "protected",
|
|
3470
3751
|
"static": true,
|
|
3471
|
-
"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.' }, ]",
|
|
3472
3753
|
"type": {
|
|
3473
|
-
"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]"
|
|
3474
3755
|
}
|
|
3475
3756
|
},
|
|
3476
3757
|
{
|
|
@@ -3494,6 +3775,13 @@
|
|
|
3494
3775
|
"text": "((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null"
|
|
3495
3776
|
}
|
|
3496
3777
|
},
|
|
3778
|
+
{
|
|
3779
|
+
"kind": "field",
|
|
3780
|
+
"name": "onAdd",
|
|
3781
|
+
"type": {
|
|
3782
|
+
"text": "((e: CustomEvent<MultiSelectEventDetail<T>>) => void) | null"
|
|
3783
|
+
}
|
|
3784
|
+
},
|
|
3497
3785
|
{
|
|
3498
3786
|
"kind": "field",
|
|
3499
3787
|
"name": "#shadow",
|
|
@@ -4047,6 +4335,118 @@
|
|
|
4047
4335
|
},
|
|
4048
4336
|
"description": "Dismiss the transient message shown by showMessage, if any."
|
|
4049
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
|
+
},
|
|
4050
4450
|
{
|
|
4051
4451
|
"kind": "method",
|
|
4052
4452
|
"name": "open",
|
|
@@ -4177,6 +4577,26 @@
|
|
|
4177
4577
|
"attribute": "empty-message",
|
|
4178
4578
|
"description": "Message shown when a search yields no matches."
|
|
4179
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
|
+
},
|
|
4180
4600
|
{
|
|
4181
4601
|
"kind": "field",
|
|
4182
4602
|
"name": "loadingMessage",
|
|
@@ -5257,9 +5677,18 @@
|
|
|
5257
5677
|
"name": "addNewCallback",
|
|
5258
5678
|
"privacy": "public",
|
|
5259
5679
|
"type": {
|
|
5260
|
-
"text": "(value: string) => unknown | Promise<unknown>"
|
|
5680
|
+
"text": "(value: string) => unknown | null | undefined | Promise<unknown | null | undefined>"
|
|
5261
5681
|
},
|
|
5262
|
-
"description": "Create a new option from the typed text."
|
|
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"
|
|
5690
|
+
},
|
|
5691
|
+
"description": "Dynamically compute the \"add new\" prompt label from the typed text (returns plain text). Takes precedence over `add-new-text`."
|
|
5263
5692
|
},
|
|
5264
5693
|
{
|
|
5265
5694
|
"kind": "field",
|
|
@@ -5343,6 +5772,22 @@
|
|
|
5343
5772
|
"default": "'No results found'",
|
|
5344
5773
|
"description": "Message shown when a search yields no matches."
|
|
5345
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
|
+
},
|
|
5346
5791
|
{
|
|
5347
5792
|
"name": "loading-message",
|
|
5348
5793
|
"fieldName": "loadingMessage",
|
|
@@ -5978,6 +6423,10 @@
|
|
|
5978
6423
|
{
|
|
5979
6424
|
"name": "change",
|
|
5980
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."
|
|
5981
6430
|
}
|
|
5982
6431
|
],
|
|
5983
6432
|
"tagName": "web-multiselect",
|
|
@@ -6079,14 +6528,6 @@
|
|
|
6079
6528
|
"name": "--ms-input-bg-disabled",
|
|
6080
6529
|
"description": "Disabled input background"
|
|
6081
6530
|
},
|
|
6082
|
-
{
|
|
6083
|
-
"name": "--ms-input-padding",
|
|
6084
|
-
"description": "Input padding"
|
|
6085
|
-
},
|
|
6086
|
-
{
|
|
6087
|
-
"name": "--ms-input-padding-right",
|
|
6088
|
-
"description": "Input right padding (for toggle)"
|
|
6089
|
-
},
|
|
6090
6531
|
{
|
|
6091
6532
|
"name": "--ms-input-height",
|
|
6092
6533
|
"description": "Input height"
|
|
@@ -6107,90 +6548,6 @@
|
|
|
6107
6548
|
"name": "--ms-input-text",
|
|
6108
6549
|
"description": "Input text color"
|
|
6109
6550
|
},
|
|
6110
|
-
{
|
|
6111
|
-
"name": "--ms-input-size-xs-font",
|
|
6112
|
-
"description": "XS size font"
|
|
6113
|
-
},
|
|
6114
|
-
{
|
|
6115
|
-
"name": "--ms-input-size-xs-padding-v",
|
|
6116
|
-
"description": "XS vertical padding"
|
|
6117
|
-
},
|
|
6118
|
-
{
|
|
6119
|
-
"name": "--ms-input-size-xs-padding-h",
|
|
6120
|
-
"description": "XS horizontal padding"
|
|
6121
|
-
},
|
|
6122
|
-
{
|
|
6123
|
-
"name": "--ms-input-size-xs-height",
|
|
6124
|
-
"description": "XS input height"
|
|
6125
|
-
},
|
|
6126
|
-
{
|
|
6127
|
-
"name": "--ms-input-size-sm-font",
|
|
6128
|
-
"description": "SM size font"
|
|
6129
|
-
},
|
|
6130
|
-
{
|
|
6131
|
-
"name": "--ms-input-size-sm-padding-v",
|
|
6132
|
-
"description": "SM vertical padding"
|
|
6133
|
-
},
|
|
6134
|
-
{
|
|
6135
|
-
"name": "--ms-input-size-sm-padding-h",
|
|
6136
|
-
"description": "SM horizontal padding"
|
|
6137
|
-
},
|
|
6138
|
-
{
|
|
6139
|
-
"name": "--ms-input-size-sm-height",
|
|
6140
|
-
"description": "SM input height"
|
|
6141
|
-
},
|
|
6142
|
-
{
|
|
6143
|
-
"name": "--ms-input-size-md-font",
|
|
6144
|
-
"description": "MD size font"
|
|
6145
|
-
},
|
|
6146
|
-
{
|
|
6147
|
-
"name": "--ms-input-size-md-padding-v",
|
|
6148
|
-
"description": "MD vertical padding"
|
|
6149
|
-
},
|
|
6150
|
-
{
|
|
6151
|
-
"name": "--ms-input-size-md-padding-h",
|
|
6152
|
-
"description": "MD horizontal padding"
|
|
6153
|
-
},
|
|
6154
|
-
{
|
|
6155
|
-
"name": "--ms-input-size-md-height",
|
|
6156
|
-
"description": "MD input height"
|
|
6157
|
-
},
|
|
6158
|
-
{
|
|
6159
|
-
"name": "--ms-input-size-lg-font",
|
|
6160
|
-
"description": "LG size font"
|
|
6161
|
-
},
|
|
6162
|
-
{
|
|
6163
|
-
"name": "--ms-input-size-lg-padding-v",
|
|
6164
|
-
"description": "LG vertical padding"
|
|
6165
|
-
},
|
|
6166
|
-
{
|
|
6167
|
-
"name": "--ms-input-size-lg-padding-h",
|
|
6168
|
-
"description": "LG horizontal padding"
|
|
6169
|
-
},
|
|
6170
|
-
{
|
|
6171
|
-
"name": "--ms-input-size-lg-height",
|
|
6172
|
-
"description": "LG input height"
|
|
6173
|
-
},
|
|
6174
|
-
{
|
|
6175
|
-
"name": "--ms-input-size-xl-font",
|
|
6176
|
-
"description": "XL size font"
|
|
6177
|
-
},
|
|
6178
|
-
{
|
|
6179
|
-
"name": "--ms-input-size-xl-padding-v",
|
|
6180
|
-
"description": "XL vertical padding"
|
|
6181
|
-
},
|
|
6182
|
-
{
|
|
6183
|
-
"name": "--ms-input-size-xl-padding-h",
|
|
6184
|
-
"description": "XL horizontal padding"
|
|
6185
|
-
},
|
|
6186
|
-
{
|
|
6187
|
-
"name": "--ms-input-size-xl-height",
|
|
6188
|
-
"description": "XL input height"
|
|
6189
|
-
},
|
|
6190
|
-
{
|
|
6191
|
-
"name": "--ms-toggle-right",
|
|
6192
|
-
"description": "Toggle icon right position"
|
|
6193
|
-
},
|
|
6194
6551
|
{
|
|
6195
6552
|
"name": "--ms-toggle-color",
|
|
6196
6553
|
"description": "Toggle icon color"
|
|
@@ -6203,10 +6560,6 @@
|
|
|
6203
6560
|
"name": "--ms-toggle-icon-color-open",
|
|
6204
6561
|
"description": "Toggle icon color when open"
|
|
6205
6562
|
},
|
|
6206
|
-
{
|
|
6207
|
-
"name": "--ms-counter-offset",
|
|
6208
|
-
"description": "Counter badge offset"
|
|
6209
|
-
},
|
|
6210
6563
|
{
|
|
6211
6564
|
"name": "--ms-counter-padding",
|
|
6212
6565
|
"description": "Counter badge padding"
|
|
@@ -6807,6 +7160,18 @@
|
|
|
6807
7160
|
"name": "--ms-icon-remove",
|
|
6808
7161
|
"description": "Remove icon as CSS url() to a mask-friendly SVG; color comes from currentColor"
|
|
6809
7162
|
},
|
|
7163
|
+
{
|
|
7164
|
+
"name": "--ms-icon-filter",
|
|
7165
|
+
"description": "Funnel glyph (fullscreen search-mode toggle); chains to --base-icon-filter"
|
|
7166
|
+
},
|
|
7167
|
+
{
|
|
7168
|
+
"name": "--ms-icon-check",
|
|
7169
|
+
"description": "Checkmark glyph (mask) for a checked checkbox/option; chains to --base-icon-check"
|
|
7170
|
+
},
|
|
7171
|
+
{
|
|
7172
|
+
"name": "--ms-icon-indeterminate",
|
|
7173
|
+
"description": "Dash glyph (mask) for a tri-state/partial checkbox; chains to --base-icon-indeterminate"
|
|
7174
|
+
},
|
|
6810
7175
|
{
|
|
6811
7176
|
"name": "--ms-badge-counter-bg",
|
|
6812
7177
|
"description": "Counter badge background"
|
|
@@ -7259,10 +7624,6 @@
|
|
|
7259
7624
|
"name": "--ms-debug-bullet-color",
|
|
7260
7625
|
"description": "Debug stat bullet marker color"
|
|
7261
7626
|
},
|
|
7262
|
-
{
|
|
7263
|
-
"name": "--ms-transform-center-y",
|
|
7264
|
-
"description": "Center Y transform"
|
|
7265
|
-
},
|
|
7266
7627
|
{
|
|
7267
7628
|
"name": "--ms-transform-rotate-180",
|
|
7268
7629
|
"description": "180 degree rotation"
|