@khanacademy/wonder-blocks-dropdown 5.8.1 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/dist/components/combobox-live-region.d.ts +2 -2
- package/dist/components/combobox.d.ts +1 -1
- package/dist/components/dropdown-core-virtualized.d.ts +1 -1
- package/dist/components/dropdown-opener.d.ts +8 -0
- package/dist/components/listbox.d.ts +2 -2
- package/dist/components/multi-select.d.ts +44 -60
- package/dist/components/select-opener.d.ts +4 -0
- package/dist/components/single-select.d.ts +40 -42
- package/dist/es/index.js +475 -418
- package/dist/hooks/use-listbox.d.ts +1 -1
- package/dist/hooks/use-select-validation.d.ts +39 -0
- package/dist/index.js +474 -417
- package/dist/util/constants.d.ts +10 -7
- package/package.json +19 -19
package/dist/index.js
CHANGED
|
@@ -61,13 +61,12 @@ var xIcon__default = /*#__PURE__*/_interopDefaultLegacy(xIcon);
|
|
|
61
61
|
var IconButton__default = /*#__PURE__*/_interopDefaultLegacy(IconButton);
|
|
62
62
|
var Pill__default = /*#__PURE__*/_interopDefaultLegacy(Pill);
|
|
63
63
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
down: 40
|
|
64
|
+
const keys = {
|
|
65
|
+
escape: "Escape",
|
|
66
|
+
tab: "Tab",
|
|
67
|
+
space: " ",
|
|
68
|
+
up: "ArrowUp",
|
|
69
|
+
down: "ArrowDown"
|
|
71
70
|
};
|
|
72
71
|
const selectDropdownStyle = {
|
|
73
72
|
marginTop: tokens.spacing.xSmall_8,
|
|
@@ -531,7 +530,9 @@ class DropdownOpener extends React__namespace.Component {
|
|
|
531
530
|
opened,
|
|
532
531
|
"aria-controls": ariaControls,
|
|
533
532
|
"aria-haspopup": ariaHasPopUp,
|
|
534
|
-
|
|
533
|
+
"aria-required": ariaRequired,
|
|
534
|
+
id,
|
|
535
|
+
onBlur
|
|
535
536
|
} = this.props;
|
|
536
537
|
const renderedChildren = this.props.children(_extends__default["default"]({}, eventState, {
|
|
537
538
|
text,
|
|
@@ -540,16 +541,19 @@ class DropdownOpener extends React__namespace.Component {
|
|
|
540
541
|
const childrenProps = renderedChildren.props;
|
|
541
542
|
const childrenTestId = this.getTestIdFromProps(childrenProps);
|
|
542
543
|
return React__namespace.cloneElement(renderedChildren, _extends__default["default"]({}, clickableChildrenProps, {
|
|
544
|
+
"aria-invalid": this.props.error,
|
|
543
545
|
disabled,
|
|
544
546
|
"aria-controls": ariaControls,
|
|
545
547
|
id,
|
|
546
548
|
"aria-expanded": opened ? "true" : "false",
|
|
547
549
|
"aria-haspopup": ariaHasPopUp,
|
|
550
|
+
"aria-required": ariaRequired,
|
|
548
551
|
onClick: childrenProps.onClick ? e => {
|
|
549
552
|
childrenProps.onClick(e);
|
|
550
553
|
clickableChildrenProps.onClick(e);
|
|
551
554
|
} : clickableChildrenProps.onClick,
|
|
552
|
-
"data-testid": childrenTestId || testId
|
|
555
|
+
"data-testid": childrenTestId || testId,
|
|
556
|
+
onBlur
|
|
553
557
|
}));
|
|
554
558
|
}
|
|
555
559
|
render() {
|
|
@@ -861,13 +865,13 @@ class DropdownCore extends React__namespace.Component {
|
|
|
861
865
|
}
|
|
862
866
|
constructor(props) {
|
|
863
867
|
super(props);
|
|
864
|
-
this.focusedIndex = void 0;
|
|
865
|
-
this.focusedOriginalIndex = void 0;
|
|
866
|
-
this.itemsClicked = void 0;
|
|
867
868
|
this.popperElement = void 0;
|
|
868
869
|
this.virtualizedListRef = void 0;
|
|
869
870
|
this.handleKeyDownDebounced = void 0;
|
|
870
871
|
this.textSuggestion = void 0;
|
|
872
|
+
this.focusedIndex = -1;
|
|
873
|
+
this.focusedOriginalIndex = -1;
|
|
874
|
+
this.itemsClicked = false;
|
|
871
875
|
this.searchFieldRef = React__namespace.createRef();
|
|
872
876
|
this.handleInteract = event => {
|
|
873
877
|
const {
|
|
@@ -887,39 +891,39 @@ class DropdownCore extends React__namespace.Component {
|
|
|
887
891
|
open,
|
|
888
892
|
searchText
|
|
889
893
|
} = this.props;
|
|
890
|
-
const
|
|
891
|
-
if (enableTypeAhead && getStringForKey(
|
|
894
|
+
const key = event.key;
|
|
895
|
+
if (enableTypeAhead && getStringForKey(key)) {
|
|
892
896
|
event.stopPropagation();
|
|
893
|
-
this.textSuggestion +=
|
|
897
|
+
this.textSuggestion += key;
|
|
894
898
|
this.handleKeyDownDebounced(this.textSuggestion);
|
|
895
899
|
}
|
|
896
900
|
if (!open) {
|
|
897
|
-
if (
|
|
901
|
+
if (key === keys.down) {
|
|
898
902
|
event.preventDefault();
|
|
899
903
|
onOpenChanged(true);
|
|
900
904
|
return;
|
|
901
905
|
}
|
|
902
906
|
return;
|
|
903
907
|
}
|
|
904
|
-
switch (
|
|
905
|
-
case
|
|
908
|
+
switch (key) {
|
|
909
|
+
case keys.tab:
|
|
906
910
|
if (this.isSearchFieldFocused() && searchText) {
|
|
907
911
|
return;
|
|
908
912
|
}
|
|
909
913
|
this.restoreTabOrder();
|
|
910
914
|
onOpenChanged(false);
|
|
911
915
|
return;
|
|
912
|
-
case
|
|
916
|
+
case keys.space:
|
|
913
917
|
if (this.isSearchFieldFocused()) {
|
|
914
918
|
return;
|
|
915
919
|
}
|
|
916
920
|
event.preventDefault();
|
|
917
921
|
return;
|
|
918
|
-
case
|
|
922
|
+
case keys.up:
|
|
919
923
|
event.preventDefault();
|
|
920
924
|
this.focusPreviousItem();
|
|
921
925
|
return;
|
|
922
|
-
case
|
|
926
|
+
case keys.down:
|
|
923
927
|
event.preventDefault();
|
|
924
928
|
this.focusNextItem();
|
|
925
929
|
return;
|
|
@@ -930,15 +934,15 @@ class DropdownCore extends React__namespace.Component {
|
|
|
930
934
|
onOpenChanged,
|
|
931
935
|
open
|
|
932
936
|
} = this.props;
|
|
933
|
-
const
|
|
934
|
-
switch (
|
|
935
|
-
case
|
|
937
|
+
const key = event.key;
|
|
938
|
+
switch (key) {
|
|
939
|
+
case keys.space:
|
|
936
940
|
if (this.isSearchFieldFocused()) {
|
|
937
941
|
return;
|
|
938
942
|
}
|
|
939
943
|
event.preventDefault();
|
|
940
944
|
return;
|
|
941
|
-
case
|
|
945
|
+
case keys.escape:
|
|
942
946
|
if (open) {
|
|
943
947
|
event.stopPropagation();
|
|
944
948
|
this.restoreTabOrder();
|
|
@@ -1111,18 +1115,37 @@ class DropdownCore extends React__namespace.Component {
|
|
|
1111
1115
|
}
|
|
1112
1116
|
focusCurrentItem(onFocus) {
|
|
1113
1117
|
const focusedItemRef = this.state.itemRefs[this.focusedIndex];
|
|
1114
|
-
if (focusedItemRef) {
|
|
1115
|
-
|
|
1116
|
-
|
|
1118
|
+
if (!focusedItemRef) {
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
const {
|
|
1122
|
+
current: virtualizedList
|
|
1123
|
+
} = this.virtualizedListRef;
|
|
1124
|
+
if (virtualizedList) {
|
|
1125
|
+
virtualizedList.scrollToItem(focusedItemRef.originalIndex);
|
|
1126
|
+
}
|
|
1127
|
+
const focusNode = () => {
|
|
1128
|
+
if (!this.props.open) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
const currentFocusedItemRef = this.state.itemRefs[this.focusedIndex];
|
|
1132
|
+
const node = ReactDOM__namespace.findDOMNode(currentFocusedItemRef.ref.current);
|
|
1133
|
+
if (!node && this.shouldVirtualizeList()) {
|
|
1134
|
+
this.props.schedule.animationFrame(focusNode);
|
|
1135
|
+
return;
|
|
1117
1136
|
}
|
|
1118
|
-
const node = ReactDOM__namespace.findDOMNode(focusedItemRef.ref.current);
|
|
1119
1137
|
if (node) {
|
|
1120
1138
|
node.focus();
|
|
1121
|
-
this.focusedOriginalIndex =
|
|
1139
|
+
this.focusedOriginalIndex = currentFocusedItemRef.originalIndex;
|
|
1122
1140
|
if (onFocus) {
|
|
1123
1141
|
onFocus(node);
|
|
1124
1142
|
}
|
|
1125
1143
|
}
|
|
1144
|
+
};
|
|
1145
|
+
if (this.shouldVirtualizeList()) {
|
|
1146
|
+
this.props.schedule.animationFrame(focusNode);
|
|
1147
|
+
} else {
|
|
1148
|
+
focusNode();
|
|
1126
1149
|
}
|
|
1127
1150
|
}
|
|
1128
1151
|
focusSearchField() {
|
|
@@ -1142,7 +1165,7 @@ class DropdownCore extends React__namespace.Component {
|
|
|
1142
1165
|
return this.focusSearchField();
|
|
1143
1166
|
}
|
|
1144
1167
|
this.focusedIndex = this.state.itemRefs.length - 1;
|
|
1145
|
-
} else {
|
|
1168
|
+
} else if (!this.isSearchFieldFocused()) {
|
|
1146
1169
|
this.focusedIndex -= 1;
|
|
1147
1170
|
}
|
|
1148
1171
|
this.scheduleToFocusCurrentItem();
|
|
@@ -1153,7 +1176,7 @@ class DropdownCore extends React__namespace.Component {
|
|
|
1153
1176
|
return this.focusSearchField();
|
|
1154
1177
|
}
|
|
1155
1178
|
this.focusedIndex = 0;
|
|
1156
|
-
} else {
|
|
1179
|
+
} else if (!this.isSearchFieldFocused()) {
|
|
1157
1180
|
this.focusedIndex += 1;
|
|
1158
1181
|
}
|
|
1159
1182
|
this.scheduleToFocusCurrentItem();
|
|
@@ -1235,7 +1258,7 @@ class DropdownCore extends React__namespace.Component {
|
|
|
1235
1258
|
const focusIndex = focusCounter - 1;
|
|
1236
1259
|
return _extends__default["default"]({}, item, {
|
|
1237
1260
|
role: populatedProps.role || itemRole,
|
|
1238
|
-
ref: item.focusable
|
|
1261
|
+
ref: item.focusable && this.state.itemRefs[focusIndex] ? this.state.itemRefs[focusIndex].ref : null,
|
|
1239
1262
|
onClick: () => {
|
|
1240
1263
|
this.handleItemClick(focusIndex, item);
|
|
1241
1264
|
}
|
|
@@ -1696,7 +1719,7 @@ const styles$5 = aphrodite.StyleSheet.create({
|
|
|
1696
1719
|
}
|
|
1697
1720
|
});
|
|
1698
1721
|
|
|
1699
|
-
const _excluded$2 = ["children", "disabled", "error", "id", "isPlaceholder", "light", "open", "testId", "onOpenChanged"];
|
|
1722
|
+
const _excluded$2 = ["children", "disabled", "error", "id", "isPlaceholder", "light", "open", "testId", "aria-required", "onBlur", "onOpenChanged"];
|
|
1700
1723
|
const StyledButton = wonderBlocksCore.addStyle("button");
|
|
1701
1724
|
class SelectOpener extends React__namespace.Component {
|
|
1702
1725
|
constructor(props) {
|
|
@@ -1739,7 +1762,9 @@ class SelectOpener extends React__namespace.Component {
|
|
|
1739
1762
|
isPlaceholder,
|
|
1740
1763
|
light,
|
|
1741
1764
|
open,
|
|
1742
|
-
testId
|
|
1765
|
+
testId,
|
|
1766
|
+
"aria-required": ariaRequired,
|
|
1767
|
+
onBlur
|
|
1743
1768
|
} = _this$props,
|
|
1744
1769
|
sharedProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded$2);
|
|
1745
1770
|
const stateStyles = _generateStyles(light, isPlaceholder, error);
|
|
@@ -1748,6 +1773,8 @@ class SelectOpener extends React__namespace.Component {
|
|
|
1748
1773
|
return React__namespace.createElement(StyledButton, _extends__default["default"]({}, sharedProps, {
|
|
1749
1774
|
"aria-disabled": disabled,
|
|
1750
1775
|
"aria-expanded": open ? "true" : "false",
|
|
1776
|
+
"aria-invalid": error,
|
|
1777
|
+
"aria-required": ariaRequired,
|
|
1751
1778
|
"aria-haspopup": "listbox",
|
|
1752
1779
|
"data-testid": testId,
|
|
1753
1780
|
id: id,
|
|
@@ -1755,7 +1782,8 @@ class SelectOpener extends React__namespace.Component {
|
|
|
1755
1782
|
type: "button",
|
|
1756
1783
|
onClick: !disabled ? this.handleClick : undefined,
|
|
1757
1784
|
onKeyDown: !disabled ? this.handleKeyDown : undefined,
|
|
1758
|
-
onKeyUp: !disabled ? this.handleKeyUp : undefined
|
|
1785
|
+
onKeyUp: !disabled ? this.handleKeyUp : undefined,
|
|
1786
|
+
onBlur: onBlur
|
|
1759
1787
|
}), React__namespace.createElement(wonderBlocksTypography.LabelMedium, {
|
|
1760
1788
|
style: styles$4.text
|
|
1761
1789
|
}, children || "\u00A0"), React__namespace.createElement(wonderBlocksIcon.PhosphorIcon, {
|
|
@@ -1904,117 +1932,206 @@ const _generateStyles = (light, placeholder, error) => {
|
|
|
1904
1932
|
return stateStyles[styleKey];
|
|
1905
1933
|
};
|
|
1906
1934
|
|
|
1907
|
-
const
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1935
|
+
const defaultErrorMessage = "This field is required.";
|
|
1936
|
+
function hasValue(value) {
|
|
1937
|
+
return value ? value.length > 0 : false;
|
|
1938
|
+
}
|
|
1939
|
+
function useSelectValidation({
|
|
1940
|
+
value,
|
|
1941
|
+
disabled = false,
|
|
1942
|
+
validate,
|
|
1943
|
+
onValidate,
|
|
1944
|
+
required,
|
|
1945
|
+
open
|
|
1946
|
+
}) {
|
|
1947
|
+
const [errorMessage, setErrorMessage] = React__namespace.useState(() => validate && hasValue(value) && !disabled && validate(value) || null);
|
|
1948
|
+
const handleValidation = React__namespace.useCallback(newValue => {
|
|
1949
|
+
if (disabled) {
|
|
1950
|
+
return;
|
|
1951
|
+
}
|
|
1952
|
+
if (validate) {
|
|
1953
|
+
const error = newValue !== undefined && validate(newValue) || null;
|
|
1954
|
+
setErrorMessage(error);
|
|
1955
|
+
if (onValidate) {
|
|
1956
|
+
onValidate(error);
|
|
1919
1957
|
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
if (selectedValue !== this.props.selectedValue) {
|
|
1923
|
-
this.props.onChange(selectedValue);
|
|
1958
|
+
if (error) {
|
|
1959
|
+
return;
|
|
1924
1960
|
}
|
|
1925
|
-
|
|
1926
|
-
|
|
1961
|
+
}
|
|
1962
|
+
if (required) {
|
|
1963
|
+
const requiredString = typeof required === "string" ? required : defaultErrorMessage;
|
|
1964
|
+
const error = hasValue(newValue) ? null : requiredString;
|
|
1965
|
+
setErrorMessage(error);
|
|
1966
|
+
if (onValidate) {
|
|
1967
|
+
onValidate(error);
|
|
1927
1968
|
}
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1969
|
+
}
|
|
1970
|
+
}, [disabled, validate, setErrorMessage, onValidate, required]);
|
|
1971
|
+
wonderBlocksCore.useOnMountEffect(() => {
|
|
1972
|
+
if (hasValue(value)) {
|
|
1973
|
+
handleValidation(value);
|
|
1974
|
+
}
|
|
1975
|
+
});
|
|
1976
|
+
function onOpenerBlurValidation() {
|
|
1977
|
+
if (!open && required && !hasValue(value)) {
|
|
1978
|
+
handleValidation(value);
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
const onDropdownClosedValidation = () => {
|
|
1982
|
+
if (required && !hasValue(value)) {
|
|
1983
|
+
handleValidation(value);
|
|
1984
|
+
}
|
|
1985
|
+
};
|
|
1986
|
+
const onSelectionValidation = newValue => {
|
|
1987
|
+
handleValidation(newValue);
|
|
1988
|
+
};
|
|
1989
|
+
const onSelectedValuesChangeValidation = () => {
|
|
1990
|
+
setErrorMessage(null);
|
|
1991
|
+
if (onValidate) {
|
|
1992
|
+
onValidate(null);
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
return {
|
|
1996
|
+
errorMessage,
|
|
1997
|
+
onOpenerBlurValidation,
|
|
1998
|
+
onDropdownClosedValidation,
|
|
1999
|
+
onSelectionValidation,
|
|
2000
|
+
onSelectedValuesChangeValidation
|
|
2001
|
+
};
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
const _excluded$1 = ["children", "error", "id", "opener", "light", "placeholder", "selectedValue", "testId", "alignment", "autoFocus", "dropdownStyle", "enableTypeAhead", "isFilterable", "labels", "onChange", "onToggle", "opened", "style", "className", "aria-invalid", "aria-required", "disabled", "dropdownId", "validate", "onValidate", "required", "showOpenerLabelAsText"];
|
|
2005
|
+
const SingleSelect = props => {
|
|
2006
|
+
const selectedIndex = React__namespace.useRef(0);
|
|
2007
|
+
const {
|
|
2008
|
+
children,
|
|
2009
|
+
error = false,
|
|
2010
|
+
id,
|
|
2011
|
+
opener,
|
|
2012
|
+
light = false,
|
|
2013
|
+
placeholder,
|
|
2014
|
+
selectedValue,
|
|
2015
|
+
testId,
|
|
2016
|
+
alignment = "left",
|
|
2017
|
+
autoFocus = true,
|
|
2018
|
+
dropdownStyle,
|
|
2019
|
+
enableTypeAhead = true,
|
|
2020
|
+
isFilterable,
|
|
2021
|
+
labels = {
|
|
2022
|
+
clearSearch: defaultLabels.clearSearch,
|
|
2023
|
+
filter: defaultLabels.filter,
|
|
2024
|
+
noResults: defaultLabels.noResults,
|
|
2025
|
+
someResults: defaultLabels.someSelected
|
|
2026
|
+
},
|
|
2027
|
+
onChange,
|
|
2028
|
+
onToggle,
|
|
2029
|
+
opened,
|
|
2030
|
+
style,
|
|
2031
|
+
className,
|
|
2032
|
+
"aria-invalid": ariaInvalid,
|
|
2033
|
+
"aria-required": ariaRequired,
|
|
2034
|
+
disabled = false,
|
|
2035
|
+
dropdownId,
|
|
2036
|
+
validate,
|
|
2037
|
+
onValidate,
|
|
2038
|
+
required,
|
|
2039
|
+
showOpenerLabelAsText = true
|
|
2040
|
+
} = props,
|
|
2041
|
+
sharedProps = _objectWithoutPropertiesLoose__default["default"](props, _excluded$1);
|
|
2042
|
+
const [open, setOpen] = React__namespace.useState(false);
|
|
2043
|
+
const [searchText, setSearchText] = React__namespace.useState("");
|
|
2044
|
+
const [openerElement, setOpenerElement] = React__namespace.useState();
|
|
2045
|
+
const {
|
|
2046
|
+
errorMessage,
|
|
2047
|
+
onOpenerBlurValidation,
|
|
2048
|
+
onDropdownClosedValidation,
|
|
2049
|
+
onSelectionValidation
|
|
2050
|
+
} = useSelectValidation({
|
|
2051
|
+
value: selectedValue,
|
|
2052
|
+
disabled,
|
|
2053
|
+
validate,
|
|
2054
|
+
onValidate,
|
|
2055
|
+
required,
|
|
2056
|
+
open
|
|
2057
|
+
});
|
|
2058
|
+
const hasError = error || !!errorMessage;
|
|
2059
|
+
React__namespace.useEffect(() => {
|
|
2060
|
+
if (disabled) {
|
|
2061
|
+
setOpen(false);
|
|
2062
|
+
} else if (typeof opened === "boolean") {
|
|
2063
|
+
setOpen(opened);
|
|
2064
|
+
}
|
|
2065
|
+
}, [disabled, opened]);
|
|
2066
|
+
const handleOpenChanged = opened => {
|
|
2067
|
+
setOpen(opened);
|
|
2068
|
+
setSearchText("");
|
|
2069
|
+
if (onToggle) {
|
|
2070
|
+
onToggle(opened);
|
|
2071
|
+
}
|
|
2072
|
+
if (!opened) {
|
|
2073
|
+
onDropdownClosedValidation();
|
|
2074
|
+
}
|
|
2075
|
+
};
|
|
2076
|
+
const handleToggle = newSelectedValue => {
|
|
2077
|
+
if (newSelectedValue !== selectedValue) {
|
|
2078
|
+
onChange(newSelectedValue);
|
|
2079
|
+
}
|
|
2080
|
+
if (open && openerElement) {
|
|
2081
|
+
openerElement.focus();
|
|
2082
|
+
}
|
|
2083
|
+
setOpen(false);
|
|
2084
|
+
if (onToggle) {
|
|
2085
|
+
onToggle(false);
|
|
2086
|
+
}
|
|
2087
|
+
onSelectionValidation(newSelectedValue);
|
|
2088
|
+
};
|
|
2089
|
+
const mapOptionItemsToDropdownItems = children => {
|
|
2090
|
+
let indexCounter = 0;
|
|
2091
|
+
selectedIndex.current = 0;
|
|
2092
|
+
return children.map(option => {
|
|
2093
|
+
const {
|
|
2094
|
+
disabled,
|
|
2095
|
+
value
|
|
2096
|
+
} = option.props;
|
|
2097
|
+
const selected = selectedValue === value;
|
|
2098
|
+
if (selected) {
|
|
2099
|
+
selectedIndex.current = indexCounter;
|
|
1933
2100
|
}
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
value
|
|
1945
|
-
} = option.props;
|
|
1946
|
-
const selected = selectedValue === value;
|
|
1947
|
-
if (selected) {
|
|
1948
|
-
this.selectedIndex = indexCounter;
|
|
1949
|
-
}
|
|
1950
|
-
if (!disabled) {
|
|
1951
|
-
indexCounter += 1;
|
|
2101
|
+
if (!disabled) {
|
|
2102
|
+
indexCounter += 1;
|
|
2103
|
+
}
|
|
2104
|
+
return {
|
|
2105
|
+
component: option,
|
|
2106
|
+
focusable: !disabled,
|
|
2107
|
+
populatedProps: {
|
|
2108
|
+
onToggle: handleToggle,
|
|
2109
|
+
selected: selected,
|
|
2110
|
+
variant: "check"
|
|
1952
2111
|
}
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
onToggle: this.handleToggle,
|
|
1958
|
-
selected: selected,
|
|
1959
|
-
variant: "check"
|
|
1960
|
-
}
|
|
1961
|
-
};
|
|
1962
|
-
});
|
|
1963
|
-
};
|
|
1964
|
-
this.handleSearchTextChanged = searchText => {
|
|
1965
|
-
this.setState({
|
|
1966
|
-
searchText
|
|
1967
|
-
});
|
|
1968
|
-
};
|
|
1969
|
-
this.handleOpenerRef = node => {
|
|
1970
|
-
const openerElement = ReactDOM__namespace.findDOMNode(node);
|
|
1971
|
-
this.setState({
|
|
1972
|
-
openerElement
|
|
1973
|
-
});
|
|
1974
|
-
};
|
|
1975
|
-
this.handleClick = e => {
|
|
1976
|
-
this.handleOpenChanged(!this.state.open);
|
|
1977
|
-
};
|
|
1978
|
-
this.selectedIndex = 0;
|
|
1979
|
-
this.state = {
|
|
1980
|
-
open: false,
|
|
1981
|
-
searchText: ""
|
|
1982
|
-
};
|
|
1983
|
-
}
|
|
1984
|
-
static getDerivedStateFromProps(props, state) {
|
|
1985
|
-
return {
|
|
1986
|
-
open: props.disabled ? false : typeof props.opened === "boolean" ? props.opened : state.open
|
|
1987
|
-
};
|
|
1988
|
-
}
|
|
1989
|
-
filterChildren(children) {
|
|
1990
|
-
const {
|
|
1991
|
-
searchText
|
|
1992
|
-
} = this.state;
|
|
2112
|
+
};
|
|
2113
|
+
});
|
|
2114
|
+
};
|
|
2115
|
+
const filterChildren = children => {
|
|
1993
2116
|
const lowercasedSearchText = searchText.toLowerCase();
|
|
1994
2117
|
return children.filter(({
|
|
1995
2118
|
props
|
|
1996
2119
|
}) => !searchText || getLabel(props).toLowerCase().indexOf(lowercasedSearchText) > -1);
|
|
1997
|
-
}
|
|
1998
|
-
getMenuItems
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
}
|
|
2004
|
-
|
|
2005
|
-
const
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
placeholder,
|
|
2013
|
-
selectedValue,
|
|
2014
|
-
testId,
|
|
2015
|
-
showOpenerLabelAsText
|
|
2016
|
-
} = _this$props,
|
|
2017
|
-
sharedProps = _objectWithoutPropertiesLoose__default["default"](_this$props, _excluded$1);
|
|
2120
|
+
};
|
|
2121
|
+
const getMenuItems = children => {
|
|
2122
|
+
return mapOptionItemsToDropdownItems(isFilterable ? filterChildren(children) : children);
|
|
2123
|
+
};
|
|
2124
|
+
const handleSearchTextChanged = searchText => {
|
|
2125
|
+
setSearchText(searchText);
|
|
2126
|
+
};
|
|
2127
|
+
const handleOpenerRef = node => {
|
|
2128
|
+
const openerElement = ReactDOM__namespace.findDOMNode(node);
|
|
2129
|
+
setOpenerElement(openerElement);
|
|
2130
|
+
};
|
|
2131
|
+
const handleClick = e => {
|
|
2132
|
+
handleOpenChanged(!open);
|
|
2133
|
+
};
|
|
2134
|
+
const renderOpener = (isDisabled, dropdownId) => {
|
|
2018
2135
|
const items = React__namespace.Children.toArray(children);
|
|
2019
2136
|
const selectedItem = items.find(option => option.props.value === selectedValue);
|
|
2020
2137
|
const menuText = selectedItem ? getSelectOpenerLabel(showOpenerLabelAsText, selectedItem.props) : placeholder;
|
|
@@ -2026,202 +2143,160 @@ class SingleSelect extends React__namespace.Component {
|
|
|
2026
2143
|
id: uniqueOpenerId,
|
|
2027
2144
|
"aria-controls": dropdownId,
|
|
2028
2145
|
"aria-haspopup": "listbox",
|
|
2029
|
-
onClick:
|
|
2146
|
+
onClick: handleClick,
|
|
2030
2147
|
disabled: isDisabled,
|
|
2031
|
-
ref:
|
|
2148
|
+
ref: handleOpenerRef,
|
|
2032
2149
|
text: menuText,
|
|
2033
|
-
opened:
|
|
2150
|
+
opened: open,
|
|
2151
|
+
error: hasError,
|
|
2152
|
+
onBlur: onOpenerBlurValidation
|
|
2034
2153
|
}, opener) : React__namespace.createElement(SelectOpener, _extends__default["default"]({}, sharedProps, {
|
|
2035
2154
|
"aria-controls": dropdownId,
|
|
2036
2155
|
disabled: isDisabled,
|
|
2037
2156
|
id: uniqueOpenerId,
|
|
2038
|
-
error:
|
|
2157
|
+
error: hasError,
|
|
2039
2158
|
isPlaceholder: !selectedItem,
|
|
2040
2159
|
light: light,
|
|
2041
|
-
onOpenChanged:
|
|
2042
|
-
open:
|
|
2043
|
-
ref:
|
|
2044
|
-
testId: testId
|
|
2160
|
+
onOpenChanged: handleOpenChanged,
|
|
2161
|
+
open: open,
|
|
2162
|
+
ref: handleOpenerRef,
|
|
2163
|
+
testId: testId,
|
|
2164
|
+
onBlur: onOpenerBlurValidation
|
|
2045
2165
|
}), menuText);
|
|
2046
2166
|
});
|
|
2047
2167
|
return dropdownOpener;
|
|
2048
|
-
}
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2168
|
+
};
|
|
2169
|
+
const allChildren = React__namespace.Children.toArray(children).filter(Boolean);
|
|
2170
|
+
const numEnabledOptions = allChildren.filter(option => !option.props.disabled).length;
|
|
2171
|
+
const items = getMenuItems(allChildren);
|
|
2172
|
+
const isDisabled = numEnabledOptions === 0 || disabled;
|
|
2173
|
+
return React__namespace.createElement(wonderBlocksCore.IDProvider, {
|
|
2174
|
+
id: dropdownId,
|
|
2175
|
+
scope: "single-select-dropdown"
|
|
2176
|
+
}, uniqueDropdownId => React__namespace.createElement(DropdownCore$1, {
|
|
2177
|
+
id: uniqueDropdownId,
|
|
2178
|
+
role: "listbox",
|
|
2179
|
+
selectionType: "single",
|
|
2180
|
+
alignment: alignment,
|
|
2181
|
+
autoFocus: autoFocus,
|
|
2182
|
+
enableTypeAhead: enableTypeAhead,
|
|
2183
|
+
dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
|
|
2184
|
+
initialFocusedIndex: selectedIndex.current,
|
|
2185
|
+
items: items,
|
|
2186
|
+
light: light,
|
|
2187
|
+
onOpenChanged: handleOpenChanged,
|
|
2188
|
+
open: open,
|
|
2189
|
+
opener: renderOpener(isDisabled, uniqueDropdownId),
|
|
2190
|
+
openerElement: openerElement,
|
|
2191
|
+
style: style,
|
|
2192
|
+
className: className,
|
|
2193
|
+
isFilterable: isFilterable,
|
|
2194
|
+
onSearchTextChanged: isFilterable ? handleSearchTextChanged : undefined,
|
|
2195
|
+
searchText: isFilterable ? searchText : "",
|
|
2196
|
+
labels: labels,
|
|
2197
|
+
"aria-invalid": ariaInvalid,
|
|
2198
|
+
"aria-required": ariaRequired,
|
|
2199
|
+
disabled: isDisabled
|
|
2200
|
+
}));
|
|
2201
|
+
};
|
|
2202
|
+
|
|
2203
|
+
const _excluded = ["id", "light", "opener", "testId", "alignment", "dropdownStyle", "implicitAllEnabled", "isFilterable", "labels", "onChange", "onToggle", "opened", "selectedValues", "shortcuts", "style", "className", "aria-invalid", "aria-required", "disabled", "error", "children", "dropdownId", "showOpenerLabelAsText", "validate", "onValidate", "required"];
|
|
2204
|
+
const MultiSelect = props => {
|
|
2205
|
+
const {
|
|
2206
|
+
id,
|
|
2207
|
+
light = false,
|
|
2208
|
+
opener,
|
|
2209
|
+
testId,
|
|
2210
|
+
alignment = "left",
|
|
2055
2211
|
dropdownStyle,
|
|
2056
|
-
|
|
2212
|
+
implicitAllEnabled,
|
|
2057
2213
|
isFilterable,
|
|
2058
|
-
labels,
|
|
2059
|
-
|
|
2214
|
+
labels: propLabels,
|
|
2215
|
+
onChange,
|
|
2216
|
+
onToggle,
|
|
2217
|
+
opened,
|
|
2218
|
+
selectedValues = [],
|
|
2219
|
+
shortcuts = false,
|
|
2060
2220
|
style,
|
|
2221
|
+
className,
|
|
2061
2222
|
"aria-invalid": ariaInvalid,
|
|
2062
2223
|
"aria-required": ariaRequired,
|
|
2063
|
-
disabled,
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
labels: {
|
|
2111
|
-
clearSearch: defaultLabels.clearSearch,
|
|
2112
|
-
filter: defaultLabels.filter,
|
|
2113
|
-
noResults: defaultLabels.noResults,
|
|
2114
|
-
someResults: defaultLabels.someSelected
|
|
2115
|
-
},
|
|
2116
|
-
showOpenerLabelAsText: true
|
|
2117
|
-
};
|
|
2118
|
-
|
|
2119
|
-
const _excluded = ["id", "light", "opener", "testId", "alignment", "dropdownStyle", "implicitAllEnabled", "isFilterable", "labels", "onChange", "onToggle", "opened", "selectedValues", "shortcuts", "style", "className", "aria-invalid", "aria-required", "showOpenerLabelAsText"];
|
|
2120
|
-
class MultiSelect extends React__namespace.Component {
|
|
2121
|
-
constructor(props) {
|
|
2122
|
-
super(props);
|
|
2123
|
-
this.labels = void 0;
|
|
2124
|
-
this.handleOpenChanged = opened => {
|
|
2125
|
-
this.setState({
|
|
2126
|
-
open: opened,
|
|
2127
|
-
searchText: "",
|
|
2128
|
-
lastSelectedValues: this.props.selectedValues
|
|
2129
|
-
});
|
|
2130
|
-
if (this.props.onToggle) {
|
|
2131
|
-
this.props.onToggle(opened);
|
|
2132
|
-
}
|
|
2133
|
-
};
|
|
2134
|
-
this.handleToggle = selectedValue => {
|
|
2135
|
-
const {
|
|
2136
|
-
onChange,
|
|
2137
|
-
selectedValues
|
|
2138
|
-
} = this.props;
|
|
2139
|
-
if (selectedValues.includes(selectedValue)) {
|
|
2140
|
-
const index = selectedValues.indexOf(selectedValue);
|
|
2141
|
-
const updatedSelection = [...selectedValues.slice(0, index), ...selectedValues.slice(index + 1)];
|
|
2142
|
-
onChange(updatedSelection);
|
|
2224
|
+
disabled = false,
|
|
2225
|
+
error = false,
|
|
2226
|
+
children,
|
|
2227
|
+
dropdownId,
|
|
2228
|
+
showOpenerLabelAsText = true,
|
|
2229
|
+
validate,
|
|
2230
|
+
onValidate,
|
|
2231
|
+
required
|
|
2232
|
+
} = props,
|
|
2233
|
+
sharedProps = _objectWithoutPropertiesLoose__default["default"](props, _excluded);
|
|
2234
|
+
const labels = _extends__default["default"]({}, defaultLabels, propLabels);
|
|
2235
|
+
const [open, setOpen] = React__namespace.useState(false);
|
|
2236
|
+
const [searchText, setSearchText] = React__namespace.useState("");
|
|
2237
|
+
const [lastSelectedValues, setLastSelectedValues] = React__namespace.useState([]);
|
|
2238
|
+
const [openerElement, setOpenerElement] = React__namespace.useState();
|
|
2239
|
+
const {
|
|
2240
|
+
errorMessage,
|
|
2241
|
+
onOpenerBlurValidation,
|
|
2242
|
+
onDropdownClosedValidation,
|
|
2243
|
+
onSelectionValidation,
|
|
2244
|
+
onSelectedValuesChangeValidation
|
|
2245
|
+
} = useSelectValidation({
|
|
2246
|
+
value: selectedValues,
|
|
2247
|
+
disabled,
|
|
2248
|
+
validate,
|
|
2249
|
+
onValidate,
|
|
2250
|
+
required,
|
|
2251
|
+
open
|
|
2252
|
+
});
|
|
2253
|
+
const hasError = error || !!errorMessage;
|
|
2254
|
+
React__namespace.useEffect(() => {
|
|
2255
|
+
if (disabled) {
|
|
2256
|
+
setOpen(false);
|
|
2257
|
+
} else if (typeof opened === "boolean") {
|
|
2258
|
+
setOpen(opened);
|
|
2259
|
+
}
|
|
2260
|
+
}, [disabled, opened]);
|
|
2261
|
+
const handleOpenChanged = opened => {
|
|
2262
|
+
setOpen(opened);
|
|
2263
|
+
setSearchText("");
|
|
2264
|
+
setLastSelectedValues(selectedValues);
|
|
2265
|
+
if (onToggle) {
|
|
2266
|
+
onToggle(opened);
|
|
2267
|
+
}
|
|
2268
|
+
if (!opened) {
|
|
2269
|
+
if (lastSelectedValues !== selectedValues) {
|
|
2270
|
+
onSelectionValidation(selectedValues);
|
|
2143
2271
|
} else {
|
|
2144
|
-
|
|
2272
|
+
onDropdownClosedValidation();
|
|
2145
2273
|
}
|
|
2146
|
-
};
|
|
2147
|
-
this.handleSelectAll = () => {
|
|
2148
|
-
const {
|
|
2149
|
-
children,
|
|
2150
|
-
onChange
|
|
2151
|
-
} = this.props;
|
|
2152
|
-
const allChildren = React__namespace.Children.toArray(children);
|
|
2153
|
-
const selected = allChildren.filter(option => !!option && !option.props.disabled).map(option => option.props.value);
|
|
2154
|
-
onChange(selected);
|
|
2155
|
-
};
|
|
2156
|
-
this.handleSelectNone = () => {
|
|
2157
|
-
const {
|
|
2158
|
-
onChange
|
|
2159
|
-
} = this.props;
|
|
2160
|
-
onChange([]);
|
|
2161
|
-
};
|
|
2162
|
-
this.mapOptionItemToDropdownItem = option => {
|
|
2163
|
-
const {
|
|
2164
|
-
selectedValues
|
|
2165
|
-
} = this.props;
|
|
2166
|
-
const {
|
|
2167
|
-
disabled,
|
|
2168
|
-
value
|
|
2169
|
-
} = option.props;
|
|
2170
|
-
return {
|
|
2171
|
-
component: option,
|
|
2172
|
-
focusable: !disabled,
|
|
2173
|
-
populatedProps: {
|
|
2174
|
-
onToggle: this.handleToggle,
|
|
2175
|
-
selected: selectedValues.includes(value),
|
|
2176
|
-
variant: "checkbox"
|
|
2177
|
-
}
|
|
2178
|
-
};
|
|
2179
|
-
};
|
|
2180
|
-
this.handleOpenerRef = node => {
|
|
2181
|
-
const openerElement = ReactDOM__namespace.findDOMNode(node);
|
|
2182
|
-
this.setState({
|
|
2183
|
-
openerElement
|
|
2184
|
-
});
|
|
2185
|
-
};
|
|
2186
|
-
this.handleSearchTextChanged = searchText => {
|
|
2187
|
-
this.setState({
|
|
2188
|
-
searchText
|
|
2189
|
-
});
|
|
2190
|
-
};
|
|
2191
|
-
this.handleClick = e => {
|
|
2192
|
-
this.handleOpenChanged(!this.state.open);
|
|
2193
|
-
};
|
|
2194
|
-
this.state = {
|
|
2195
|
-
open: false,
|
|
2196
|
-
searchText: "",
|
|
2197
|
-
lastSelectedValues: [],
|
|
2198
|
-
labels: _extends__default["default"]({}, defaultLabels, props.labels)
|
|
2199
|
-
};
|
|
2200
|
-
this.labels = _extends__default["default"]({}, defaultLabels, props.labels);
|
|
2201
|
-
}
|
|
2202
|
-
static getDerivedStateFromProps(props, state) {
|
|
2203
|
-
return {
|
|
2204
|
-
open: props.disabled ? false : typeof props.opened === "boolean" ? props.opened : state.open
|
|
2205
|
-
};
|
|
2206
|
-
}
|
|
2207
|
-
componentDidUpdate(prevProps) {
|
|
2208
|
-
if (this.props.labels !== prevProps.labels) {
|
|
2209
|
-
this.setState({
|
|
2210
|
-
labels: _extends__default["default"]({}, this.state.labels, this.props.labels)
|
|
2211
|
-
});
|
|
2212
2274
|
}
|
|
2213
|
-
}
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
selectedValues,
|
|
2218
|
-
|
|
2219
|
-
}
|
|
2275
|
+
};
|
|
2276
|
+
const handleToggle = selectedValue => {
|
|
2277
|
+
if (selectedValues.includes(selectedValue)) {
|
|
2278
|
+
const index = selectedValues.indexOf(selectedValue);
|
|
2279
|
+
const updatedSelection = [...selectedValues.slice(0, index), ...selectedValues.slice(index + 1)];
|
|
2280
|
+
onChange(updatedSelection);
|
|
2281
|
+
} else {
|
|
2282
|
+
onChange([...selectedValues, selectedValue]);
|
|
2283
|
+
}
|
|
2284
|
+
onSelectedValuesChangeValidation();
|
|
2285
|
+
};
|
|
2286
|
+
const handleSelectAll = () => {
|
|
2287
|
+
const allChildren = React__namespace.Children.toArray(children);
|
|
2288
|
+
const selected = allChildren.filter(option => !!option && !option.props.disabled).map(option => option.props.value);
|
|
2289
|
+
onChange(selected);
|
|
2290
|
+
};
|
|
2291
|
+
const handleSelectNone = () => {
|
|
2292
|
+
onChange([]);
|
|
2293
|
+
};
|
|
2294
|
+
const getMenuText = children => {
|
|
2220
2295
|
const {
|
|
2221
2296
|
noneSelected,
|
|
2222
2297
|
someSelected,
|
|
2223
2298
|
allSelected
|
|
2224
|
-
} =
|
|
2299
|
+
} = labels;
|
|
2225
2300
|
const numSelectedAll = children.filter(option => !option.props.disabled).length;
|
|
2226
2301
|
const noSelectionText = implicitAllEnabled ? allSelected : noneSelected;
|
|
2227
2302
|
switch (selectedValues.length) {
|
|
@@ -2243,24 +2318,20 @@ class MultiSelect extends React__namespace.Component {
|
|
|
2243
2318
|
default:
|
|
2244
2319
|
return someSelected(selectedValues.length);
|
|
2245
2320
|
}
|
|
2246
|
-
}
|
|
2247
|
-
getShortcuts
|
|
2248
|
-
const {
|
|
2249
|
-
selectedValues,
|
|
2250
|
-
shortcuts
|
|
2251
|
-
} = this.props;
|
|
2321
|
+
};
|
|
2322
|
+
const getShortcuts = numOptions => {
|
|
2252
2323
|
const {
|
|
2253
2324
|
selectAllLabel,
|
|
2254
2325
|
selectNoneLabel
|
|
2255
|
-
} =
|
|
2256
|
-
if (shortcuts && !
|
|
2326
|
+
} = labels;
|
|
2327
|
+
if (shortcuts && !searchText) {
|
|
2257
2328
|
const selectAllDisabled = numOptions === selectedValues.length;
|
|
2258
2329
|
const selectAll = {
|
|
2259
2330
|
component: React__namespace.createElement(ActionItem, {
|
|
2260
2331
|
disabled: selectAllDisabled,
|
|
2261
2332
|
label: selectAllLabel(numOptions),
|
|
2262
2333
|
indent: true,
|
|
2263
|
-
onClick:
|
|
2334
|
+
onClick: handleSelectAll
|
|
2264
2335
|
}),
|
|
2265
2336
|
focusable: !selectAllDisabled,
|
|
2266
2337
|
populatedProps: {}
|
|
@@ -2271,7 +2342,7 @@ class MultiSelect extends React__namespace.Component {
|
|
|
2271
2342
|
disabled: selectNoneDisabled,
|
|
2272
2343
|
label: selectNoneLabel,
|
|
2273
2344
|
indent: true,
|
|
2274
|
-
onClick:
|
|
2345
|
+
onClick: handleSelectNone
|
|
2275
2346
|
}),
|
|
2276
2347
|
focusable: !selectNoneDisabled,
|
|
2277
2348
|
populatedProps: {}
|
|
@@ -2287,18 +2358,11 @@ class MultiSelect extends React__namespace.Component {
|
|
|
2287
2358
|
} else {
|
|
2288
2359
|
return [];
|
|
2289
2360
|
}
|
|
2290
|
-
}
|
|
2291
|
-
getMenuItems
|
|
2292
|
-
const {
|
|
2293
|
-
isFilterable
|
|
2294
|
-
} = this.props;
|
|
2361
|
+
};
|
|
2362
|
+
const getMenuItems = children => {
|
|
2295
2363
|
if (!isFilterable) {
|
|
2296
|
-
return children.map(
|
|
2364
|
+
return children.map(mapOptionItemToDropdownItem);
|
|
2297
2365
|
}
|
|
2298
|
-
const {
|
|
2299
|
-
searchText,
|
|
2300
|
-
lastSelectedValues
|
|
2301
|
-
} = this.state;
|
|
2302
2366
|
const lowercasedSearchText = searchText.toLowerCase();
|
|
2303
2367
|
const filteredChildren = children.filter(({
|
|
2304
2368
|
props
|
|
@@ -2312,7 +2376,7 @@ class MultiSelect extends React__namespace.Component {
|
|
|
2312
2376
|
restOfTheChildren.push(child);
|
|
2313
2377
|
}
|
|
2314
2378
|
}
|
|
2315
|
-
const lastSelectedItems = lastSelectedChildren.map(
|
|
2379
|
+
const lastSelectedItems = lastSelectedChildren.map(mapOptionItemToDropdownItem);
|
|
2316
2380
|
if (lastSelectedChildren.length && restOfTheChildren.length) {
|
|
2317
2381
|
lastSelectedItems.push({
|
|
2318
2382
|
component: React__namespace.createElement(SeparatorItem, {
|
|
@@ -2322,116 +2386,109 @@ class MultiSelect extends React__namespace.Component {
|
|
|
2322
2386
|
populatedProps: {}
|
|
2323
2387
|
});
|
|
2324
2388
|
}
|
|
2325
|
-
return [...lastSelectedItems, ...restOfTheChildren.map(
|
|
2326
|
-
}
|
|
2327
|
-
|
|
2328
|
-
const
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2389
|
+
return [...lastSelectedItems, ...restOfTheChildren.map(mapOptionItemToDropdownItem)];
|
|
2390
|
+
};
|
|
2391
|
+
const mapOptionItemToDropdownItem = option => {
|
|
2392
|
+
const {
|
|
2393
|
+
disabled,
|
|
2394
|
+
value
|
|
2395
|
+
} = option.props;
|
|
2396
|
+
return {
|
|
2397
|
+
component: option,
|
|
2398
|
+
focusable: !disabled,
|
|
2399
|
+
populatedProps: {
|
|
2400
|
+
onToggle: handleToggle,
|
|
2401
|
+
selected: selectedValues.includes(value),
|
|
2402
|
+
variant: "checkbox"
|
|
2403
|
+
}
|
|
2404
|
+
};
|
|
2405
|
+
};
|
|
2406
|
+
const handleOpenerRef = node => {
|
|
2407
|
+
const openerElement = ReactDOM__namespace.findDOMNode(node);
|
|
2408
|
+
setOpenerElement(openerElement);
|
|
2409
|
+
};
|
|
2410
|
+
const handleSearchTextChanged = searchText => {
|
|
2411
|
+
setSearchText(searchText);
|
|
2412
|
+
};
|
|
2413
|
+
const handleClick = e => {
|
|
2414
|
+
handleOpenChanged(!open);
|
|
2415
|
+
};
|
|
2416
|
+
const renderOpener = (allChildren, isDisabled, dropdownId) => {
|
|
2336
2417
|
const {
|
|
2337
2418
|
noneSelected
|
|
2338
|
-
} =
|
|
2339
|
-
const menuText =
|
|
2419
|
+
} = labels;
|
|
2420
|
+
const menuText = getMenuText(allChildren);
|
|
2340
2421
|
const dropdownOpener = React__namespace.createElement(wonderBlocksCore.IDProvider, {
|
|
2341
2422
|
id: id,
|
|
2342
2423
|
scope: "multi-select-opener"
|
|
2343
2424
|
}, uniqueOpenerId => {
|
|
2344
2425
|
return opener ? React__namespace.createElement(DropdownOpener, {
|
|
2345
2426
|
id: uniqueOpenerId,
|
|
2427
|
+
error: hasError,
|
|
2346
2428
|
"aria-controls": dropdownId,
|
|
2347
2429
|
"aria-haspopup": "listbox",
|
|
2348
|
-
onClick:
|
|
2430
|
+
onClick: handleClick,
|
|
2431
|
+
onBlur: onOpenerBlurValidation,
|
|
2349
2432
|
disabled: isDisabled,
|
|
2350
|
-
ref:
|
|
2433
|
+
ref: handleOpenerRef,
|
|
2351
2434
|
text: menuText,
|
|
2352
|
-
opened:
|
|
2435
|
+
opened: open
|
|
2353
2436
|
}, opener) : React__namespace.createElement(SelectOpener, _extends__default["default"]({}, sharedProps, {
|
|
2437
|
+
error: hasError,
|
|
2354
2438
|
disabled: isDisabled,
|
|
2355
2439
|
id: uniqueOpenerId,
|
|
2356
2440
|
"aria-controls": dropdownId,
|
|
2357
2441
|
isPlaceholder: menuText === noneSelected,
|
|
2358
2442
|
light: light,
|
|
2359
|
-
onOpenChanged:
|
|
2360
|
-
|
|
2361
|
-
|
|
2443
|
+
onOpenChanged: handleOpenChanged,
|
|
2444
|
+
onBlur: onOpenerBlurValidation,
|
|
2445
|
+
open: open,
|
|
2446
|
+
ref: handleOpenerRef,
|
|
2362
2447
|
testId: testId
|
|
2363
2448
|
}), menuText);
|
|
2364
2449
|
});
|
|
2365
2450
|
return dropdownOpener;
|
|
2366
|
-
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2451
|
+
};
|
|
2452
|
+
const {
|
|
2453
|
+
clearSearch,
|
|
2454
|
+
filter,
|
|
2455
|
+
noResults,
|
|
2456
|
+
someSelected
|
|
2457
|
+
} = labels;
|
|
2458
|
+
const allChildren = React__namespace.Children.toArray(children).filter(Boolean);
|
|
2459
|
+
const numEnabledOptions = allChildren.filter(option => !option.props.disabled).length;
|
|
2460
|
+
const filteredItems = getMenuItems(allChildren);
|
|
2461
|
+
const isDisabled = numEnabledOptions === 0 || disabled;
|
|
2462
|
+
return React__namespace.createElement(wonderBlocksCore.IDProvider, {
|
|
2463
|
+
id: dropdownId,
|
|
2464
|
+
scope: "multi-select-dropdown"
|
|
2465
|
+
}, uniqueDropdownId => React__namespace.createElement(DropdownCore$1, {
|
|
2466
|
+
id: uniqueDropdownId,
|
|
2467
|
+
role: "listbox",
|
|
2468
|
+
alignment: alignment,
|
|
2469
|
+
dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
|
|
2470
|
+
isFilterable: isFilterable,
|
|
2471
|
+
items: [...getShortcuts(numEnabledOptions), ...filteredItems],
|
|
2472
|
+
light: light,
|
|
2473
|
+
onOpenChanged: handleOpenChanged,
|
|
2474
|
+
open: open,
|
|
2475
|
+
opener: renderOpener(allChildren, isDisabled, uniqueDropdownId),
|
|
2476
|
+
openerElement: openerElement,
|
|
2477
|
+
selectionType: "multi",
|
|
2478
|
+
style: style,
|
|
2479
|
+
className: className,
|
|
2480
|
+
onSearchTextChanged: isFilterable ? handleSearchTextChanged : undefined,
|
|
2481
|
+
searchText: isFilterable ? searchText : "",
|
|
2482
|
+
labels: {
|
|
2386
2483
|
clearSearch,
|
|
2387
2484
|
filter,
|
|
2388
2485
|
noResults,
|
|
2389
|
-
someSelected
|
|
2390
|
-
}
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
return React__namespace.createElement(wonderBlocksCore.IDProvider, {
|
|
2396
|
-
id: dropdownId,
|
|
2397
|
-
scope: "multi-select-dropdown"
|
|
2398
|
-
}, uniqueDropdownId => React__namespace.createElement(DropdownCore$1, {
|
|
2399
|
-
id: uniqueDropdownId,
|
|
2400
|
-
role: "listbox",
|
|
2401
|
-
alignment: alignment,
|
|
2402
|
-
dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
|
|
2403
|
-
isFilterable: isFilterable,
|
|
2404
|
-
items: [...this.getShortcuts(numEnabledOptions), ...filteredItems],
|
|
2405
|
-
light: light,
|
|
2406
|
-
onOpenChanged: this.handleOpenChanged,
|
|
2407
|
-
open: open,
|
|
2408
|
-
opener: this.renderOpener(allChildren, isDisabled, uniqueDropdownId),
|
|
2409
|
-
openerElement: this.state.openerElement,
|
|
2410
|
-
selectionType: "multi",
|
|
2411
|
-
style: style,
|
|
2412
|
-
className: className,
|
|
2413
|
-
onSearchTextChanged: isFilterable ? this.handleSearchTextChanged : undefined,
|
|
2414
|
-
searchText: isFilterable ? searchText : "",
|
|
2415
|
-
labels: {
|
|
2416
|
-
clearSearch,
|
|
2417
|
-
filter,
|
|
2418
|
-
noResults,
|
|
2419
|
-
someResults: someSelected
|
|
2420
|
-
},
|
|
2421
|
-
"aria-invalid": ariaInvalid,
|
|
2422
|
-
"aria-required": ariaRequired,
|
|
2423
|
-
disabled: isDisabled
|
|
2424
|
-
}));
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2427
|
-
MultiSelect.defaultProps = {
|
|
2428
|
-
alignment: "left",
|
|
2429
|
-
disabled: false,
|
|
2430
|
-
error: false,
|
|
2431
|
-
light: false,
|
|
2432
|
-
shortcuts: false,
|
|
2433
|
-
selectedValues: [],
|
|
2434
|
-
showOpenerLabelAsText: true
|
|
2486
|
+
someResults: someSelected
|
|
2487
|
+
},
|
|
2488
|
+
"aria-invalid": ariaInvalid,
|
|
2489
|
+
"aria-required": ariaRequired,
|
|
2490
|
+
disabled: isDisabled
|
|
2491
|
+
}));
|
|
2435
2492
|
};
|
|
2436
2493
|
|
|
2437
2494
|
function updateMultipleSelection(previousSelection, value = "") {
|