@khanacademy/wonder-blocks-dropdown 6.0.0 → 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 +25 -0
- package/dist/components/dropdown-opener.d.ts +8 -0
- 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 +445 -407
- package/dist/hooks/use-select-validation.d.ts +39 -0
- package/dist/index.js +444 -406
- package/dist/util/constants.d.ts +10 -7
- package/package.json +2 -2
package/dist/es/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as tokens from '@khanacademy/wonder-blocks-tokens';
|
|
|
6
6
|
import { spacing, color, mix, fade, font, border, semanticColor } from '@khanacademy/wonder-blocks-tokens';
|
|
7
7
|
import { LabelMedium, LabelSmall, LabelLarge } from '@khanacademy/wonder-blocks-typography';
|
|
8
8
|
import _objectWithoutPropertiesLoose from '@babel/runtime/helpers/objectWithoutPropertiesLoose';
|
|
9
|
-
import { View, addStyle, IDProvider, useUniqueIdWithMock } from '@khanacademy/wonder-blocks-core';
|
|
9
|
+
import { View, addStyle, IDProvider, useOnMountEffect, useUniqueIdWithMock } from '@khanacademy/wonder-blocks-core';
|
|
10
10
|
import { Strut } from '@khanacademy/wonder-blocks-layout';
|
|
11
11
|
import { PhosphorIcon } from '@khanacademy/wonder-blocks-icon';
|
|
12
12
|
import checkIcon from '@phosphor-icons/core/bold/check-bold.svg';
|
|
@@ -25,13 +25,12 @@ import { TextField } from '@khanacademy/wonder-blocks-form';
|
|
|
25
25
|
import IconButton from '@khanacademy/wonder-blocks-icon-button';
|
|
26
26
|
import Pill from '@khanacademy/wonder-blocks-pill';
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
down: 40
|
|
28
|
+
const keys = {
|
|
29
|
+
escape: "Escape",
|
|
30
|
+
tab: "Tab",
|
|
31
|
+
space: " ",
|
|
32
|
+
up: "ArrowUp",
|
|
33
|
+
down: "ArrowDown"
|
|
35
34
|
};
|
|
36
35
|
const selectDropdownStyle = {
|
|
37
36
|
marginTop: spacing.xSmall_8,
|
|
@@ -495,7 +494,9 @@ class DropdownOpener extends React.Component {
|
|
|
495
494
|
opened,
|
|
496
495
|
"aria-controls": ariaControls,
|
|
497
496
|
"aria-haspopup": ariaHasPopUp,
|
|
498
|
-
|
|
497
|
+
"aria-required": ariaRequired,
|
|
498
|
+
id,
|
|
499
|
+
onBlur
|
|
499
500
|
} = this.props;
|
|
500
501
|
const renderedChildren = this.props.children(_extends({}, eventState, {
|
|
501
502
|
text,
|
|
@@ -504,16 +505,19 @@ class DropdownOpener extends React.Component {
|
|
|
504
505
|
const childrenProps = renderedChildren.props;
|
|
505
506
|
const childrenTestId = this.getTestIdFromProps(childrenProps);
|
|
506
507
|
return React.cloneElement(renderedChildren, _extends({}, clickableChildrenProps, {
|
|
508
|
+
"aria-invalid": this.props.error,
|
|
507
509
|
disabled,
|
|
508
510
|
"aria-controls": ariaControls,
|
|
509
511
|
id,
|
|
510
512
|
"aria-expanded": opened ? "true" : "false",
|
|
511
513
|
"aria-haspopup": ariaHasPopUp,
|
|
514
|
+
"aria-required": ariaRequired,
|
|
512
515
|
onClick: childrenProps.onClick ? e => {
|
|
513
516
|
childrenProps.onClick(e);
|
|
514
517
|
clickableChildrenProps.onClick(e);
|
|
515
518
|
} : clickableChildrenProps.onClick,
|
|
516
|
-
"data-testid": childrenTestId || testId
|
|
519
|
+
"data-testid": childrenTestId || testId,
|
|
520
|
+
onBlur
|
|
517
521
|
}));
|
|
518
522
|
}
|
|
519
523
|
render() {
|
|
@@ -851,39 +855,39 @@ class DropdownCore extends React.Component {
|
|
|
851
855
|
open,
|
|
852
856
|
searchText
|
|
853
857
|
} = this.props;
|
|
854
|
-
const
|
|
855
|
-
if (enableTypeAhead && getStringForKey(
|
|
858
|
+
const key = event.key;
|
|
859
|
+
if (enableTypeAhead && getStringForKey(key)) {
|
|
856
860
|
event.stopPropagation();
|
|
857
|
-
this.textSuggestion +=
|
|
861
|
+
this.textSuggestion += key;
|
|
858
862
|
this.handleKeyDownDebounced(this.textSuggestion);
|
|
859
863
|
}
|
|
860
864
|
if (!open) {
|
|
861
|
-
if (
|
|
865
|
+
if (key === keys.down) {
|
|
862
866
|
event.preventDefault();
|
|
863
867
|
onOpenChanged(true);
|
|
864
868
|
return;
|
|
865
869
|
}
|
|
866
870
|
return;
|
|
867
871
|
}
|
|
868
|
-
switch (
|
|
869
|
-
case
|
|
872
|
+
switch (key) {
|
|
873
|
+
case keys.tab:
|
|
870
874
|
if (this.isSearchFieldFocused() && searchText) {
|
|
871
875
|
return;
|
|
872
876
|
}
|
|
873
877
|
this.restoreTabOrder();
|
|
874
878
|
onOpenChanged(false);
|
|
875
879
|
return;
|
|
876
|
-
case
|
|
880
|
+
case keys.space:
|
|
877
881
|
if (this.isSearchFieldFocused()) {
|
|
878
882
|
return;
|
|
879
883
|
}
|
|
880
884
|
event.preventDefault();
|
|
881
885
|
return;
|
|
882
|
-
case
|
|
886
|
+
case keys.up:
|
|
883
887
|
event.preventDefault();
|
|
884
888
|
this.focusPreviousItem();
|
|
885
889
|
return;
|
|
886
|
-
case
|
|
890
|
+
case keys.down:
|
|
887
891
|
event.preventDefault();
|
|
888
892
|
this.focusNextItem();
|
|
889
893
|
return;
|
|
@@ -894,15 +898,15 @@ class DropdownCore extends React.Component {
|
|
|
894
898
|
onOpenChanged,
|
|
895
899
|
open
|
|
896
900
|
} = this.props;
|
|
897
|
-
const
|
|
898
|
-
switch (
|
|
899
|
-
case
|
|
901
|
+
const key = event.key;
|
|
902
|
+
switch (key) {
|
|
903
|
+
case keys.space:
|
|
900
904
|
if (this.isSearchFieldFocused()) {
|
|
901
905
|
return;
|
|
902
906
|
}
|
|
903
907
|
event.preventDefault();
|
|
904
908
|
return;
|
|
905
|
-
case
|
|
909
|
+
case keys.escape:
|
|
906
910
|
if (open) {
|
|
907
911
|
event.stopPropagation();
|
|
908
912
|
this.restoreTabOrder();
|
|
@@ -1679,7 +1683,7 @@ const styles$5 = StyleSheet.create({
|
|
|
1679
1683
|
}
|
|
1680
1684
|
});
|
|
1681
1685
|
|
|
1682
|
-
const _excluded$2 = ["children", "disabled", "error", "id", "isPlaceholder", "light", "open", "testId", "onOpenChanged"];
|
|
1686
|
+
const _excluded$2 = ["children", "disabled", "error", "id", "isPlaceholder", "light", "open", "testId", "aria-required", "onBlur", "onOpenChanged"];
|
|
1683
1687
|
const StyledButton = addStyle("button");
|
|
1684
1688
|
class SelectOpener extends React.Component {
|
|
1685
1689
|
constructor(props) {
|
|
@@ -1722,7 +1726,9 @@ class SelectOpener extends React.Component {
|
|
|
1722
1726
|
isPlaceholder,
|
|
1723
1727
|
light,
|
|
1724
1728
|
open,
|
|
1725
|
-
testId
|
|
1729
|
+
testId,
|
|
1730
|
+
"aria-required": ariaRequired,
|
|
1731
|
+
onBlur
|
|
1726
1732
|
} = _this$props,
|
|
1727
1733
|
sharedProps = _objectWithoutPropertiesLoose(_this$props, _excluded$2);
|
|
1728
1734
|
const stateStyles = _generateStyles(light, isPlaceholder, error);
|
|
@@ -1731,6 +1737,8 @@ class SelectOpener extends React.Component {
|
|
|
1731
1737
|
return React.createElement(StyledButton, _extends({}, sharedProps, {
|
|
1732
1738
|
"aria-disabled": disabled,
|
|
1733
1739
|
"aria-expanded": open ? "true" : "false",
|
|
1740
|
+
"aria-invalid": error,
|
|
1741
|
+
"aria-required": ariaRequired,
|
|
1734
1742
|
"aria-haspopup": "listbox",
|
|
1735
1743
|
"data-testid": testId,
|
|
1736
1744
|
id: id,
|
|
@@ -1738,7 +1746,8 @@ class SelectOpener extends React.Component {
|
|
|
1738
1746
|
type: "button",
|
|
1739
1747
|
onClick: !disabled ? this.handleClick : undefined,
|
|
1740
1748
|
onKeyDown: !disabled ? this.handleKeyDown : undefined,
|
|
1741
|
-
onKeyUp: !disabled ? this.handleKeyUp : undefined
|
|
1749
|
+
onKeyUp: !disabled ? this.handleKeyUp : undefined,
|
|
1750
|
+
onBlur: onBlur
|
|
1742
1751
|
}), React.createElement(LabelMedium, {
|
|
1743
1752
|
style: styles$4.text
|
|
1744
1753
|
}, children || "\u00A0"), React.createElement(PhosphorIcon, {
|
|
@@ -1887,117 +1896,206 @@ const _generateStyles = (light, placeholder, error) => {
|
|
|
1887
1896
|
return stateStyles[styleKey];
|
|
1888
1897
|
};
|
|
1889
1898
|
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1899
|
+
const defaultErrorMessage = "This field is required.";
|
|
1900
|
+
function hasValue(value) {
|
|
1901
|
+
return value ? value.length > 0 : false;
|
|
1902
|
+
}
|
|
1903
|
+
function useSelectValidation({
|
|
1904
|
+
value,
|
|
1905
|
+
disabled = false,
|
|
1906
|
+
validate,
|
|
1907
|
+
onValidate,
|
|
1908
|
+
required,
|
|
1909
|
+
open
|
|
1910
|
+
}) {
|
|
1911
|
+
const [errorMessage, setErrorMessage] = React.useState(() => validate && hasValue(value) && !disabled && validate(value) || null);
|
|
1912
|
+
const handleValidation = React.useCallback(newValue => {
|
|
1913
|
+
if (disabled) {
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
if (validate) {
|
|
1917
|
+
const error = newValue !== undefined && validate(newValue) || null;
|
|
1918
|
+
setErrorMessage(error);
|
|
1919
|
+
if (onValidate) {
|
|
1920
|
+
onValidate(error);
|
|
1902
1921
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
if (selectedValue !== this.props.selectedValue) {
|
|
1906
|
-
this.props.onChange(selectedValue);
|
|
1922
|
+
if (error) {
|
|
1923
|
+
return;
|
|
1907
1924
|
}
|
|
1908
|
-
|
|
1909
|
-
|
|
1925
|
+
}
|
|
1926
|
+
if (required) {
|
|
1927
|
+
const requiredString = typeof required === "string" ? required : defaultErrorMessage;
|
|
1928
|
+
const error = hasValue(newValue) ? null : requiredString;
|
|
1929
|
+
setErrorMessage(error);
|
|
1930
|
+
if (onValidate) {
|
|
1931
|
+
onValidate(error);
|
|
1910
1932
|
}
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1933
|
+
}
|
|
1934
|
+
}, [disabled, validate, setErrorMessage, onValidate, required]);
|
|
1935
|
+
useOnMountEffect(() => {
|
|
1936
|
+
if (hasValue(value)) {
|
|
1937
|
+
handleValidation(value);
|
|
1938
|
+
}
|
|
1939
|
+
});
|
|
1940
|
+
function onOpenerBlurValidation() {
|
|
1941
|
+
if (!open && required && !hasValue(value)) {
|
|
1942
|
+
handleValidation(value);
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
const onDropdownClosedValidation = () => {
|
|
1946
|
+
if (required && !hasValue(value)) {
|
|
1947
|
+
handleValidation(value);
|
|
1948
|
+
}
|
|
1949
|
+
};
|
|
1950
|
+
const onSelectionValidation = newValue => {
|
|
1951
|
+
handleValidation(newValue);
|
|
1952
|
+
};
|
|
1953
|
+
const onSelectedValuesChangeValidation = () => {
|
|
1954
|
+
setErrorMessage(null);
|
|
1955
|
+
if (onValidate) {
|
|
1956
|
+
onValidate(null);
|
|
1957
|
+
}
|
|
1958
|
+
};
|
|
1959
|
+
return {
|
|
1960
|
+
errorMessage,
|
|
1961
|
+
onOpenerBlurValidation,
|
|
1962
|
+
onDropdownClosedValidation,
|
|
1963
|
+
onSelectionValidation,
|
|
1964
|
+
onSelectedValuesChangeValidation
|
|
1965
|
+
};
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
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"];
|
|
1969
|
+
const SingleSelect = props => {
|
|
1970
|
+
const selectedIndex = React.useRef(0);
|
|
1971
|
+
const {
|
|
1972
|
+
children,
|
|
1973
|
+
error = false,
|
|
1974
|
+
id,
|
|
1975
|
+
opener,
|
|
1976
|
+
light = false,
|
|
1977
|
+
placeholder,
|
|
1978
|
+
selectedValue,
|
|
1979
|
+
testId,
|
|
1980
|
+
alignment = "left",
|
|
1981
|
+
autoFocus = true,
|
|
1982
|
+
dropdownStyle,
|
|
1983
|
+
enableTypeAhead = true,
|
|
1984
|
+
isFilterable,
|
|
1985
|
+
labels = {
|
|
1986
|
+
clearSearch: defaultLabels.clearSearch,
|
|
1987
|
+
filter: defaultLabels.filter,
|
|
1988
|
+
noResults: defaultLabels.noResults,
|
|
1989
|
+
someResults: defaultLabels.someSelected
|
|
1990
|
+
},
|
|
1991
|
+
onChange,
|
|
1992
|
+
onToggle,
|
|
1993
|
+
opened,
|
|
1994
|
+
style,
|
|
1995
|
+
className,
|
|
1996
|
+
"aria-invalid": ariaInvalid,
|
|
1997
|
+
"aria-required": ariaRequired,
|
|
1998
|
+
disabled = false,
|
|
1999
|
+
dropdownId,
|
|
2000
|
+
validate,
|
|
2001
|
+
onValidate,
|
|
2002
|
+
required,
|
|
2003
|
+
showOpenerLabelAsText = true
|
|
2004
|
+
} = props,
|
|
2005
|
+
sharedProps = _objectWithoutPropertiesLoose(props, _excluded$1);
|
|
2006
|
+
const [open, setOpen] = React.useState(false);
|
|
2007
|
+
const [searchText, setSearchText] = React.useState("");
|
|
2008
|
+
const [openerElement, setOpenerElement] = React.useState();
|
|
2009
|
+
const {
|
|
2010
|
+
errorMessage,
|
|
2011
|
+
onOpenerBlurValidation,
|
|
2012
|
+
onDropdownClosedValidation,
|
|
2013
|
+
onSelectionValidation
|
|
2014
|
+
} = useSelectValidation({
|
|
2015
|
+
value: selectedValue,
|
|
2016
|
+
disabled,
|
|
2017
|
+
validate,
|
|
2018
|
+
onValidate,
|
|
2019
|
+
required,
|
|
2020
|
+
open
|
|
2021
|
+
});
|
|
2022
|
+
const hasError = error || !!errorMessage;
|
|
2023
|
+
React.useEffect(() => {
|
|
2024
|
+
if (disabled) {
|
|
2025
|
+
setOpen(false);
|
|
2026
|
+
} else if (typeof opened === "boolean") {
|
|
2027
|
+
setOpen(opened);
|
|
2028
|
+
}
|
|
2029
|
+
}, [disabled, opened]);
|
|
2030
|
+
const handleOpenChanged = opened => {
|
|
2031
|
+
setOpen(opened);
|
|
2032
|
+
setSearchText("");
|
|
2033
|
+
if (onToggle) {
|
|
2034
|
+
onToggle(opened);
|
|
2035
|
+
}
|
|
2036
|
+
if (!opened) {
|
|
2037
|
+
onDropdownClosedValidation();
|
|
2038
|
+
}
|
|
2039
|
+
};
|
|
2040
|
+
const handleToggle = newSelectedValue => {
|
|
2041
|
+
if (newSelectedValue !== selectedValue) {
|
|
2042
|
+
onChange(newSelectedValue);
|
|
2043
|
+
}
|
|
2044
|
+
if (open && openerElement) {
|
|
2045
|
+
openerElement.focus();
|
|
2046
|
+
}
|
|
2047
|
+
setOpen(false);
|
|
2048
|
+
if (onToggle) {
|
|
2049
|
+
onToggle(false);
|
|
2050
|
+
}
|
|
2051
|
+
onSelectionValidation(newSelectedValue);
|
|
2052
|
+
};
|
|
2053
|
+
const mapOptionItemsToDropdownItems = children => {
|
|
2054
|
+
let indexCounter = 0;
|
|
2055
|
+
selectedIndex.current = 0;
|
|
2056
|
+
return children.map(option => {
|
|
2057
|
+
const {
|
|
2058
|
+
disabled,
|
|
2059
|
+
value
|
|
2060
|
+
} = option.props;
|
|
2061
|
+
const selected = selectedValue === value;
|
|
2062
|
+
if (selected) {
|
|
2063
|
+
selectedIndex.current = indexCounter;
|
|
1916
2064
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
value
|
|
1928
|
-
} = option.props;
|
|
1929
|
-
const selected = selectedValue === value;
|
|
1930
|
-
if (selected) {
|
|
1931
|
-
this.selectedIndex = indexCounter;
|
|
1932
|
-
}
|
|
1933
|
-
if (!disabled) {
|
|
1934
|
-
indexCounter += 1;
|
|
2065
|
+
if (!disabled) {
|
|
2066
|
+
indexCounter += 1;
|
|
2067
|
+
}
|
|
2068
|
+
return {
|
|
2069
|
+
component: option,
|
|
2070
|
+
focusable: !disabled,
|
|
2071
|
+
populatedProps: {
|
|
2072
|
+
onToggle: handleToggle,
|
|
2073
|
+
selected: selected,
|
|
2074
|
+
variant: "check"
|
|
1935
2075
|
}
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
onToggle: this.handleToggle,
|
|
1941
|
-
selected: selected,
|
|
1942
|
-
variant: "check"
|
|
1943
|
-
}
|
|
1944
|
-
};
|
|
1945
|
-
});
|
|
1946
|
-
};
|
|
1947
|
-
this.handleSearchTextChanged = searchText => {
|
|
1948
|
-
this.setState({
|
|
1949
|
-
searchText
|
|
1950
|
-
});
|
|
1951
|
-
};
|
|
1952
|
-
this.handleOpenerRef = node => {
|
|
1953
|
-
const openerElement = ReactDOM.findDOMNode(node);
|
|
1954
|
-
this.setState({
|
|
1955
|
-
openerElement
|
|
1956
|
-
});
|
|
1957
|
-
};
|
|
1958
|
-
this.handleClick = e => {
|
|
1959
|
-
this.handleOpenChanged(!this.state.open);
|
|
1960
|
-
};
|
|
1961
|
-
this.selectedIndex = 0;
|
|
1962
|
-
this.state = {
|
|
1963
|
-
open: false,
|
|
1964
|
-
searchText: ""
|
|
1965
|
-
};
|
|
1966
|
-
}
|
|
1967
|
-
static getDerivedStateFromProps(props, state) {
|
|
1968
|
-
return {
|
|
1969
|
-
open: props.disabled ? false : typeof props.opened === "boolean" ? props.opened : state.open
|
|
1970
|
-
};
|
|
1971
|
-
}
|
|
1972
|
-
filterChildren(children) {
|
|
1973
|
-
const {
|
|
1974
|
-
searchText
|
|
1975
|
-
} = this.state;
|
|
2076
|
+
};
|
|
2077
|
+
});
|
|
2078
|
+
};
|
|
2079
|
+
const filterChildren = children => {
|
|
1976
2080
|
const lowercasedSearchText = searchText.toLowerCase();
|
|
1977
2081
|
return children.filter(({
|
|
1978
2082
|
props
|
|
1979
2083
|
}) => !searchText || getLabel(props).toLowerCase().indexOf(lowercasedSearchText) > -1);
|
|
1980
|
-
}
|
|
1981
|
-
getMenuItems
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
}
|
|
1987
|
-
|
|
1988
|
-
const
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
placeholder,
|
|
1996
|
-
selectedValue,
|
|
1997
|
-
testId,
|
|
1998
|
-
showOpenerLabelAsText
|
|
1999
|
-
} = _this$props,
|
|
2000
|
-
sharedProps = _objectWithoutPropertiesLoose(_this$props, _excluded$1);
|
|
2084
|
+
};
|
|
2085
|
+
const getMenuItems = children => {
|
|
2086
|
+
return mapOptionItemsToDropdownItems(isFilterable ? filterChildren(children) : children);
|
|
2087
|
+
};
|
|
2088
|
+
const handleSearchTextChanged = searchText => {
|
|
2089
|
+
setSearchText(searchText);
|
|
2090
|
+
};
|
|
2091
|
+
const handleOpenerRef = node => {
|
|
2092
|
+
const openerElement = ReactDOM.findDOMNode(node);
|
|
2093
|
+
setOpenerElement(openerElement);
|
|
2094
|
+
};
|
|
2095
|
+
const handleClick = e => {
|
|
2096
|
+
handleOpenChanged(!open);
|
|
2097
|
+
};
|
|
2098
|
+
const renderOpener = (isDisabled, dropdownId) => {
|
|
2001
2099
|
const items = React.Children.toArray(children);
|
|
2002
2100
|
const selectedItem = items.find(option => option.props.value === selectedValue);
|
|
2003
2101
|
const menuText = selectedItem ? getSelectOpenerLabel(showOpenerLabelAsText, selectedItem.props) : placeholder;
|
|
@@ -2009,202 +2107,160 @@ class SingleSelect extends React.Component {
|
|
|
2009
2107
|
id: uniqueOpenerId,
|
|
2010
2108
|
"aria-controls": dropdownId,
|
|
2011
2109
|
"aria-haspopup": "listbox",
|
|
2012
|
-
onClick:
|
|
2110
|
+
onClick: handleClick,
|
|
2013
2111
|
disabled: isDisabled,
|
|
2014
|
-
ref:
|
|
2112
|
+
ref: handleOpenerRef,
|
|
2015
2113
|
text: menuText,
|
|
2016
|
-
opened:
|
|
2114
|
+
opened: open,
|
|
2115
|
+
error: hasError,
|
|
2116
|
+
onBlur: onOpenerBlurValidation
|
|
2017
2117
|
}, opener) : React.createElement(SelectOpener, _extends({}, sharedProps, {
|
|
2018
2118
|
"aria-controls": dropdownId,
|
|
2019
2119
|
disabled: isDisabled,
|
|
2020
2120
|
id: uniqueOpenerId,
|
|
2021
|
-
error:
|
|
2121
|
+
error: hasError,
|
|
2022
2122
|
isPlaceholder: !selectedItem,
|
|
2023
2123
|
light: light,
|
|
2024
|
-
onOpenChanged:
|
|
2025
|
-
open:
|
|
2026
|
-
ref:
|
|
2027
|
-
testId: testId
|
|
2124
|
+
onOpenChanged: handleOpenChanged,
|
|
2125
|
+
open: open,
|
|
2126
|
+
ref: handleOpenerRef,
|
|
2127
|
+
testId: testId,
|
|
2128
|
+
onBlur: onOpenerBlurValidation
|
|
2028
2129
|
}), menuText);
|
|
2029
2130
|
});
|
|
2030
2131
|
return dropdownOpener;
|
|
2031
|
-
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2132
|
+
};
|
|
2133
|
+
const allChildren = React.Children.toArray(children).filter(Boolean);
|
|
2134
|
+
const numEnabledOptions = allChildren.filter(option => !option.props.disabled).length;
|
|
2135
|
+
const items = getMenuItems(allChildren);
|
|
2136
|
+
const isDisabled = numEnabledOptions === 0 || disabled;
|
|
2137
|
+
return React.createElement(IDProvider, {
|
|
2138
|
+
id: dropdownId,
|
|
2139
|
+
scope: "single-select-dropdown"
|
|
2140
|
+
}, uniqueDropdownId => React.createElement(DropdownCore$1, {
|
|
2141
|
+
id: uniqueDropdownId,
|
|
2142
|
+
role: "listbox",
|
|
2143
|
+
selectionType: "single",
|
|
2144
|
+
alignment: alignment,
|
|
2145
|
+
autoFocus: autoFocus,
|
|
2146
|
+
enableTypeAhead: enableTypeAhead,
|
|
2147
|
+
dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
|
|
2148
|
+
initialFocusedIndex: selectedIndex.current,
|
|
2149
|
+
items: items,
|
|
2150
|
+
light: light,
|
|
2151
|
+
onOpenChanged: handleOpenChanged,
|
|
2152
|
+
open: open,
|
|
2153
|
+
opener: renderOpener(isDisabled, uniqueDropdownId),
|
|
2154
|
+
openerElement: openerElement,
|
|
2155
|
+
style: style,
|
|
2156
|
+
className: className,
|
|
2157
|
+
isFilterable: isFilterable,
|
|
2158
|
+
onSearchTextChanged: isFilterable ? handleSearchTextChanged : undefined,
|
|
2159
|
+
searchText: isFilterable ? searchText : "",
|
|
2160
|
+
labels: labels,
|
|
2161
|
+
"aria-invalid": ariaInvalid,
|
|
2162
|
+
"aria-required": ariaRequired,
|
|
2163
|
+
disabled: isDisabled
|
|
2164
|
+
}));
|
|
2165
|
+
};
|
|
2166
|
+
|
|
2167
|
+
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"];
|
|
2168
|
+
const MultiSelect = props => {
|
|
2169
|
+
const {
|
|
2170
|
+
id,
|
|
2171
|
+
light = false,
|
|
2172
|
+
opener,
|
|
2173
|
+
testId,
|
|
2174
|
+
alignment = "left",
|
|
2038
2175
|
dropdownStyle,
|
|
2039
|
-
|
|
2176
|
+
implicitAllEnabled,
|
|
2040
2177
|
isFilterable,
|
|
2041
|
-
labels,
|
|
2042
|
-
|
|
2178
|
+
labels: propLabels,
|
|
2179
|
+
onChange,
|
|
2180
|
+
onToggle,
|
|
2181
|
+
opened,
|
|
2182
|
+
selectedValues = [],
|
|
2183
|
+
shortcuts = false,
|
|
2043
2184
|
style,
|
|
2185
|
+
className,
|
|
2044
2186
|
"aria-invalid": ariaInvalid,
|
|
2045
2187
|
"aria-required": ariaRequired,
|
|
2046
|
-
disabled,
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
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
|
-
labels: {
|
|
2094
|
-
clearSearch: defaultLabels.clearSearch,
|
|
2095
|
-
filter: defaultLabels.filter,
|
|
2096
|
-
noResults: defaultLabels.noResults,
|
|
2097
|
-
someResults: defaultLabels.someSelected
|
|
2098
|
-
},
|
|
2099
|
-
showOpenerLabelAsText: true
|
|
2100
|
-
};
|
|
2101
|
-
|
|
2102
|
-
const _excluded = ["id", "light", "opener", "testId", "alignment", "dropdownStyle", "implicitAllEnabled", "isFilterable", "labels", "onChange", "onToggle", "opened", "selectedValues", "shortcuts", "style", "className", "aria-invalid", "aria-required", "showOpenerLabelAsText"];
|
|
2103
|
-
class MultiSelect extends React.Component {
|
|
2104
|
-
constructor(props) {
|
|
2105
|
-
super(props);
|
|
2106
|
-
this.labels = void 0;
|
|
2107
|
-
this.handleOpenChanged = opened => {
|
|
2108
|
-
this.setState({
|
|
2109
|
-
open: opened,
|
|
2110
|
-
searchText: "",
|
|
2111
|
-
lastSelectedValues: this.props.selectedValues
|
|
2112
|
-
});
|
|
2113
|
-
if (this.props.onToggle) {
|
|
2114
|
-
this.props.onToggle(opened);
|
|
2115
|
-
}
|
|
2116
|
-
};
|
|
2117
|
-
this.handleToggle = selectedValue => {
|
|
2118
|
-
const {
|
|
2119
|
-
onChange,
|
|
2120
|
-
selectedValues
|
|
2121
|
-
} = this.props;
|
|
2122
|
-
if (selectedValues.includes(selectedValue)) {
|
|
2123
|
-
const index = selectedValues.indexOf(selectedValue);
|
|
2124
|
-
const updatedSelection = [...selectedValues.slice(0, index), ...selectedValues.slice(index + 1)];
|
|
2125
|
-
onChange(updatedSelection);
|
|
2188
|
+
disabled = false,
|
|
2189
|
+
error = false,
|
|
2190
|
+
children,
|
|
2191
|
+
dropdownId,
|
|
2192
|
+
showOpenerLabelAsText = true,
|
|
2193
|
+
validate,
|
|
2194
|
+
onValidate,
|
|
2195
|
+
required
|
|
2196
|
+
} = props,
|
|
2197
|
+
sharedProps = _objectWithoutPropertiesLoose(props, _excluded);
|
|
2198
|
+
const labels = _extends({}, defaultLabels, propLabels);
|
|
2199
|
+
const [open, setOpen] = React.useState(false);
|
|
2200
|
+
const [searchText, setSearchText] = React.useState("");
|
|
2201
|
+
const [lastSelectedValues, setLastSelectedValues] = React.useState([]);
|
|
2202
|
+
const [openerElement, setOpenerElement] = React.useState();
|
|
2203
|
+
const {
|
|
2204
|
+
errorMessage,
|
|
2205
|
+
onOpenerBlurValidation,
|
|
2206
|
+
onDropdownClosedValidation,
|
|
2207
|
+
onSelectionValidation,
|
|
2208
|
+
onSelectedValuesChangeValidation
|
|
2209
|
+
} = useSelectValidation({
|
|
2210
|
+
value: selectedValues,
|
|
2211
|
+
disabled,
|
|
2212
|
+
validate,
|
|
2213
|
+
onValidate,
|
|
2214
|
+
required,
|
|
2215
|
+
open
|
|
2216
|
+
});
|
|
2217
|
+
const hasError = error || !!errorMessage;
|
|
2218
|
+
React.useEffect(() => {
|
|
2219
|
+
if (disabled) {
|
|
2220
|
+
setOpen(false);
|
|
2221
|
+
} else if (typeof opened === "boolean") {
|
|
2222
|
+
setOpen(opened);
|
|
2223
|
+
}
|
|
2224
|
+
}, [disabled, opened]);
|
|
2225
|
+
const handleOpenChanged = opened => {
|
|
2226
|
+
setOpen(opened);
|
|
2227
|
+
setSearchText("");
|
|
2228
|
+
setLastSelectedValues(selectedValues);
|
|
2229
|
+
if (onToggle) {
|
|
2230
|
+
onToggle(opened);
|
|
2231
|
+
}
|
|
2232
|
+
if (!opened) {
|
|
2233
|
+
if (lastSelectedValues !== selectedValues) {
|
|
2234
|
+
onSelectionValidation(selectedValues);
|
|
2126
2235
|
} else {
|
|
2127
|
-
|
|
2236
|
+
onDropdownClosedValidation();
|
|
2128
2237
|
}
|
|
2129
|
-
};
|
|
2130
|
-
this.handleSelectAll = () => {
|
|
2131
|
-
const {
|
|
2132
|
-
children,
|
|
2133
|
-
onChange
|
|
2134
|
-
} = this.props;
|
|
2135
|
-
const allChildren = React.Children.toArray(children);
|
|
2136
|
-
const selected = allChildren.filter(option => !!option && !option.props.disabled).map(option => option.props.value);
|
|
2137
|
-
onChange(selected);
|
|
2138
|
-
};
|
|
2139
|
-
this.handleSelectNone = () => {
|
|
2140
|
-
const {
|
|
2141
|
-
onChange
|
|
2142
|
-
} = this.props;
|
|
2143
|
-
onChange([]);
|
|
2144
|
-
};
|
|
2145
|
-
this.mapOptionItemToDropdownItem = option => {
|
|
2146
|
-
const {
|
|
2147
|
-
selectedValues
|
|
2148
|
-
} = this.props;
|
|
2149
|
-
const {
|
|
2150
|
-
disabled,
|
|
2151
|
-
value
|
|
2152
|
-
} = option.props;
|
|
2153
|
-
return {
|
|
2154
|
-
component: option,
|
|
2155
|
-
focusable: !disabled,
|
|
2156
|
-
populatedProps: {
|
|
2157
|
-
onToggle: this.handleToggle,
|
|
2158
|
-
selected: selectedValues.includes(value),
|
|
2159
|
-
variant: "checkbox"
|
|
2160
|
-
}
|
|
2161
|
-
};
|
|
2162
|
-
};
|
|
2163
|
-
this.handleOpenerRef = node => {
|
|
2164
|
-
const openerElement = ReactDOM.findDOMNode(node);
|
|
2165
|
-
this.setState({
|
|
2166
|
-
openerElement
|
|
2167
|
-
});
|
|
2168
|
-
};
|
|
2169
|
-
this.handleSearchTextChanged = searchText => {
|
|
2170
|
-
this.setState({
|
|
2171
|
-
searchText
|
|
2172
|
-
});
|
|
2173
|
-
};
|
|
2174
|
-
this.handleClick = e => {
|
|
2175
|
-
this.handleOpenChanged(!this.state.open);
|
|
2176
|
-
};
|
|
2177
|
-
this.state = {
|
|
2178
|
-
open: false,
|
|
2179
|
-
searchText: "",
|
|
2180
|
-
lastSelectedValues: [],
|
|
2181
|
-
labels: _extends({}, defaultLabels, props.labels)
|
|
2182
|
-
};
|
|
2183
|
-
this.labels = _extends({}, defaultLabels, props.labels);
|
|
2184
|
-
}
|
|
2185
|
-
static getDerivedStateFromProps(props, state) {
|
|
2186
|
-
return {
|
|
2187
|
-
open: props.disabled ? false : typeof props.opened === "boolean" ? props.opened : state.open
|
|
2188
|
-
};
|
|
2189
|
-
}
|
|
2190
|
-
componentDidUpdate(prevProps) {
|
|
2191
|
-
if (this.props.labels !== prevProps.labels) {
|
|
2192
|
-
this.setState({
|
|
2193
|
-
labels: _extends({}, this.state.labels, this.props.labels)
|
|
2194
|
-
});
|
|
2195
2238
|
}
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
selectedValues,
|
|
2201
|
-
|
|
2202
|
-
}
|
|
2239
|
+
};
|
|
2240
|
+
const handleToggle = selectedValue => {
|
|
2241
|
+
if (selectedValues.includes(selectedValue)) {
|
|
2242
|
+
const index = selectedValues.indexOf(selectedValue);
|
|
2243
|
+
const updatedSelection = [...selectedValues.slice(0, index), ...selectedValues.slice(index + 1)];
|
|
2244
|
+
onChange(updatedSelection);
|
|
2245
|
+
} else {
|
|
2246
|
+
onChange([...selectedValues, selectedValue]);
|
|
2247
|
+
}
|
|
2248
|
+
onSelectedValuesChangeValidation();
|
|
2249
|
+
};
|
|
2250
|
+
const handleSelectAll = () => {
|
|
2251
|
+
const allChildren = React.Children.toArray(children);
|
|
2252
|
+
const selected = allChildren.filter(option => !!option && !option.props.disabled).map(option => option.props.value);
|
|
2253
|
+
onChange(selected);
|
|
2254
|
+
};
|
|
2255
|
+
const handleSelectNone = () => {
|
|
2256
|
+
onChange([]);
|
|
2257
|
+
};
|
|
2258
|
+
const getMenuText = children => {
|
|
2203
2259
|
const {
|
|
2204
2260
|
noneSelected,
|
|
2205
2261
|
someSelected,
|
|
2206
2262
|
allSelected
|
|
2207
|
-
} =
|
|
2263
|
+
} = labels;
|
|
2208
2264
|
const numSelectedAll = children.filter(option => !option.props.disabled).length;
|
|
2209
2265
|
const noSelectionText = implicitAllEnabled ? allSelected : noneSelected;
|
|
2210
2266
|
switch (selectedValues.length) {
|
|
@@ -2226,24 +2282,20 @@ class MultiSelect extends React.Component {
|
|
|
2226
2282
|
default:
|
|
2227
2283
|
return someSelected(selectedValues.length);
|
|
2228
2284
|
}
|
|
2229
|
-
}
|
|
2230
|
-
getShortcuts
|
|
2231
|
-
const {
|
|
2232
|
-
selectedValues,
|
|
2233
|
-
shortcuts
|
|
2234
|
-
} = this.props;
|
|
2285
|
+
};
|
|
2286
|
+
const getShortcuts = numOptions => {
|
|
2235
2287
|
const {
|
|
2236
2288
|
selectAllLabel,
|
|
2237
2289
|
selectNoneLabel
|
|
2238
|
-
} =
|
|
2239
|
-
if (shortcuts && !
|
|
2290
|
+
} = labels;
|
|
2291
|
+
if (shortcuts && !searchText) {
|
|
2240
2292
|
const selectAllDisabled = numOptions === selectedValues.length;
|
|
2241
2293
|
const selectAll = {
|
|
2242
2294
|
component: React.createElement(ActionItem, {
|
|
2243
2295
|
disabled: selectAllDisabled,
|
|
2244
2296
|
label: selectAllLabel(numOptions),
|
|
2245
2297
|
indent: true,
|
|
2246
|
-
onClick:
|
|
2298
|
+
onClick: handleSelectAll
|
|
2247
2299
|
}),
|
|
2248
2300
|
focusable: !selectAllDisabled,
|
|
2249
2301
|
populatedProps: {}
|
|
@@ -2254,7 +2306,7 @@ class MultiSelect extends React.Component {
|
|
|
2254
2306
|
disabled: selectNoneDisabled,
|
|
2255
2307
|
label: selectNoneLabel,
|
|
2256
2308
|
indent: true,
|
|
2257
|
-
onClick:
|
|
2309
|
+
onClick: handleSelectNone
|
|
2258
2310
|
}),
|
|
2259
2311
|
focusable: !selectNoneDisabled,
|
|
2260
2312
|
populatedProps: {}
|
|
@@ -2270,18 +2322,11 @@ class MultiSelect extends React.Component {
|
|
|
2270
2322
|
} else {
|
|
2271
2323
|
return [];
|
|
2272
2324
|
}
|
|
2273
|
-
}
|
|
2274
|
-
getMenuItems
|
|
2275
|
-
const {
|
|
2276
|
-
isFilterable
|
|
2277
|
-
} = this.props;
|
|
2325
|
+
};
|
|
2326
|
+
const getMenuItems = children => {
|
|
2278
2327
|
if (!isFilterable) {
|
|
2279
|
-
return children.map(
|
|
2328
|
+
return children.map(mapOptionItemToDropdownItem);
|
|
2280
2329
|
}
|
|
2281
|
-
const {
|
|
2282
|
-
searchText,
|
|
2283
|
-
lastSelectedValues
|
|
2284
|
-
} = this.state;
|
|
2285
2330
|
const lowercasedSearchText = searchText.toLowerCase();
|
|
2286
2331
|
const filteredChildren = children.filter(({
|
|
2287
2332
|
props
|
|
@@ -2295,7 +2340,7 @@ class MultiSelect extends React.Component {
|
|
|
2295
2340
|
restOfTheChildren.push(child);
|
|
2296
2341
|
}
|
|
2297
2342
|
}
|
|
2298
|
-
const lastSelectedItems = lastSelectedChildren.map(
|
|
2343
|
+
const lastSelectedItems = lastSelectedChildren.map(mapOptionItemToDropdownItem);
|
|
2299
2344
|
if (lastSelectedChildren.length && restOfTheChildren.length) {
|
|
2300
2345
|
lastSelectedItems.push({
|
|
2301
2346
|
component: React.createElement(SeparatorItem, {
|
|
@@ -2305,116 +2350,109 @@ class MultiSelect extends React.Component {
|
|
|
2305
2350
|
populatedProps: {}
|
|
2306
2351
|
});
|
|
2307
2352
|
}
|
|
2308
|
-
return [...lastSelectedItems, ...restOfTheChildren.map(
|
|
2309
|
-
}
|
|
2310
|
-
|
|
2311
|
-
const
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2353
|
+
return [...lastSelectedItems, ...restOfTheChildren.map(mapOptionItemToDropdownItem)];
|
|
2354
|
+
};
|
|
2355
|
+
const mapOptionItemToDropdownItem = option => {
|
|
2356
|
+
const {
|
|
2357
|
+
disabled,
|
|
2358
|
+
value
|
|
2359
|
+
} = option.props;
|
|
2360
|
+
return {
|
|
2361
|
+
component: option,
|
|
2362
|
+
focusable: !disabled,
|
|
2363
|
+
populatedProps: {
|
|
2364
|
+
onToggle: handleToggle,
|
|
2365
|
+
selected: selectedValues.includes(value),
|
|
2366
|
+
variant: "checkbox"
|
|
2367
|
+
}
|
|
2368
|
+
};
|
|
2369
|
+
};
|
|
2370
|
+
const handleOpenerRef = node => {
|
|
2371
|
+
const openerElement = ReactDOM.findDOMNode(node);
|
|
2372
|
+
setOpenerElement(openerElement);
|
|
2373
|
+
};
|
|
2374
|
+
const handleSearchTextChanged = searchText => {
|
|
2375
|
+
setSearchText(searchText);
|
|
2376
|
+
};
|
|
2377
|
+
const handleClick = e => {
|
|
2378
|
+
handleOpenChanged(!open);
|
|
2379
|
+
};
|
|
2380
|
+
const renderOpener = (allChildren, isDisabled, dropdownId) => {
|
|
2319
2381
|
const {
|
|
2320
2382
|
noneSelected
|
|
2321
|
-
} =
|
|
2322
|
-
const menuText =
|
|
2383
|
+
} = labels;
|
|
2384
|
+
const menuText = getMenuText(allChildren);
|
|
2323
2385
|
const dropdownOpener = React.createElement(IDProvider, {
|
|
2324
2386
|
id: id,
|
|
2325
2387
|
scope: "multi-select-opener"
|
|
2326
2388
|
}, uniqueOpenerId => {
|
|
2327
2389
|
return opener ? React.createElement(DropdownOpener, {
|
|
2328
2390
|
id: uniqueOpenerId,
|
|
2391
|
+
error: hasError,
|
|
2329
2392
|
"aria-controls": dropdownId,
|
|
2330
2393
|
"aria-haspopup": "listbox",
|
|
2331
|
-
onClick:
|
|
2394
|
+
onClick: handleClick,
|
|
2395
|
+
onBlur: onOpenerBlurValidation,
|
|
2332
2396
|
disabled: isDisabled,
|
|
2333
|
-
ref:
|
|
2397
|
+
ref: handleOpenerRef,
|
|
2334
2398
|
text: menuText,
|
|
2335
|
-
opened:
|
|
2399
|
+
opened: open
|
|
2336
2400
|
}, opener) : React.createElement(SelectOpener, _extends({}, sharedProps, {
|
|
2401
|
+
error: hasError,
|
|
2337
2402
|
disabled: isDisabled,
|
|
2338
2403
|
id: uniqueOpenerId,
|
|
2339
2404
|
"aria-controls": dropdownId,
|
|
2340
2405
|
isPlaceholder: menuText === noneSelected,
|
|
2341
2406
|
light: light,
|
|
2342
|
-
onOpenChanged:
|
|
2343
|
-
|
|
2344
|
-
|
|
2407
|
+
onOpenChanged: handleOpenChanged,
|
|
2408
|
+
onBlur: onOpenerBlurValidation,
|
|
2409
|
+
open: open,
|
|
2410
|
+
ref: handleOpenerRef,
|
|
2345
2411
|
testId: testId
|
|
2346
2412
|
}), menuText);
|
|
2347
2413
|
});
|
|
2348
2414
|
return dropdownOpener;
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2415
|
+
};
|
|
2416
|
+
const {
|
|
2417
|
+
clearSearch,
|
|
2418
|
+
filter,
|
|
2419
|
+
noResults,
|
|
2420
|
+
someSelected
|
|
2421
|
+
} = labels;
|
|
2422
|
+
const allChildren = React.Children.toArray(children).filter(Boolean);
|
|
2423
|
+
const numEnabledOptions = allChildren.filter(option => !option.props.disabled).length;
|
|
2424
|
+
const filteredItems = getMenuItems(allChildren);
|
|
2425
|
+
const isDisabled = numEnabledOptions === 0 || disabled;
|
|
2426
|
+
return React.createElement(IDProvider, {
|
|
2427
|
+
id: dropdownId,
|
|
2428
|
+
scope: "multi-select-dropdown"
|
|
2429
|
+
}, uniqueDropdownId => React.createElement(DropdownCore$1, {
|
|
2430
|
+
id: uniqueDropdownId,
|
|
2431
|
+
role: "listbox",
|
|
2432
|
+
alignment: alignment,
|
|
2433
|
+
dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
|
|
2434
|
+
isFilterable: isFilterable,
|
|
2435
|
+
items: [...getShortcuts(numEnabledOptions), ...filteredItems],
|
|
2436
|
+
light: light,
|
|
2437
|
+
onOpenChanged: handleOpenChanged,
|
|
2438
|
+
open: open,
|
|
2439
|
+
opener: renderOpener(allChildren, isDisabled, uniqueDropdownId),
|
|
2440
|
+
openerElement: openerElement,
|
|
2441
|
+
selectionType: "multi",
|
|
2442
|
+
style: style,
|
|
2443
|
+
className: className,
|
|
2444
|
+
onSearchTextChanged: isFilterable ? handleSearchTextChanged : undefined,
|
|
2445
|
+
searchText: isFilterable ? searchText : "",
|
|
2446
|
+
labels: {
|
|
2369
2447
|
clearSearch,
|
|
2370
2448
|
filter,
|
|
2371
2449
|
noResults,
|
|
2372
|
-
someSelected
|
|
2373
|
-
}
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
return React.createElement(IDProvider, {
|
|
2379
|
-
id: dropdownId,
|
|
2380
|
-
scope: "multi-select-dropdown"
|
|
2381
|
-
}, uniqueDropdownId => React.createElement(DropdownCore$1, {
|
|
2382
|
-
id: uniqueDropdownId,
|
|
2383
|
-
role: "listbox",
|
|
2384
|
-
alignment: alignment,
|
|
2385
|
-
dropdownStyle: [isFilterable && filterableDropdownStyle, selectDropdownStyle, dropdownStyle],
|
|
2386
|
-
isFilterable: isFilterable,
|
|
2387
|
-
items: [...this.getShortcuts(numEnabledOptions), ...filteredItems],
|
|
2388
|
-
light: light,
|
|
2389
|
-
onOpenChanged: this.handleOpenChanged,
|
|
2390
|
-
open: open,
|
|
2391
|
-
opener: this.renderOpener(allChildren, isDisabled, uniqueDropdownId),
|
|
2392
|
-
openerElement: this.state.openerElement,
|
|
2393
|
-
selectionType: "multi",
|
|
2394
|
-
style: style,
|
|
2395
|
-
className: className,
|
|
2396
|
-
onSearchTextChanged: isFilterable ? this.handleSearchTextChanged : undefined,
|
|
2397
|
-
searchText: isFilterable ? searchText : "",
|
|
2398
|
-
labels: {
|
|
2399
|
-
clearSearch,
|
|
2400
|
-
filter,
|
|
2401
|
-
noResults,
|
|
2402
|
-
someResults: someSelected
|
|
2403
|
-
},
|
|
2404
|
-
"aria-invalid": ariaInvalid,
|
|
2405
|
-
"aria-required": ariaRequired,
|
|
2406
|
-
disabled: isDisabled
|
|
2407
|
-
}));
|
|
2408
|
-
}
|
|
2409
|
-
}
|
|
2410
|
-
MultiSelect.defaultProps = {
|
|
2411
|
-
alignment: "left",
|
|
2412
|
-
disabled: false,
|
|
2413
|
-
error: false,
|
|
2414
|
-
light: false,
|
|
2415
|
-
shortcuts: false,
|
|
2416
|
-
selectedValues: [],
|
|
2417
|
-
showOpenerLabelAsText: true
|
|
2450
|
+
someResults: someSelected
|
|
2451
|
+
},
|
|
2452
|
+
"aria-invalid": ariaInvalid,
|
|
2453
|
+
"aria-required": ariaRequired,
|
|
2454
|
+
disabled: isDisabled
|
|
2455
|
+
}));
|
|
2418
2456
|
};
|
|
2419
2457
|
|
|
2420
2458
|
function updateMultipleSelection(previousSelection, value = "") {
|