@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.
@@ -1,520 +0,0 @@
1
- ### Single select with placeholder and set widths
2
-
3
- This single select has a starting placeholder and a set minWidth and maxWidth.
4
- Notice how the dropdown is always at least as wide as the opener. Also, when
5
- the first item is chosen, the text in the opener would exceed the maxWidth. It
6
- ellipses instead.
7
-
8
- ```js
9
- import {SingleSelect, OptionItem} from "@khanacademy/wonder-blocks-dropdown";
10
- import {View} from "@khanacademy/wonder-blocks-core";
11
- import {StyleSheet} from "aphrodite";
12
-
13
- const styles = StyleSheet.create({
14
- row: {
15
- flexDirection: "row",
16
- },
17
- setWidth: {
18
- minWidth: 170,
19
- maxWidth: 190,
20
- },
21
- });
22
-
23
- class ExampleWithPlaceholder extends React.Component {
24
- constructor() {
25
- super();
26
- this.state = {
27
- selectedValue: null,
28
- };
29
- this.handleChange = this.handleChange.bind(this);
30
- }
31
-
32
- handleChange(selected) {
33
- console.log(`${selected} was selected!`);
34
- this.setState({
35
- selectedValue: selected,
36
- });
37
- }
38
-
39
- render() {
40
- return <SingleSelect
41
- onChange={this.handleChange}
42
- onToggle={(opened) => console.log('toggle: ', opened)}
43
- placeholder="Choose a fruit"
44
- selectedValue={this.state.selectedValue}
45
- style={styles.setWidth}
46
- testId="fruit-select"
47
- >
48
- <OptionItem label="Vine-ripened tomatoes" value="tomato" testId="tomato" />
49
- <OptionItem label="Watermelon" value="watermelon" testId="watermelon" />
50
- <OptionItem label="Strawberry" value="strawberry" testId="strawberry" />
51
- {false && <OptionItem label="Other" value="other" testId="other" />}
52
- </SingleSelect>;
53
- }
54
- }
55
-
56
- <View style={styles.row}>
57
- <ExampleWithPlaceholder />
58
- </View>
59
- ```
60
-
61
- ### Single select with starting selected item and disabled item
62
-
63
- This select starts with a starting selected item. One of the items is disabled
64
- and thus cannot be selected.
65
-
66
- ```js
67
- import {SingleSelect, OptionItem} from "@khanacademy/wonder-blocks-dropdown";
68
- import {View} from "@khanacademy/wonder-blocks-core";
69
- import {StyleSheet} from "aphrodite";
70
-
71
- const styles = StyleSheet.create({
72
- row: {
73
- flexDirection: "row",
74
- },
75
- });
76
-
77
- class ExampleWithStartingSelection extends React.Component {
78
- constructor() {
79
- super();
80
- this.state = {
81
- selectedValue: "banana",
82
- };
83
- // Styleguidist doesn't support arrow functions in class field properties
84
- this.handleChange = this.handleChange.bind(this);
85
- }
86
-
87
- handleChange(selected) {
88
- console.log(`${selected} was selected!`);
89
- this.setState({
90
- selectedValue: selected,
91
- });
92
- }
93
-
94
- render() {
95
- return <SingleSelect
96
- onChange={this.handleChange}
97
- placeholder="Choose a juice"
98
- selectedValue={this.state.selectedValue}
99
- >
100
- <OptionItem label="Banana juice" value="banana" />
101
- <OptionItem label="Guava juice" value="guava" disabled />
102
- <OptionItem label="White grape juice" value="grape" />
103
- </SingleSelect>;
104
- }
105
- }
106
-
107
- <View style={styles.row}>
108
- <ExampleWithStartingSelection />
109
- </View>
110
- ```
111
-
112
- ### Disabled select
113
-
114
- This select is disabled.
115
- ```js
116
- import {SingleSelect, OptionItem} from "@khanacademy/wonder-blocks-dropdown";
117
- import {View} from "@khanacademy/wonder-blocks-core";
118
- import {StyleSheet} from "aphrodite";
119
-
120
- const styles = StyleSheet.create({
121
- row: {
122
- flexDirection: "row",
123
- },
124
- });
125
-
126
- class DisabledExample extends React.Component {
127
- constructor() {
128
- super();
129
- this.state = {
130
- selectedValue: "banana",
131
- };
132
- // Styleguidist doesn't support arrow functions in class field properties
133
- this.handleChange = this.handleChange.bind(this);
134
- }
135
-
136
- handleChange(selected) {
137
- console.log(`${selected} was selected!`);
138
- this.setState({
139
- selectedValue: selected,
140
- });
141
- }
142
-
143
- render() {
144
- return <SingleSelect
145
- disabled={true}
146
- onChange={this.handleChange}
147
- placeholder="Choose a juice"
148
- selectedValue={this.state.selectedValue}
149
- >
150
- <OptionItem label="Banana juice" value="banana" />
151
- <OptionItem label="Guava juice" value="guava" disabled />
152
- <OptionItem label="White grape juice" value="grape" />
153
- </SingleSelect>;
154
- }
155
- }
156
-
157
- <View style={styles.row}>
158
- <DisabledExample />
159
- </View>
160
- ```
161
-
162
- ### Select on dark background, right-aligned
163
-
164
- This single select is on a dark background and is also right-aligned.
165
-
166
- ```js
167
- import {SingleSelect, OptionItem} from "@khanacademy/wonder-blocks-dropdown";
168
- import Color from "@khanacademy/wonder-blocks-color";
169
- import {View} from "@khanacademy/wonder-blocks-core";
170
- import {StyleSheet} from "aphrodite";
171
-
172
- const styles = StyleSheet.create({
173
- row: {
174
- flexDirection: "row",
175
- },
176
- darkBackgroundWrapper: {
177
- flexDirection: "row",
178
- justifyContent: "flex-end",
179
- backgroundColor: Color.darkBlue,
180
- width: 350,
181
- height: 200,
182
- paddingRight: 10,
183
- paddingTop: 10,
184
- },
185
- });
186
-
187
- class LightRightAlignedExample extends React.Component {
188
- constructor() {
189
- super();
190
- this.state = {
191
- selectedValue: null,
192
- };
193
- // Styleguidist doesn't support arrow functions in class field properties
194
- this.handleChange = this.handleChange.bind(this);
195
- }
196
-
197
- handleChange(selected) {
198
- console.log(`${selected} was selected!`);
199
- this.setState({
200
- selectedValue: selected,
201
- });
202
- }
203
-
204
- render() {
205
- return <SingleSelect
206
- alignment="right"
207
- light={true}
208
- onChange={this.handleChange}
209
- placeholder="Choose a drink"
210
- selectedValue={this.state.selectedValue}
211
- >
212
- <OptionItem label="Regular milk tea with boba" value="regular" />
213
- <OptionItem label="Wintermelon milk tea with boba" value="wintermelon" />
214
- <OptionItem label="Taro milk tea, half sugar" value="taro" />
215
- </SingleSelect>;
216
- }
217
- }
218
-
219
- <View style={styles.row}>
220
- <View style={styles.darkBackgroundWrapper}>
221
- <LightRightAlignedExample />
222
- </View>
223
- </View>
224
-
225
- ```
226
-
227
- ### Empty menus are disabled automatically
228
-
229
- ```js
230
- import {SingleSelect} from "@khanacademy/wonder-blocks-dropdown";
231
- import {View} from "@khanacademy/wonder-blocks-core";
232
- import {StyleSheet} from "aphrodite";
233
-
234
- const styles = StyleSheet.create({
235
- row: {
236
- flexDirection: "row",
237
- },
238
- });
239
-
240
- <View style={styles.row}>
241
- <SingleSelect placeholder="empty" />
242
- </View>
243
- ```
244
-
245
- ### Accessibility
246
-
247
- If you need to associate this component with another element (e.g. `<label>`),
248
- make sure to pass the `aria-labelledby` and/or `id` props to the `SingleSelect` component.
249
- This way, the `opener` will receive this value and it will associate both
250
- elements.
251
-
252
- Also, if you need screen readers to understand any relevant information on every
253
- option item, you can use `aria-label` on each item. e.g. You can use it to let
254
- screen readers know the current selected/unselected status of the item when it
255
- receives focus.
256
-
257
- ```js
258
- import {SingleSelect, OptionItem} from "@khanacademy/wonder-blocks-dropdown";
259
- import {View} from "@khanacademy/wonder-blocks-core";
260
- import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
261
-
262
- <View>
263
- <LabelLarge
264
- tag="label"
265
- id="label-for-single-select"
266
- htmlFor="unique-single-select"
267
- >
268
- Associated label element
269
- </LabelLarge>
270
- <SingleSelect
271
- aria-labelledby="label-for-single-select"
272
- id="unique-single-select"
273
- placeholder="Accessible SingleSelect"
274
- selectedValue="one"
275
- >
276
- <OptionItem label="First element" aria-label="First element, selected" value="one" />
277
- <OptionItem label="Second element" aria-label="Second element, unselelected" value="two" />
278
- </SingleSelect>
279
- </View>
280
- ```
281
-
282
- ### Example: Opening a SingleSelect programmatically
283
-
284
- Sometimes you'll want to trigger a dropdown programmatically. This can be done by
285
- setting a value to the `opened` prop (`true` or `false`). In this situation the `SingleSelect` is a
286
- controlled component. The parent is responsible for managing the opening/closing
287
- of the dropdown when using this prop.
288
-
289
- This means that you'll also have to update `opened` to the value triggered by
290
- the `onToggle` prop.
291
-
292
- ```js
293
- import {OptionItem} from "@khanacademy/wonder-blocks-dropdown";
294
- import Button from "@khanacademy/wonder-blocks-button";
295
- import {View} from "@khanacademy/wonder-blocks-core";
296
- import {Strut} from "@khanacademy/wonder-blocks-layout";
297
- import Spacing from "@khanacademy/wonder-blocks-spacing";
298
- import {StyleSheet} from "aphrodite";
299
-
300
- const styles = StyleSheet.create({
301
- row: {
302
- flexDirection: "row",
303
- }
304
- });
305
-
306
- class ControlledSingleSelectExample extends React.Component {
307
- constructor() {
308
- super();
309
- this.state = {
310
- opened: false,
311
- selectedValue: null,
312
- };
313
- this.handleChange = this.handleChange.bind(this);
314
- this.handleToggleMenu = this.handleToggleMenu.bind(this);
315
- }
316
-
317
- handleChange(selected) {
318
- this.setState({
319
- selectedValue: selected,
320
- });
321
- }
322
-
323
- handleToggleMenu(opened) {
324
- this.setState({
325
- opened,
326
- });
327
- }
328
-
329
- render() {
330
- return (
331
- <View style={styles.row}>
332
- <SingleSelect
333
- opened={this.state.opened}
334
- onToggle={this.handleToggleMenu}
335
- onChange={this.handleChange}
336
- selectedValue={this.state.selectedValue}
337
- placeholder="Choose"
338
- >
339
- <OptionItem label="item 1" value="1" />
340
- <OptionItem label="item 2" value="2" />
341
- <OptionItem label="item 3" value="3" />
342
- </SingleSelect>
343
- <Strut size={Spacing.medium_16} />
344
- <Button onClick={() => this.handleToggleMenu(true)}>
345
- Open SingleSelect programatically
346
- </Button>
347
- </View>
348
- );
349
- }
350
- }
351
-
352
- <ControlledSingleSelectExample />
353
- ```
354
-
355
- ### Example: SingleSelect with custom opener
356
-
357
- In case you need to use a custom opener with the SingleSelect, you can use the
358
- `opener` property to achieve this. In this example, the `opener` prop accepts a
359
- function with the following arguments:
360
-
361
- - `eventState`: lets you customize the style for different states, such as
362
- `pressed`, `hovered` and `focused`.
363
- - `text`: Passes the menu label defined in the parent component. By default,
364
- `text` will be initialized with the value of the `placeholder` prop set in the
365
- `SingleSelect` component.
366
-
367
- **Note:** If you need to use a custom ID for testing the opener, make sure to
368
- pass the `testId` prop inside the opener component/element.
369
-
370
- ```js
371
- import {SingleSelect, OptionItem} from "@khanacademy/wonder-blocks-dropdown";
372
- import Color from "@khanacademy/wonder-blocks-color";
373
- import {View} from "@khanacademy/wonder-blocks-core";
374
- import {HeadingLarge} from "@khanacademy/wonder-blocks-typography";
375
- import {StyleSheet} from "aphrodite";
376
-
377
- const styles = StyleSheet.create({
378
- focused: {
379
- color: Color.purple,
380
- },
381
- hovered: {
382
- textDecoration: "underline",
383
- color: Color.purple,
384
- cursor: "pointer",
385
- },
386
- pressed: {
387
- color: Color.blue,
388
- },
389
- });
390
-
391
- class SingleSelectWithCustomOpener extends React.Component {
392
- constructor() {
393
- super();
394
- this.state = {
395
- opened: false,
396
- selectedValue: null,
397
- };
398
- this.handleChange = this.handleChange.bind(this);
399
- this.handleToggleMenu = this.handleToggleMenu.bind(this);
400
- }
401
-
402
- handleChange(selected) {
403
- this.setState({
404
- selectedValue: selected,
405
- });
406
- }
407
-
408
- handleToggleMenu(opened) {
409
- this.setState({
410
- opened,
411
- });
412
- }
413
-
414
- render() {
415
- return (
416
- <SingleSelect
417
- placeholder="Choose a juice"
418
- opened={this.state.opened}
419
- onChange={this.handleChange}
420
- onToggle={this.handleToggleMenu}
421
- selectedValue={this.state.selectedValue}
422
- opener={({focused, hovered, pressed, text}) => (
423
- <HeadingLarge
424
- onClick={()=>{console.log('custom click!!!!!')}}
425
- testId="single-select-custom-opener"
426
- style={[
427
- focused && styles.focused,
428
- hovered && styles.hovered,
429
- pressed && styles.pressed
430
- ]}
431
- >
432
- {text}
433
- </HeadingLarge>
434
- )}
435
-
436
- >
437
- <OptionItem label="Banana juice" value="banana" />
438
- <OptionItem label="Guava juice" value="guava" disabled />
439
- <OptionItem label="White grape juice" value="grape" />
440
- </SingleSelect>
441
- );
442
- }
443
- }
444
-
445
- <SingleSelectWithCustomOpener />
446
- ```
447
-
448
- ### Single select with search filter and custom styles
449
-
450
- When there are many options, you could use a search filter in the SingleSelect.
451
- The search filter will be performed toward the labels of the option items. Note
452
- that this example shows how we can add custom styles to the dropdown as well.
453
-
454
- ```js
455
- import {SingleSelect, OptionItem} from "@khanacademy/wonder-blocks-dropdown";
456
- import {View} from "@khanacademy/wonder-blocks-core";
457
- import {StyleSheet} from "aphrodite";
458
-
459
- const styles = StyleSheet.create({
460
- row: {
461
- flexDirection: "row",
462
- },
463
- fullBleed: {
464
- width: "100%",
465
- },
466
- });
467
-
468
- const fruits = ["banana", "strawberry", "pear", "orange"];
469
-
470
- const optionItems = new Array(1000).fill(null).map((_, i) => (<OptionItem
471
- key={i}
472
- value={(i + 1).toString()}
473
- label={`Fruit # ${i + 1} ${fruits[i%fruits.length]}`}
474
- />));
475
-
476
- class ExampleWithFilter extends React.Component {
477
- constructor() {
478
- super();
479
- this.state = {
480
- opened: false,
481
- selectedValue: null,
482
- };
483
- this.handleChange = this.handleChange.bind(this);
484
- this.handleToggleMenu = this.handleToggleMenu.bind(this);
485
- }
486
-
487
- handleChange(selected) {
488
- this.setState({
489
- selectedValue: selected,
490
- });
491
- }
492
-
493
- handleToggleMenu(opened) {
494
- this.setState({
495
- opened,
496
- });
497
- }
498
-
499
- render() {
500
- return (
501
- <SingleSelect
502
- opened={this.state.opened}
503
- onToggle={this.handleToggleMenu}
504
- onChange={this.handleChange}
505
- isFilterable={true}
506
- placeholder="Select a fruit"
507
- selectedValue={this.state.selectedValue}
508
- dropdownStyle={styles.fullBleed}
509
- style={styles.fullBleed}
510
- >
511
- {optionItems}
512
- </SingleSelect>
513
- );
514
- }
515
- }
516
-
517
- <View style={styles.row}>
518
- <ExampleWithFilter />
519
- </View>
520
- ```