@khanacademy/wonder-blocks-dropdown 2.6.10 → 2.7.2
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 +33 -0
- package/dist/es/index.js +36 -140
- package/dist/index.js +88 -198
- package/package.json +10 -9
- package/src/components/__tests__/dropdown-core-virtualized.test.js +0 -9
- package/src/components/__tests__/search-text-input.test.js +124 -57
- package/src/components/dropdown-core.js +12 -0
- package/src/components/search-text-input.js +34 -146
- package/src/components/single-select.stories.js +9 -2
- package/src/util/constants.js +3 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import {
|
|
4
|
-
import "
|
|
3
|
+
import {render, screen} from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
5
|
|
|
6
6
|
import SearchTextInput from "../search-text-input.js";
|
|
7
7
|
|
|
8
8
|
describe("SearchTextInput", () => {
|
|
9
|
-
|
|
9
|
+
test("text input container should be focused when focusing on the input", () => {
|
|
10
10
|
// Arrange
|
|
11
|
-
|
|
11
|
+
render(
|
|
12
12
|
<SearchTextInput
|
|
13
13
|
searchText=""
|
|
14
14
|
testId="search-text-input"
|
|
@@ -16,18 +16,18 @@ describe("SearchTextInput", () => {
|
|
|
16
16
|
/>,
|
|
17
17
|
);
|
|
18
18
|
|
|
19
|
-
const input =
|
|
19
|
+
const input = screen.getByTestId("search-text-input");
|
|
20
20
|
|
|
21
21
|
// Act
|
|
22
|
-
input.
|
|
22
|
+
input.focus();
|
|
23
23
|
|
|
24
24
|
// Assert
|
|
25
|
-
expect(
|
|
25
|
+
expect(input).toHaveFocus();
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
test("text input should not be focused when losing focus", () => {
|
|
29
29
|
// Arrange
|
|
30
|
-
|
|
30
|
+
render(
|
|
31
31
|
<SearchTextInput
|
|
32
32
|
searchText=""
|
|
33
33
|
testId="search-text-input"
|
|
@@ -35,23 +35,23 @@ describe("SearchTextInput", () => {
|
|
|
35
35
|
/>,
|
|
36
36
|
);
|
|
37
37
|
|
|
38
|
-
const input =
|
|
38
|
+
const input = screen.getByTestId("search-text-input");
|
|
39
39
|
// focus in
|
|
40
|
-
input.
|
|
40
|
+
input.focus();
|
|
41
41
|
|
|
42
42
|
// Act
|
|
43
43
|
// focus out
|
|
44
|
-
input.
|
|
44
|
+
input.blur();
|
|
45
45
|
|
|
46
46
|
// Assert
|
|
47
|
-
expect(
|
|
47
|
+
expect(input).not.toHaveFocus();
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
test("onChange should be invoked if text input changes", () => {
|
|
51
51
|
// Arrange
|
|
52
52
|
const onChangeMock = jest.fn();
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
render(
|
|
55
55
|
<SearchTextInput
|
|
56
56
|
searchText=""
|
|
57
57
|
testId="search-text-input"
|
|
@@ -59,87 +59,154 @@ describe("SearchTextInput", () => {
|
|
|
59
59
|
/>,
|
|
60
60
|
);
|
|
61
61
|
|
|
62
|
-
const input =
|
|
62
|
+
const input = screen.getByTestId("search-text-input");
|
|
63
63
|
|
|
64
64
|
// Act
|
|
65
|
-
|
|
66
|
-
target: {value: "query"},
|
|
67
|
-
preventDefault: jest.fn(),
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
wrapper.update();
|
|
65
|
+
userEvent.paste(input, "value");
|
|
71
66
|
|
|
72
67
|
// Assert
|
|
73
|
-
expect(onChangeMock).toHaveBeenCalledWith("
|
|
68
|
+
expect(onChangeMock).toHaveBeenCalledWith("value");
|
|
74
69
|
});
|
|
75
70
|
|
|
76
|
-
|
|
71
|
+
test("displays the dismiss button when search text exists", () => {
|
|
77
72
|
// Arrange
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
73
|
+
const SearchFieldWrapper = () => {
|
|
74
|
+
const [value, setValue] = React.useState("");
|
|
75
|
+
return (
|
|
76
|
+
<SearchTextInput
|
|
77
|
+
searchText={value}
|
|
78
|
+
testId="search-text-input"
|
|
79
|
+
onChange={setValue}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
render(<SearchFieldWrapper />);
|
|
85
|
+
|
|
86
|
+
const input = screen.getByTestId("search-text-input");
|
|
87
|
+
|
|
88
|
+
// Act
|
|
89
|
+
userEvent.paste(input, "value");
|
|
90
|
+
|
|
91
|
+
// Assert
|
|
92
|
+
const clearIconButton = screen.queryByRole("button");
|
|
93
|
+
expect(clearIconButton).toBeInTheDocument();
|
|
94
|
+
});
|
|
86
95
|
|
|
87
|
-
|
|
96
|
+
test("search should be cleared if the clear icon is clicked", () => {
|
|
97
|
+
// Arrange
|
|
98
|
+
const SearchFieldWrapper = () => {
|
|
99
|
+
const [value, setValue] = React.useState("initial value");
|
|
100
|
+
return (
|
|
101
|
+
<SearchTextInput
|
|
102
|
+
searchText={value}
|
|
103
|
+
testId="search-text-input"
|
|
104
|
+
onChange={setValue}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
render(<SearchFieldWrapper />);
|
|
110
|
+
|
|
111
|
+
const input = screen.getByTestId("search-text-input");
|
|
112
|
+
const clearIconButton = screen.queryByRole("button");
|
|
88
113
|
|
|
89
114
|
// Act
|
|
90
|
-
|
|
91
|
-
target: {value: "query"},
|
|
92
|
-
preventDefault: jest.fn(),
|
|
93
|
-
});
|
|
115
|
+
userEvent.click(clearIconButton);
|
|
94
116
|
|
|
95
117
|
// Assert
|
|
96
|
-
expect(
|
|
118
|
+
expect(input).toHaveValue("");
|
|
97
119
|
});
|
|
98
120
|
|
|
99
|
-
|
|
121
|
+
test("focus should return to the input element after clear button is clicked", () => {
|
|
100
122
|
// Arrange
|
|
101
|
-
const
|
|
123
|
+
const SearchFieldWrapper = () => {
|
|
124
|
+
const [value, setValue] = React.useState("");
|
|
125
|
+
return (
|
|
126
|
+
<SearchTextInput
|
|
127
|
+
searchText={value}
|
|
128
|
+
testId="search-text-input"
|
|
129
|
+
onChange={setValue}
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
render(<SearchFieldWrapper />);
|
|
135
|
+
|
|
136
|
+
const input = screen.getByTestId("search-text-input");
|
|
137
|
+
userEvent.paste(input, "something");
|
|
102
138
|
|
|
103
|
-
|
|
139
|
+
// Act
|
|
140
|
+
const clearIconButton = screen.queryByRole("button");
|
|
141
|
+
userEvent.click(clearIconButton);
|
|
142
|
+
|
|
143
|
+
// Assert
|
|
144
|
+
expect(input).toHaveFocus();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("placeholder should be updated by the parent component", () => {
|
|
148
|
+
// Arrange
|
|
149
|
+
const {rerender} = render(
|
|
104
150
|
<SearchTextInput
|
|
105
151
|
searchText="query"
|
|
106
|
-
onChange={() =>
|
|
107
|
-
|
|
152
|
+
onChange={() => {}}
|
|
153
|
+
labels={{
|
|
154
|
+
clearSearch: "Clear",
|
|
155
|
+
filter: "Filter",
|
|
156
|
+
}}
|
|
157
|
+
testId="search-text-input"
|
|
108
158
|
/>,
|
|
109
159
|
);
|
|
110
160
|
|
|
111
|
-
const
|
|
161
|
+
const input = screen.getByTestId("search-text-input");
|
|
112
162
|
|
|
113
163
|
// Act
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
164
|
+
rerender(
|
|
165
|
+
<SearchTextInput
|
|
166
|
+
searchText="query"
|
|
167
|
+
onChange={() => {}}
|
|
168
|
+
labels={{
|
|
169
|
+
clearSearch: "Dismiss",
|
|
170
|
+
filter: "Search",
|
|
171
|
+
}}
|
|
172
|
+
testId="search-text-input"
|
|
173
|
+
/>,
|
|
174
|
+
);
|
|
117
175
|
|
|
118
176
|
// Assert
|
|
119
|
-
expect(
|
|
177
|
+
expect(input).toHaveAttribute("placeholder", "Search");
|
|
120
178
|
});
|
|
121
179
|
|
|
122
|
-
|
|
180
|
+
test("button label should be updated by the parent component", () => {
|
|
123
181
|
// Arrange
|
|
124
|
-
const
|
|
182
|
+
const {rerender} = render(
|
|
125
183
|
<SearchTextInput
|
|
126
184
|
searchText="query"
|
|
127
|
-
onChange={() =>
|
|
185
|
+
onChange={() => {}}
|
|
128
186
|
labels={{
|
|
129
187
|
clearSearch: "Clear",
|
|
130
188
|
filter: "Filter",
|
|
131
189
|
}}
|
|
190
|
+
testId="search-text-input"
|
|
132
191
|
/>,
|
|
133
192
|
);
|
|
134
193
|
|
|
135
|
-
|
|
136
|
-
wrapper.setProps({labels: {clearSearch: "Dismiss", filter: "Search"}});
|
|
194
|
+
const clearIconButton = screen.queryByRole("button");
|
|
137
195
|
|
|
138
|
-
|
|
196
|
+
// Act
|
|
197
|
+
rerender(
|
|
198
|
+
<SearchTextInput
|
|
199
|
+
searchText="query"
|
|
200
|
+
onChange={() => {}}
|
|
201
|
+
labels={{
|
|
202
|
+
clearSearch: "Dismiss",
|
|
203
|
+
filter: "Search",
|
|
204
|
+
}}
|
|
205
|
+
testId="search-text-input"
|
|
206
|
+
/>,
|
|
207
|
+
);
|
|
139
208
|
|
|
140
209
|
// Assert
|
|
141
|
-
expect(
|
|
142
|
-
labels: {clearSearch: "Dismiss", filter: "Search"},
|
|
143
|
-
});
|
|
210
|
+
expect(clearIconButton).toHaveAttribute("aria-label", "Dismiss");
|
|
144
211
|
});
|
|
145
212
|
});
|
|
@@ -669,6 +669,12 @@ class DropdownCore extends React.Component<Props, State> {
|
|
|
669
669
|
},
|
|
670
670
|
// apply custom styles
|
|
671
671
|
style: searchInputStyle,
|
|
672
|
+
// TODO(WB-1310): Remove the autofocus prop after making
|
|
673
|
+
// the search field sticky.
|
|
674
|
+
// Currently autofocusing on the search field to work
|
|
675
|
+
// around it losing focus on mount when switching between
|
|
676
|
+
// virtualized and non-virtualized dropdown filter results.
|
|
677
|
+
autofocus: this.focusedIndex === 0,
|
|
672
678
|
});
|
|
673
679
|
}
|
|
674
680
|
|
|
@@ -719,6 +725,12 @@ class DropdownCore extends React.Component<Props, State> {
|
|
|
719
725
|
itemRef: this.state.itemRefs[focusIndex]
|
|
720
726
|
? this.state.itemRefs[focusIndex].ref
|
|
721
727
|
: null,
|
|
728
|
+
// TODO(WB-1310): Remove the autofocus prop after making
|
|
729
|
+
// the search field sticky.
|
|
730
|
+
// Currently autofocusing on the search field to work
|
|
731
|
+
// around it losing focus on mount when switching between
|
|
732
|
+
// virtualized and non-virtualized dropdown filter results.
|
|
733
|
+
autofocus: this.focusedIndex === 0,
|
|
722
734
|
},
|
|
723
735
|
};
|
|
724
736
|
}
|
|
@@ -2,17 +2,11 @@
|
|
|
2
2
|
// A TextField with a search icon on its left side and X icon on its right side
|
|
3
3
|
|
|
4
4
|
import * as React from "react";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import {styles as typographyStyles} from "@khanacademy/wonder-blocks-typography";
|
|
8
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
9
|
-
import IconButton from "@khanacademy/wonder-blocks-icon-button";
|
|
10
|
-
import Icon, {icons} from "@khanacademy/wonder-blocks-icon";
|
|
11
|
-
import Color from "@khanacademy/wonder-blocks-color";
|
|
12
|
-
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
5
|
+
|
|
6
|
+
import SearchField from "@khanacademy/wonder-blocks-search-field";
|
|
13
7
|
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
14
8
|
|
|
15
|
-
import {defaultLabels
|
|
9
|
+
import {defaultLabels} from "../util/constants.js";
|
|
16
10
|
|
|
17
11
|
type Labels = {|
|
|
18
12
|
clearSearch: string,
|
|
@@ -57,22 +51,20 @@ type Props = {|
|
|
|
57
51
|
* Test ID used for e2e testing.
|
|
58
52
|
*/
|
|
59
53
|
testId?: string,
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Automatically focus on this search field on mount.
|
|
57
|
+
* TODO(WB-1310): Remove the autofocus prop after making
|
|
58
|
+
* the search field sticky in dropdowns.
|
|
59
|
+
*/
|
|
60
|
+
autofocus?: boolean,
|
|
60
61
|
|};
|
|
61
62
|
|
|
62
63
|
type DefaultProps = {|
|
|
63
64
|
labels: $PropertyType<Props, "labels">,
|
|
64
65
|
|};
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
focused: boolean,
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* The object containing the custom labels used inside this component.
|
|
71
|
-
*/
|
|
72
|
-
labels: Labels,
|
|
73
|
-
|};
|
|
74
|
-
|
|
75
|
-
export default class SearchTextInput extends React.Component<Props, State> {
|
|
67
|
+
export default class SearchTextInput extends React.Component<Props> {
|
|
76
68
|
static isClassOf(instance: React.Element<any>): boolean {
|
|
77
69
|
return (
|
|
78
70
|
instance && instance.type && instance.type.__IS_SEARCH_TEXT_INPUT__
|
|
@@ -86,142 +78,38 @@ export default class SearchTextInput extends React.Component<Props, State> {
|
|
|
86
78
|
},
|
|
87
79
|
};
|
|
88
80
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (this.props.
|
|
100
|
-
|
|
101
|
-
this.setState({
|
|
102
|
-
labels: {...this.state.labels, ...this.props.labels},
|
|
103
|
-
});
|
|
81
|
+
// TODO(WB-1310): Remove `componentDidMount` autofocus on the search field
|
|
82
|
+
// after making the search field sticky.
|
|
83
|
+
componentDidMount() {
|
|
84
|
+
// We need to re-focus on the text input after it mounts because of
|
|
85
|
+
// the case in which the dropdown switches between virtualized and
|
|
86
|
+
// non-virtualized. It can rerender the search field as the user is
|
|
87
|
+
// typing based on the number of search results, which results
|
|
88
|
+
// in losing focus on the field so the user can't type anymore.
|
|
89
|
+
// To work around this issue, this temporary fix auto-focuses on the
|
|
90
|
+
// search field on mount.
|
|
91
|
+
if (this.props.autofocus) {
|
|
92
|
+
this.props.itemRef?.current.focus();
|
|
104
93
|
}
|
|
105
94
|
}
|
|
106
95
|
|
|
107
96
|
static __IS_SEARCH_TEXT_INPUT__: boolean = true;
|
|
108
97
|
|
|
109
|
-
handleChange: (e: SyntheticInputEvent<>) => void = (e) => {
|
|
110
|
-
e.preventDefault();
|
|
111
|
-
this.props.onChange(e.target.value);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
handleDismiss: () => void = () => {
|
|
115
|
-
const {onClick, onChange} = this.props;
|
|
116
|
-
// Empty the search text and focus the SearchTextInput
|
|
117
|
-
onChange("");
|
|
118
|
-
if (onClick) {
|
|
119
|
-
onClick();
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
handleBlur: (e: SyntheticInputEvent<>) => void = (e) => {
|
|
124
|
-
this.setState({focused: false});
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
handleFocus: (e: SyntheticInputEvent<>) => void = (e) => {
|
|
128
|
-
this.setState({focused: true});
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
maybeRenderDismissIconButton(): React.Node {
|
|
132
|
-
const {searchText} = this.props;
|
|
133
|
-
const {clearSearch} = this.state.labels;
|
|
134
|
-
|
|
135
|
-
if (searchText.length > 0) {
|
|
136
|
-
return (
|
|
137
|
-
<IconButton
|
|
138
|
-
icon={icons.dismiss}
|
|
139
|
-
kind="tertiary"
|
|
140
|
-
onClick={this.handleDismiss}
|
|
141
|
-
style={styles.dismissIcon}
|
|
142
|
-
aria-label={clearSearch}
|
|
143
|
-
/>
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
98
|
render(): React.Node {
|
|
150
|
-
const {onClick, itemRef, searchText, style, testId} =
|
|
151
|
-
|
|
99
|
+
const {labels, onChange, onClick, itemRef, searchText, style, testId} =
|
|
100
|
+
this.props;
|
|
152
101
|
|
|
153
102
|
return (
|
|
154
|
-
<
|
|
103
|
+
<SearchField
|
|
104
|
+
clearAriaLabel={labels.clearSearch}
|
|
105
|
+
onChange={onChange}
|
|
155
106
|
onClick={onClick}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
<Icon
|
|
163
|
-
icon={icons.search}
|
|
164
|
-
size="medium"
|
|
165
|
-
color={Color.offBlack64}
|
|
166
|
-
style={styles.searchIcon}
|
|
167
|
-
aria-hidden="true"
|
|
168
|
-
/>
|
|
169
|
-
<input
|
|
170
|
-
type="text"
|
|
171
|
-
onChange={this.handleChange}
|
|
172
|
-
onFocus={this.handleFocus}
|
|
173
|
-
onBlur={this.handleBlur}
|
|
174
|
-
ref={itemRef}
|
|
175
|
-
placeholder={filter}
|
|
176
|
-
value={searchText}
|
|
177
|
-
className={css(
|
|
178
|
-
styles.inputStyleReset,
|
|
179
|
-
typographyStyles.LabelMedium,
|
|
180
|
-
)}
|
|
181
|
-
data-test-id={testId}
|
|
182
|
-
/>
|
|
183
|
-
{this.maybeRenderDismissIconButton()}
|
|
184
|
-
</View>
|
|
107
|
+
placeholder={labels.filter}
|
|
108
|
+
ref={itemRef}
|
|
109
|
+
style={style}
|
|
110
|
+
testId={testId}
|
|
111
|
+
value={searchText}
|
|
112
|
+
/>
|
|
185
113
|
);
|
|
186
114
|
}
|
|
187
115
|
}
|
|
188
|
-
|
|
189
|
-
const styles = StyleSheet.create({
|
|
190
|
-
inputContainer: {
|
|
191
|
-
flexDirection: "row",
|
|
192
|
-
border: `1px solid ${Color.offBlack16}`,
|
|
193
|
-
borderRadius: Spacing.xxxSmall_4,
|
|
194
|
-
alignItems: "center",
|
|
195
|
-
// The height of the text input is 40 in design spec and we need to
|
|
196
|
-
// specify the height as well as minHeight to make sure the search text
|
|
197
|
-
// input takes enough height to render. (otherwise, it will get
|
|
198
|
-
// squashed)
|
|
199
|
-
height: DROPDOWN_ITEM_HEIGHT,
|
|
200
|
-
minHeight: DROPDOWN_ITEM_HEIGHT,
|
|
201
|
-
},
|
|
202
|
-
focused: {
|
|
203
|
-
border: `1px solid ${Color.blue}`,
|
|
204
|
-
},
|
|
205
|
-
searchIcon: {
|
|
206
|
-
marginLeft: Spacing.xSmall_8,
|
|
207
|
-
marginRight: Spacing.xSmall_8,
|
|
208
|
-
},
|
|
209
|
-
dismissIcon: {
|
|
210
|
-
margin: 0,
|
|
211
|
-
":hover": {
|
|
212
|
-
border: "none",
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
inputStyleReset: {
|
|
216
|
-
display: "flex",
|
|
217
|
-
flex: 1,
|
|
218
|
-
background: "inherit",
|
|
219
|
-
border: "none",
|
|
220
|
-
outline: "none",
|
|
221
|
-
"::placeholder": {
|
|
222
|
-
color: Color.offBlack64,
|
|
223
|
-
},
|
|
224
|
-
width: "100%",
|
|
225
|
-
color: "inherit",
|
|
226
|
-
},
|
|
227
|
-
});
|
|
@@ -79,25 +79,28 @@ const optionItems = new Array(1000)
|
|
|
79
79
|
));
|
|
80
80
|
|
|
81
81
|
type Props = {|
|
|
82
|
+
selectedValue?: ?string,
|
|
82
83
|
opened: boolean,
|
|
83
84
|
|};
|
|
84
85
|
|
|
85
86
|
type State = {|
|
|
86
|
-
selectedValue
|
|
87
|
+
selectedValue?: ?string,
|
|
87
88
|
opened: boolean,
|
|
88
89
|
|};
|
|
89
90
|
|
|
90
91
|
type DefaultProps = {|
|
|
92
|
+
selectedValue: $PropertyType<Props, "selectedValue">,
|
|
91
93
|
opened: $PropertyType<Props, "opened">,
|
|
92
94
|
|};
|
|
93
95
|
|
|
94
96
|
class SingleSelectWithFilter extends React.Component<Props, State> {
|
|
95
97
|
static defaultProps: DefaultProps = {
|
|
98
|
+
selectedValue: "2",
|
|
96
99
|
opened: false,
|
|
97
100
|
};
|
|
98
101
|
|
|
99
102
|
state: State = {
|
|
100
|
-
selectedValue:
|
|
103
|
+
selectedValue: this.props.selectedValue,
|
|
101
104
|
opened: this.props.opened,
|
|
102
105
|
};
|
|
103
106
|
|
|
@@ -167,6 +170,10 @@ export const WithFilterOpened: StoryComponentType = () => (
|
|
|
167
170
|
<SingleSelectWithFilter opened={true} />
|
|
168
171
|
);
|
|
169
172
|
|
|
173
|
+
export const WithFilterOpenedNoValueSelected: StoryComponentType = () => (
|
|
174
|
+
<SingleSelectWithFilter opened={true} selectedValue={null} />
|
|
175
|
+
);
|
|
176
|
+
|
|
170
177
|
export const DropdownInModal: StoryComponentType = () => {
|
|
171
178
|
const [value, setValue] = React.useState(null);
|
|
172
179
|
const [opened, setOpened] = React.useState(true);
|
package/src/util/constants.js
CHANGED
|
@@ -24,6 +24,9 @@ export const filterableDropdownStyle = {
|
|
|
24
24
|
export const searchInputStyle = {
|
|
25
25
|
margin: Spacing.xSmall_8,
|
|
26
26
|
marginTop: Spacing.xxxSmall_4,
|
|
27
|
+
// Set `minHeight` to "auto" to stop the search field from having
|
|
28
|
+
// a height of 0 and being cut off.
|
|
29
|
+
minHeight: "auto",
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
// The default item height
|