@khanacademy/wonder-blocks-dropdown 5.3.8 → 5.4.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 +38 -0
- package/dist/components/action-menu.d.ts +15 -2
- package/dist/components/dropdown-core.d.ts +4 -0
- package/dist/components/dropdown-opener.d.ts +4 -0
- package/dist/components/multi-select.d.ts +9 -2
- package/dist/components/option-item.d.ts +1 -1
- package/dist/components/single-select.d.ts +9 -2
- package/dist/es/index.js +114 -61
- package/dist/hooks/use-listbox.d.ts +2 -2
- package/dist/index.js +113 -60
- package/package.json +6 -6
- package/src/components/__tests__/action-menu.test.tsx +630 -23
- package/src/components/__tests__/multi-select.test.tsx +293 -0
- package/src/components/__tests__/single-select.test.tsx +306 -0
- package/src/components/action-menu.tsx +85 -48
- package/src/components/dropdown-core.tsx +9 -2
- package/src/components/dropdown-opener.tsx +17 -1
- package/src/components/multi-select.tsx +94 -61
- package/src/components/option-item.tsx +1 -1
- package/src/components/select-opener.tsx +2 -2
- package/src/components/single-select.tsx +87 -57
- package/tsconfig-build.tsbuildinfo +1 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as ReactDOM from "react-dom";
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
IDProvider,
|
|
6
|
+
type AriaProps,
|
|
7
|
+
type StyleType,
|
|
8
|
+
} from "@khanacademy/wonder-blocks-core";
|
|
5
9
|
|
|
6
10
|
import DropdownCore from "./dropdown-core";
|
|
7
11
|
import DropdownOpener from "./dropdown-opener";
|
|
@@ -150,6 +154,13 @@ type Props = AriaProps &
|
|
|
150
154
|
* top. The items will be filtered by the input.
|
|
151
155
|
*/
|
|
152
156
|
isFilterable?: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Unique identifier attached to the listbox dropdown. If used, we need to
|
|
159
|
+
* guarantee that the ID is unique within everything rendered on a page.
|
|
160
|
+
* If one is not provided, one is auto-generated. It is used for the
|
|
161
|
+
* opener's `aria-controls` attribute for screenreaders.
|
|
162
|
+
*/
|
|
163
|
+
dropdownId?: string;
|
|
153
164
|
}>;
|
|
154
165
|
|
|
155
166
|
type State = Readonly<{
|
|
@@ -366,6 +377,7 @@ export default class SingleSelect extends React.Component<Props, State> {
|
|
|
366
377
|
|
|
367
378
|
renderOpener(
|
|
368
379
|
isDisabled: boolean,
|
|
380
|
+
dropdownId: string,
|
|
369
381
|
):
|
|
370
382
|
| React.ReactElement<React.ComponentProps<typeof DropdownOpener>>
|
|
371
383
|
| React.ReactElement<React.ComponentProps<typeof SelectOpener>> {
|
|
@@ -409,32 +421,43 @@ export default class SingleSelect extends React.Component<Props, State> {
|
|
|
409
421
|
? getLabel(selectedItem.props)
|
|
410
422
|
: placeholder;
|
|
411
423
|
|
|
412
|
-
const dropdownOpener =
|
|
413
|
-
<
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
424
|
+
const dropdownOpener = (
|
|
425
|
+
<IDProvider id={id} scope="single-select-opener">
|
|
426
|
+
{(uniqueOpenerId) => {
|
|
427
|
+
return opener ? (
|
|
428
|
+
<DropdownOpener
|
|
429
|
+
id={uniqueOpenerId}
|
|
430
|
+
aria-controls={dropdownId}
|
|
431
|
+
aria-haspopup="listbox"
|
|
432
|
+
onClick={this.handleClick}
|
|
433
|
+
disabled={isDisabled}
|
|
434
|
+
ref={this.handleOpenerRef}
|
|
435
|
+
text={menuText}
|
|
436
|
+
opened={this.state.open}
|
|
437
|
+
>
|
|
438
|
+
{opener}
|
|
439
|
+
</DropdownOpener>
|
|
440
|
+
) : (
|
|
441
|
+
<SelectOpener
|
|
442
|
+
{...sharedProps}
|
|
443
|
+
aria-controls={dropdownId}
|
|
444
|
+
disabled={isDisabled}
|
|
445
|
+
id={uniqueOpenerId}
|
|
446
|
+
error={error}
|
|
447
|
+
isPlaceholder={!selectedItem}
|
|
448
|
+
light={light}
|
|
449
|
+
onOpenChanged={this.handleOpenChanged}
|
|
450
|
+
open={this.state.open}
|
|
451
|
+
ref={this.handleOpenerRef}
|
|
452
|
+
testId={testId}
|
|
453
|
+
>
|
|
454
|
+
{menuText}
|
|
455
|
+
</SelectOpener>
|
|
456
|
+
);
|
|
457
|
+
}}
|
|
458
|
+
</IDProvider>
|
|
437
459
|
);
|
|
460
|
+
|
|
438
461
|
return dropdownOpener;
|
|
439
462
|
}
|
|
440
463
|
|
|
@@ -453,6 +476,7 @@ export default class SingleSelect extends React.Component<Props, State> {
|
|
|
453
476
|
"aria-invalid": ariaInvalid,
|
|
454
477
|
"aria-required": ariaRequired,
|
|
455
478
|
disabled,
|
|
479
|
+
dropdownId,
|
|
456
480
|
} = this.props;
|
|
457
481
|
const {searchText} = this.state;
|
|
458
482
|
const allChildren = (
|
|
@@ -465,39 +489,45 @@ export default class SingleSelect extends React.Component<Props, State> {
|
|
|
465
489
|
).length;
|
|
466
490
|
const items = this.getMenuItems(allChildren);
|
|
467
491
|
const isDisabled = numEnabledOptions === 0 || disabled;
|
|
468
|
-
const opener = this.renderOpener(isDisabled);
|
|
469
492
|
|
|
470
493
|
return (
|
|
471
|
-
<
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
494
|
+
<IDProvider id={dropdownId} scope="single-select-dropdown">
|
|
495
|
+
{(uniqueDropdownId) => (
|
|
496
|
+
<DropdownCore
|
|
497
|
+
id={uniqueDropdownId}
|
|
498
|
+
role="listbox"
|
|
499
|
+
selectionType="single"
|
|
500
|
+
alignment={alignment}
|
|
501
|
+
autoFocus={autoFocus}
|
|
502
|
+
enableTypeAhead={enableTypeAhead}
|
|
503
|
+
dropdownStyle={[
|
|
504
|
+
isFilterable && filterableDropdownStyle,
|
|
505
|
+
selectDropdownStyle,
|
|
506
|
+
dropdownStyle,
|
|
507
|
+
]}
|
|
508
|
+
initialFocusedIndex={this.selectedIndex}
|
|
509
|
+
items={items}
|
|
510
|
+
light={light}
|
|
511
|
+
onOpenChanged={this.handleOpenChanged}
|
|
512
|
+
open={this.state.open}
|
|
513
|
+
opener={this.renderOpener(isDisabled, uniqueDropdownId)}
|
|
514
|
+
openerElement={this.state.openerElement}
|
|
515
|
+
style={style}
|
|
516
|
+
className={className}
|
|
517
|
+
isFilterable={isFilterable}
|
|
518
|
+
onSearchTextChanged={
|
|
519
|
+
isFilterable
|
|
520
|
+
? this.handleSearchTextChanged
|
|
521
|
+
: undefined
|
|
522
|
+
}
|
|
523
|
+
searchText={isFilterable ? searchText : ""}
|
|
524
|
+
labels={labels}
|
|
525
|
+
aria-invalid={ariaInvalid}
|
|
526
|
+
aria-required={ariaRequired}
|
|
527
|
+
disabled={isDisabled}
|
|
528
|
+
/>
|
|
529
|
+
)}
|
|
530
|
+
</IDProvider>
|
|
501
531
|
);
|
|
502
532
|
}
|
|
503
533
|
}
|