@khanacademy/wonder-blocks-dropdown 2.8.2 → 2.9.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 +28 -0
- package/dist/es/index.js +18 -9
- package/dist/index.js +41 -30
- package/docs.md +4 -11
- package/package.json +9 -10
- package/src/components/__docs__/single-select.stories.js +54 -0
- package/src/components/__tests__/single-select.test.js +95 -0
- package/src/components/dropdown-core.js +7 -7
- package/src/components/multi-select.js +1 -1
- package/src/components/single-select.js +42 -4
- package/src/index.js +2 -1
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +0 -4548
- package/src/__tests__/generated-snapshot.test.js +0 -1612
- package/src/components/action-menu.md +0 -338
- package/src/components/multi-select.md +0 -718
- package/src/components/single-select.md +0 -520
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
The action menu is used for items that trigger actions, such as navigating to
|
|
2
|
-
a different page or opening a modal.
|
|
3
|
-
|
|
4
|
-
### Basic, right-aligned action menu
|
|
5
|
-
|
|
6
|
-
This menu shows different type of possible items in this type of menu:
|
|
7
|
-
|
|
8
|
-
1. leads to a different page (the profile)
|
|
9
|
-
2. leads to the teacher dashboard
|
|
10
|
-
3. has an onClick callback, which could be used for conversion logging
|
|
11
|
-
4. is a disabled item
|
|
12
|
-
5. is a separator
|
|
13
|
-
6. leads to the logout link
|
|
14
|
-
|
|
15
|
-
This menu is also right-aligned.
|
|
16
|
-
|
|
17
|
-
```js
|
|
18
|
-
import {ActionMenu, ActionItem, SeparatorItem} from "@khanacademy/wonder-blocks-dropdown";
|
|
19
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
20
|
-
import {StyleSheet} from "aphrodite";
|
|
21
|
-
|
|
22
|
-
const styles = StyleSheet.create({
|
|
23
|
-
row: {
|
|
24
|
-
flexDirection: "row",
|
|
25
|
-
justifyContent: "flex-end",
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
<View style={styles.row}>
|
|
29
|
-
<ActionMenu
|
|
30
|
-
alignment="right"
|
|
31
|
-
menuText="Betsy Appleseed"
|
|
32
|
-
testId="teacher-menu"
|
|
33
|
-
>
|
|
34
|
-
<ActionItem label="Profile" href="http://khanacademy.org/profile" target="_blank" testId="profile" />
|
|
35
|
-
<ActionItem label="Teacher dashboard" href="http://khanacademy.org/coach/dashboard" testId="dashboard" />
|
|
36
|
-
<ActionItem label="Settings (onClick)" onClick={() => console.log("user clicked on settings")} testId="settings" />
|
|
37
|
-
<ActionItem label="Help" disabled={true} onClick={() => console.log("this item is disabled...")} testId="help" />
|
|
38
|
-
<ActionItem label="Feedback" disabled={true} href="/feedback" testId="feedback" />
|
|
39
|
-
<SeparatorItem />
|
|
40
|
-
<ActionItem label="Log out" href="http://khanacademy.org/logout" testId="logout" />
|
|
41
|
-
</ActionMenu>
|
|
42
|
-
</View>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Truncated opener
|
|
46
|
-
|
|
47
|
-
The text in the menu opener should be truncated with ellipsis at the end
|
|
48
|
-
and the down caret should be the same size as it is for the other examples.
|
|
49
|
-
|
|
50
|
-
```js
|
|
51
|
-
import {ActionMenu, ActionItem, SeparatorItem} from "@khanacademy/wonder-blocks-dropdown";
|
|
52
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
53
|
-
import {StyleSheet} from "aphrodite";
|
|
54
|
-
import {Spring} from "@khanacademy/wonder-blocks-layout";
|
|
55
|
-
|
|
56
|
-
const styles = StyleSheet.create({
|
|
57
|
-
row: {
|
|
58
|
-
flexDirection: "row",
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
<View style={styles.row}>
|
|
63
|
-
<Spring />
|
|
64
|
-
<ActionMenu
|
|
65
|
-
menuText="Betsy Appleseed"
|
|
66
|
-
style={{width: 100}}
|
|
67
|
-
>
|
|
68
|
-
<ActionItem label="Profile" href="http://khanacademy.org/profile" />
|
|
69
|
-
<ActionItem label="Teacher dashboard" href="http://khanacademy.org/coach/dashboard" />
|
|
70
|
-
<ActionItem label="Settings (onClick)" onClick={() => console.log("user clicked on settings")} />
|
|
71
|
-
<ActionItem label="Help" disabled={true} onClick={() => console.log("this item is disabled...")} />
|
|
72
|
-
<SeparatorItem />
|
|
73
|
-
<ActionItem label="Log out" href="http://khanacademy.org/logout" />
|
|
74
|
-
</ActionMenu>
|
|
75
|
-
</View>
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### Hybrid menu of action items and option items
|
|
79
|
-
|
|
80
|
-
The following menu demonstrates a hybrid menu with both action items and items
|
|
81
|
-
that can toggle to change the state of the application. The user of this menu
|
|
82
|
-
must keep track of the state of the selected items.
|
|
83
|
-
|
|
84
|
-
```js
|
|
85
|
-
import {ActionMenu, ActionItem, OptionItem, SeparatorItem} from "@khanacademy/wonder-blocks-dropdown";
|
|
86
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
87
|
-
import {StyleSheet} from "aphrodite";
|
|
88
|
-
|
|
89
|
-
const styles = StyleSheet.create({
|
|
90
|
-
row: {
|
|
91
|
-
flexDirection: "row",
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
class HybridMenu extends React.Component {
|
|
96
|
-
constructor() {
|
|
97
|
-
super();
|
|
98
|
-
this.state = {
|
|
99
|
-
selectedValues: ["homework"],
|
|
100
|
-
showHiddenOption: false,
|
|
101
|
-
};
|
|
102
|
-
// Styleguidist doesn't support arrow functions in class field properties
|
|
103
|
-
this.handleChange = this.handleChange.bind(this);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
handleChange(update) {
|
|
107
|
-
this.setState({
|
|
108
|
-
selectedValues: update,
|
|
109
|
-
showHiddenOption: update.includes("in-class"),
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
render() {
|
|
114
|
-
const {showHiddenOption} = this.state;
|
|
115
|
-
return <ActionMenu
|
|
116
|
-
menuText="Assignments"
|
|
117
|
-
onChange={this.handleChange}
|
|
118
|
-
selectedValues={this.state.selectedValues}
|
|
119
|
-
>
|
|
120
|
-
<ActionItem label="Create..." onClick={() => console.log("create action")} />
|
|
121
|
-
<ActionItem label="Edit..." disabled={true} onClick={() => console.log("edit action")} />
|
|
122
|
-
<ActionItem label="Delete" disabled={true} onClick={() => console.log("delete action")} />
|
|
123
|
-
{showHiddenOption && <ActionItem label="Hidden menu for class" disabled={!showHiddenOption} onClick={() => console.log("hidden menu is clicked!")} />}
|
|
124
|
-
<SeparatorItem />
|
|
125
|
-
<OptionItem label="Show homework assignments" value="homework"
|
|
126
|
-
onClick={() => console.log(`Show homework assignments toggled`)} />
|
|
127
|
-
<OptionItem label="Show in-class assignments" value="in-class"
|
|
128
|
-
onClick={() => console.log(`Show in-class assignments toggled`)} />
|
|
129
|
-
</ActionMenu>
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
<View style={styles.row}>
|
|
134
|
-
<HybridMenu />
|
|
135
|
-
</View>
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Empty menus are disabled automatically
|
|
139
|
-
|
|
140
|
-
```js
|
|
141
|
-
import {StyleSheet} from "aphrodite";
|
|
142
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
143
|
-
import {ActionMenu} from "@khanacademy/wonder-blocks-dropdown";
|
|
144
|
-
|
|
145
|
-
const styles = StyleSheet.create({
|
|
146
|
-
row: {
|
|
147
|
-
flexDirection: "row",
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
<View style={styles.row}>
|
|
152
|
-
<ActionMenu menuText="Empty" />
|
|
153
|
-
</View>
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### ActionMenu with custom dropdown style
|
|
157
|
-
|
|
158
|
-
This example shows how we can add custom dropdownStyle to the action menu.
|
|
159
|
-
|
|
160
|
-
```js
|
|
161
|
-
import {ActionMenu, ActionItem, SeparatorItem} from "@khanacademy/wonder-blocks-dropdown";
|
|
162
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
163
|
-
import {StyleSheet} from "aphrodite";
|
|
164
|
-
|
|
165
|
-
const styles = StyleSheet.create({
|
|
166
|
-
row: {
|
|
167
|
-
flexDirection: "row",
|
|
168
|
-
},
|
|
169
|
-
dropdown: {
|
|
170
|
-
maxHeight: 200,
|
|
171
|
-
},
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
<View style={styles.row}>
|
|
175
|
-
<ActionMenu
|
|
176
|
-
menuText="Betsy Appleseed"
|
|
177
|
-
testId="teacher-menu"
|
|
178
|
-
dropdownStyle={styles.dropdown}
|
|
179
|
-
>
|
|
180
|
-
<ActionItem label="Profile" href="http://khanacademy.org/profile" testId="profile" />
|
|
181
|
-
<ActionItem label="Teacher dashboard" href="http://khanacademy.org/coach/dashboard" testId="dashboard" />
|
|
182
|
-
<ActionItem label="Settings (onClick)" onClick={() => console.log("user clicked on settings")} testId="settings" />
|
|
183
|
-
<ActionItem label="Help" disabled={true} onClick={() => console.log("this item is disabled...")} testId="help" />
|
|
184
|
-
<ActionItem label="Feedback" disabled={true} href="/feedback" testId="feedback" />
|
|
185
|
-
<SeparatorItem />
|
|
186
|
-
<ActionItem label="Log out" href="http://khanacademy.org/logout" testId="logout" />
|
|
187
|
-
</ActionMenu>
|
|
188
|
-
</View>
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### Example: Opening an ActionMenu programmatically
|
|
192
|
-
|
|
193
|
-
Sometimes you'll want to trigger a dropdown programmatically. This can be done by
|
|
194
|
-
setting a value to the `opened` prop (`true` or `false`). In this situation the `ActionMenu` is a
|
|
195
|
-
controlled component. The parent is responsible for managing the opening/closing
|
|
196
|
-
of the dropdown when using this prop.
|
|
197
|
-
|
|
198
|
-
This means that you'll also have to update `opened` to the value triggered by
|
|
199
|
-
the `onToggle` prop.
|
|
200
|
-
|
|
201
|
-
```js
|
|
202
|
-
import {ActionItem, OptionItem, SeparatorItem} from "@khanacademy/wonder-blocks-dropdown";
|
|
203
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
204
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
205
|
-
import {Strut} from "@khanacademy/wonder-blocks-layout";
|
|
206
|
-
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
207
|
-
import {StyleSheet} from "aphrodite";
|
|
208
|
-
|
|
209
|
-
const styles = StyleSheet.create({
|
|
210
|
-
row: {
|
|
211
|
-
flexDirection: "row",
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
class ControlledActionMenuExample extends React.Component {
|
|
216
|
-
constructor() {
|
|
217
|
-
super();
|
|
218
|
-
this.state = {
|
|
219
|
-
opened: false,
|
|
220
|
-
selectedValues: ["kumail"],
|
|
221
|
-
};
|
|
222
|
-
this.handleChange = this.handleChange.bind(this);
|
|
223
|
-
this.handleToggleMenu = this.handleToggleMenu.bind(this);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
handleChange(update) {
|
|
227
|
-
this.setState({
|
|
228
|
-
selectedValues: update,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
handleToggleMenu(opened) {
|
|
233
|
-
this.setState({
|
|
234
|
-
opened,
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
render() {
|
|
239
|
-
return (
|
|
240
|
-
<View style={styles.row}>
|
|
241
|
-
<ActionMenu
|
|
242
|
-
menuText="Betsy Appleseed"
|
|
243
|
-
onChange={this.handleChange}
|
|
244
|
-
onToggle={(opened) => {
|
|
245
|
-
console.log('toggle called!!!! ', opened);
|
|
246
|
-
this.handleToggleMenu(opened);
|
|
247
|
-
}}
|
|
248
|
-
opened={this.state.opened}
|
|
249
|
-
selectedValues={this.state.selectedValues}
|
|
250
|
-
>
|
|
251
|
-
<ActionItem label="Add new +" />
|
|
252
|
-
<SeparatorItem />
|
|
253
|
-
<OptionItem label="Alex" value="alex" />
|
|
254
|
-
<OptionItem label="Cathy" value="cathy" />
|
|
255
|
-
<OptionItem label="Kumail" value="kumail" />
|
|
256
|
-
<OptionItem label="Salman" value="salman" />
|
|
257
|
-
<OptionItem label="Yan" value="yan" />
|
|
258
|
-
<OptionItem label="Yash" value="yash" />
|
|
259
|
-
</ActionMenu>
|
|
260
|
-
<Strut size={Spacing.medium_16} />
|
|
261
|
-
<Button onClick={() => this.handleToggleMenu(true)}>
|
|
262
|
-
Open ActionMenu programatically
|
|
263
|
-
</Button>
|
|
264
|
-
</View>
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
<ControlledActionMenuExample />
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### Example: ActionMenu with custom opener
|
|
273
|
-
|
|
274
|
-
In case you need to use a custom opener, you can use the `opener` property to
|
|
275
|
-
achieve this. In this example, the `opener` prop accepts a
|
|
276
|
-
function with the following arguments:
|
|
277
|
-
|
|
278
|
-
- `eventState`: lets you customize the style for different states, such as
|
|
279
|
-
`pressed`, `hovered` and `focused`.
|
|
280
|
-
- `text`: Passes the menu label defined in the parent component. This value is
|
|
281
|
-
passed using the `placeholder` prop set in the `ActionMenu` component.
|
|
282
|
-
|
|
283
|
-
**Note:** If you need to use a custom ID for testing the opener, make sure to
|
|
284
|
-
pass the `testId` prop inside the opener component/element.
|
|
285
|
-
|
|
286
|
-
```js
|
|
287
|
-
import {ActionMenu, ActionItem, OptionItem, SeparatorItem} from "@khanacademy/wonder-blocks-dropdown";
|
|
288
|
-
import Color from "@khanacademy/wonder-blocks-color";
|
|
289
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
290
|
-
import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
|
|
291
|
-
import {StyleSheet} from "aphrodite";
|
|
292
|
-
|
|
293
|
-
const styles = StyleSheet.create({
|
|
294
|
-
focused: {
|
|
295
|
-
color: Color.purple,
|
|
296
|
-
},
|
|
297
|
-
hovered: {
|
|
298
|
-
textDecoration: "underline",
|
|
299
|
-
color: Color.purple,
|
|
300
|
-
cursor: "pointer",
|
|
301
|
-
},
|
|
302
|
-
pressed: {
|
|
303
|
-
color: Color.blue,
|
|
304
|
-
},
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
<ActionMenu
|
|
308
|
-
disabled={false}
|
|
309
|
-
menuText="Custom opener"
|
|
310
|
-
opener={({focused, hovered, pressed, text}) => (
|
|
311
|
-
<LabelLarge
|
|
312
|
-
onClick={()=>{console.log('custom click!!!!!')}}
|
|
313
|
-
testId="teacher-menu-custom-opener"
|
|
314
|
-
style={[
|
|
315
|
-
focused && styles.focused,
|
|
316
|
-
hovered && styles.hovered,
|
|
317
|
-
pressed && styles.pressed
|
|
318
|
-
]}
|
|
319
|
-
>
|
|
320
|
-
{text}
|
|
321
|
-
</LabelLarge>
|
|
322
|
-
)}
|
|
323
|
-
>
|
|
324
|
-
<ActionItem label="Profile" href="http://khanacademy.org/profile" testId="profile" />
|
|
325
|
-
<ActionItem label="Settings" onClick={() => console.log("user clicked on settings")} testId="settings" />
|
|
326
|
-
<ActionItem label="Help" disabled={true} onClick={() => console.log("this item is disabled...")} testId="help" />
|
|
327
|
-
<SeparatorItem />
|
|
328
|
-
<ActionItem label="Log out" href="http://khanacademy.org/logout" testId="logout" />
|
|
329
|
-
<OptionItem
|
|
330
|
-
label="Show homework assignments" value="homework"
|
|
331
|
-
onClick={() => console.log(`Show homework assignments toggled`)}
|
|
332
|
-
/>
|
|
333
|
-
<OptionItem
|
|
334
|
-
label="Show in-class assignments" value="in-class"
|
|
335
|
-
onClick={() => console.log(`Show in-class assignments toggled`)}
|
|
336
|
-
/>
|
|
337
|
-
</ActionMenu>
|
|
338
|
-
```
|