@patternfly/react-core 5.0.0-alpha.29 → 5.0.0-alpha.30
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 +4 -0
- package/package.json +2 -2
- package/src/components/Select/examples/Select.md +1366 -1390
|
@@ -10,7 +10,15 @@ import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
|
|
|
10
10
|
|
|
11
11
|
## Examples
|
|
12
12
|
|
|
13
|
-
### Single
|
|
13
|
+
### Single select
|
|
14
|
+
|
|
15
|
+
To let users select a single item from a list, use a single select list.
|
|
16
|
+
|
|
17
|
+
A select list may use other properties for additional customization. Select each checkbox in the example below to visualize the following behavior:
|
|
18
|
+
|
|
19
|
+
- To prevent a toggle click from opening a select list, use the `isDisabled` property.
|
|
20
|
+
- To adjust the direction a select menu opens, use the `direction` property. The menu in the following example expands upwards. By default, select lists open upwards.
|
|
21
|
+
- To add an icon to a select toggle, use the `toggleIcon` property.
|
|
14
22
|
|
|
15
23
|
```js
|
|
16
24
|
import React from 'react';
|
|
@@ -144,7 +152,9 @@ class SingleSelectInput extends React.Component {
|
|
|
144
152
|
}
|
|
145
153
|
```
|
|
146
154
|
|
|
147
|
-
###
|
|
155
|
+
### With item descriptions
|
|
156
|
+
|
|
157
|
+
To give more context to a `<SelectOption>` in a list, use the `description` property.
|
|
148
158
|
|
|
149
159
|
```js
|
|
150
160
|
import React from 'react';
|
|
@@ -232,7 +242,9 @@ class SingleSelectDescription extends React.Component {
|
|
|
232
242
|
}
|
|
233
243
|
```
|
|
234
244
|
|
|
235
|
-
###
|
|
245
|
+
### With grouped items
|
|
246
|
+
|
|
247
|
+
To group related select options together, use 1 or more `<SelectGroup>` components and title each group using the `label` property.
|
|
236
248
|
|
|
237
249
|
```js
|
|
238
250
|
import React from 'react';
|
|
@@ -312,7 +324,104 @@ class GroupedSingleSelectInput extends React.Component {
|
|
|
312
324
|
}
|
|
313
325
|
```
|
|
314
326
|
|
|
315
|
-
###
|
|
327
|
+
### Favoriting items
|
|
328
|
+
|
|
329
|
+
To allow users to favorite items in a select list, use the `onFavorite` callback. When users click the favorite button, the item is duplicated and placed in a separated group at the top of the menu. To change the name of the group use the `favoritesLabel` property.
|
|
330
|
+
|
|
331
|
+
```js
|
|
332
|
+
import React from 'react';
|
|
333
|
+
import { Select, SelectOption, SelectVariant, SelectGroup } from '@patternfly/react-core';
|
|
334
|
+
|
|
335
|
+
class FavoritesSelect extends React.Component {
|
|
336
|
+
constructor(props) {
|
|
337
|
+
super(props);
|
|
338
|
+
this.state = {
|
|
339
|
+
isOpen: false,
|
|
340
|
+
selected: null,
|
|
341
|
+
favorites: []
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
this.onToggle = (_event, isOpen) => {
|
|
345
|
+
this.setState({
|
|
346
|
+
isOpen
|
|
347
|
+
});
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
this.onSelect = (event, selection, isPlaceholder) => {
|
|
351
|
+
if (isPlaceholder) this.clearSelection();
|
|
352
|
+
else {
|
|
353
|
+
this.setState({
|
|
354
|
+
selected: selection,
|
|
355
|
+
isOpen: false
|
|
356
|
+
});
|
|
357
|
+
console.log('selected:', selection);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
this.clearSelection = () => {
|
|
362
|
+
this.setState({
|
|
363
|
+
selected: null,
|
|
364
|
+
isOpen: false
|
|
365
|
+
});
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
this.onFavorite = (itemId, isFavorite) => {
|
|
369
|
+
if (isFavorite) {
|
|
370
|
+
this.setState({
|
|
371
|
+
favorites: this.state.favorites.filter(id => id !== itemId)
|
|
372
|
+
});
|
|
373
|
+
} else
|
|
374
|
+
this.setState({
|
|
375
|
+
favorites: [...this.state.favorites, itemId]
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
this.options = [
|
|
380
|
+
<SelectGroup label="Status" key="group1">
|
|
381
|
+
<SelectOption id={'option-1'} key={0} value="Running" description="This is a description." />
|
|
382
|
+
<SelectOption id={'option-2'} key={1} value="Stopped" />
|
|
383
|
+
<SelectOption id={'option-3'} key={2} value="Down (disabled)" isDisabled />
|
|
384
|
+
<SelectOption id={'option-4'} key={3} value="Degraded" />
|
|
385
|
+
<SelectOption id={'option-5'} key={4} value="Needs maintenance" />
|
|
386
|
+
</SelectGroup>,
|
|
387
|
+
<SelectGroup label="Vendor names" key="group2">
|
|
388
|
+
<SelectOption id={'option-6'} key={5} value="Dell" />
|
|
389
|
+
<SelectOption id={'option-7'} key={6} value="Samsung" description="This is a description." />
|
|
390
|
+
<SelectOption id={'option-8'} key={7} value="Hewlett-Packard" />
|
|
391
|
+
</SelectGroup>
|
|
392
|
+
];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
render() {
|
|
396
|
+
const { isOpen, selected, favorites } = this.state;
|
|
397
|
+
const titleId = 'grouped-single-select-id';
|
|
398
|
+
return (
|
|
399
|
+
<Select
|
|
400
|
+
variant={SelectVariant.typeahead}
|
|
401
|
+
typeAheadAriaLabel="Select value"
|
|
402
|
+
onToggle={this.onToggle}
|
|
403
|
+
onSelect={this.onSelect}
|
|
404
|
+
selections={selected}
|
|
405
|
+
isOpen={isOpen}
|
|
406
|
+
placeholderText="Favorites"
|
|
407
|
+
aria-labelledby={titleId}
|
|
408
|
+
isGrouped
|
|
409
|
+
onFavorite={this.onFavorite}
|
|
410
|
+
favorites={favorites}
|
|
411
|
+
onClear={this.clearSelection}
|
|
412
|
+
>
|
|
413
|
+
{this.options}
|
|
414
|
+
</Select>
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Validated selections
|
|
421
|
+
|
|
422
|
+
To validate selections that users make, pass a validation state to the `validated` property. Validating selections can let users know if the selections they make would cause issues or errors.
|
|
423
|
+
|
|
424
|
+
The example below passes an "error" state when you choose “select a title”, a "warning" state when you choose "other", and a "success" state for any other item selected from the menu.
|
|
316
425
|
|
|
317
426
|
```js
|
|
318
427
|
import React from 'react';
|
|
@@ -411,19 +520,152 @@ class ValidatedSelect extends React.Component {
|
|
|
411
520
|
}
|
|
412
521
|
```
|
|
413
522
|
|
|
414
|
-
###
|
|
523
|
+
### Styled placeholder text
|
|
524
|
+
|
|
525
|
+
To add a toggle label to a select, use the `placeholderText` property. The following example displays "Filter by status" in the toggle before a selection is made.
|
|
526
|
+
|
|
527
|
+
To fade the color of `placeholderText` to gray, use the `hasPlaceholderStyle` property.
|
|
415
528
|
|
|
416
529
|
```js
|
|
417
530
|
import React from 'react';
|
|
418
|
-
import { Select, SelectOption, SelectVariant
|
|
531
|
+
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
419
532
|
|
|
420
|
-
|
|
533
|
+
function SelectWithPlaceholderStyle() {
|
|
534
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
535
|
+
const [selected, setSelected] = React.useState([]);
|
|
536
|
+
|
|
537
|
+
const options = [
|
|
538
|
+
<SelectOption key={0} value="Active" />,
|
|
539
|
+
<SelectOption key={1} value="Cancelled" />,
|
|
540
|
+
<SelectOption key={2} value="Paused" />
|
|
541
|
+
];
|
|
542
|
+
|
|
543
|
+
const onToggle = (_event, isOpen) => setIsOpen(isOpen);
|
|
544
|
+
|
|
545
|
+
const onSelect = (event, selection, isPlaceholder) => {
|
|
546
|
+
setSelected(selection);
|
|
547
|
+
setIsOpen(false);
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
const clearSelection = () => {
|
|
551
|
+
setSelected(null);
|
|
552
|
+
setIsOpen(false);
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
const titleId = 'placeholder-style-select-id';
|
|
556
|
+
|
|
557
|
+
return (
|
|
558
|
+
<div>
|
|
559
|
+
<span id={titleId} hidden>
|
|
560
|
+
Placeholder styles
|
|
561
|
+
</span>
|
|
562
|
+
<Select
|
|
563
|
+
variant={SelectVariant.single}
|
|
564
|
+
hasPlaceholderStyle
|
|
565
|
+
aria-label="Select input"
|
|
566
|
+
onToggle={onToggle}
|
|
567
|
+
onSelect={onSelect}
|
|
568
|
+
onClear={clearSelection}
|
|
569
|
+
selections={selected}
|
|
570
|
+
isOpen={isOpen}
|
|
571
|
+
placeholderText="Filter by status"
|
|
572
|
+
aria-labelledby={titleId}
|
|
573
|
+
>
|
|
574
|
+
{options}
|
|
575
|
+
</Select>
|
|
576
|
+
</div>
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### Placeholder select options
|
|
582
|
+
|
|
583
|
+
To set a `<SelectOption>` as a placeholder, use the `isPlaceholder` property. The following example sets the "Filter by status" as a placeholder so that it is pre-selected.
|
|
584
|
+
|
|
585
|
+
```js
|
|
586
|
+
|
|
587
|
+
import React from 'react';
|
|
588
|
+
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
589
|
+
|
|
590
|
+
function SelectWithPlaceholderStyle() {
|
|
591
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
592
|
+
const [selected, setSelected] = React.useState([]);
|
|
593
|
+
|
|
594
|
+
const options = [
|
|
595
|
+
<SelectOption key={0} value="Filter by status" isPlaceholder />,
|
|
596
|
+
<SelectOption key={1} value="Active" />,
|
|
597
|
+
<SelectOption key={2} value="Cancelled" />,
|
|
598
|
+
<SelectOption key={3} value="Paused" />
|
|
599
|
+
];
|
|
600
|
+
|
|
601
|
+
const onToggle = (_event, isOpen) => setIsOpen(isOpen);
|
|
602
|
+
|
|
603
|
+
const onSelect = (event, selection, isPlaceholder) => {
|
|
604
|
+
setSelected(selection);
|
|
605
|
+
setIsOpen(false);
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
const clearSelection = () => {
|
|
609
|
+
setSelected(null);
|
|
610
|
+
setIsOpen(false);
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
const titleId = 'placeholder-style-select-option-id';
|
|
614
|
+
|
|
615
|
+
return (
|
|
616
|
+
<div>
|
|
617
|
+
<span id={titleId} hidden>
|
|
618
|
+
Placeholder styles - select option
|
|
619
|
+
</span>
|
|
620
|
+
<Select
|
|
621
|
+
variant={SelectVariant.single}
|
|
622
|
+
hasPlaceholderStyle
|
|
623
|
+
aria-label="Select input"
|
|
624
|
+
onToggle={onToggle}
|
|
625
|
+
onSelect={onSelect}
|
|
626
|
+
onClear={clearSelection}
|
|
627
|
+
selections={selected}
|
|
628
|
+
isOpen={isOpen}
|
|
629
|
+
aria-labelledby={titleId}
|
|
630
|
+
>
|
|
631
|
+
{options}
|
|
632
|
+
</Select>
|
|
633
|
+
</div>
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### With a footer
|
|
639
|
+
|
|
640
|
+
You can add a `footer` to a `<Select>` list to hold actions that users can take on menu items.
|
|
641
|
+
|
|
642
|
+
```js
|
|
643
|
+
import React from 'react';
|
|
644
|
+
import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
|
|
645
|
+
import { Select, SelectOption, SelectVariant, SelectDirection, Divider, Button } from '@patternfly/react-core';
|
|
646
|
+
|
|
647
|
+
class SelectWithFooter extends React.Component {
|
|
421
648
|
constructor(props) {
|
|
422
649
|
super(props);
|
|
650
|
+
this.options = [
|
|
651
|
+
<SelectOption key={0} value="Select a title" isPlaceholder />,
|
|
652
|
+
<SelectOption key={1} value="Mr" />,
|
|
653
|
+
<SelectOption key={2} value="Miss" />,
|
|
654
|
+
<SelectOption key={3} value="Mrs" />,
|
|
655
|
+
<SelectOption key={4} value="Ms" />,
|
|
656
|
+
<Divider component="li" key={5} />,
|
|
657
|
+
<SelectOption key={6} value="Dr" />,
|
|
658
|
+
<SelectOption key={7} value="Other" />
|
|
659
|
+
];
|
|
660
|
+
|
|
661
|
+
this.toggleRef = React.createRef();
|
|
423
662
|
|
|
424
663
|
this.state = {
|
|
664
|
+
isToggleIcon: false,
|
|
425
665
|
isOpen: false,
|
|
426
|
-
selected:
|
|
666
|
+
selected: null,
|
|
667
|
+
isDisabled: false,
|
|
668
|
+
direction: SelectDirection.down
|
|
427
669
|
};
|
|
428
670
|
|
|
429
671
|
this.onToggle = (_event, isOpen) => {
|
|
@@ -432,54 +674,53 @@ class CheckboxSelectInput extends React.Component {
|
|
|
432
674
|
});
|
|
433
675
|
};
|
|
434
676
|
|
|
435
|
-
this.onSelect = (event, selection) => {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
this.setState(
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
);
|
|
442
|
-
|
|
443
|
-
this.
|
|
444
|
-
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
445
|
-
() => console.log('selections: ', this.state.selected)
|
|
446
|
-
);
|
|
677
|
+
this.onSelect = (event, selection, isPlaceholder) => {
|
|
678
|
+
if (isPlaceholder) this.clearSelection();
|
|
679
|
+
else {
|
|
680
|
+
this.setState({
|
|
681
|
+
selected: selection,
|
|
682
|
+
isOpen: false
|
|
683
|
+
});
|
|
684
|
+
console.log('selected:', selection);
|
|
685
|
+
this.toggleRef.current.focus();
|
|
447
686
|
}
|
|
448
687
|
};
|
|
449
688
|
|
|
450
689
|
this.clearSelection = () => {
|
|
451
690
|
this.setState({
|
|
452
|
-
selected:
|
|
691
|
+
selected: null,
|
|
692
|
+
isOpen: false
|
|
453
693
|
});
|
|
454
694
|
};
|
|
455
|
-
|
|
456
|
-
this.options = [
|
|
457
|
-
<SelectOption key={0} value="Active" description="This is a description" />,
|
|
458
|
-
<SelectOption key={1} value="Cancelled" />,
|
|
459
|
-
<SelectOption key={2} value="Paused" />,
|
|
460
|
-
<Divider key={3} />,
|
|
461
|
-
<SelectOption key={4} value="Warning" />,
|
|
462
|
-
<SelectOption key={5} value="Restarted" />
|
|
463
|
-
];
|
|
464
|
-
}
|
|
695
|
+
}
|
|
465
696
|
|
|
466
697
|
render() {
|
|
467
|
-
const { isOpen, selected } = this.state;
|
|
468
|
-
const titleId = '
|
|
698
|
+
const { isOpen, selected, isDisabled, direction, isToggleIcon } = this.state;
|
|
699
|
+
const titleId = 'title-id-footer';
|
|
469
700
|
return (
|
|
470
701
|
<div>
|
|
471
702
|
<span id={titleId} hidden>
|
|
472
|
-
|
|
703
|
+
Title
|
|
473
704
|
</span>
|
|
474
705
|
<Select
|
|
475
|
-
|
|
706
|
+
toggleIcon={isToggleIcon && <CubeIcon />}
|
|
707
|
+
toggleRef={this.toggleRef}
|
|
708
|
+
variant={SelectVariant.single}
|
|
476
709
|
aria-label="Select Input"
|
|
477
710
|
onToggle={this.onToggle}
|
|
478
711
|
onSelect={this.onSelect}
|
|
479
712
|
selections={selected}
|
|
480
713
|
isOpen={isOpen}
|
|
481
|
-
placeholderText="Filter by status"
|
|
482
714
|
aria-labelledby={titleId}
|
|
715
|
+
isDisabled={isDisabled}
|
|
716
|
+
direction={direction}
|
|
717
|
+
footer={
|
|
718
|
+
<>
|
|
719
|
+
<Button variant="link" isInline>
|
|
720
|
+
Action
|
|
721
|
+
</Button>
|
|
722
|
+
</>
|
|
723
|
+
}
|
|
483
724
|
>
|
|
484
725
|
{this.options}
|
|
485
726
|
</Select>
|
|
@@ -489,19 +730,36 @@ class CheckboxSelectInput extends React.Component {
|
|
|
489
730
|
}
|
|
490
731
|
```
|
|
491
732
|
|
|
492
|
-
###
|
|
733
|
+
### With view more
|
|
734
|
+
|
|
735
|
+
To reduce the processing load for long select lists, replace overflow items with a "View more" link at the bottom of the select menu.
|
|
736
|
+
|
|
737
|
+
Adjust the number of items shown above the "View more" link with the `numOptions` property. The following example passes 3 items into this property.
|
|
493
738
|
|
|
494
739
|
```js
|
|
495
740
|
import React from 'react';
|
|
496
|
-
import { Select, SelectOption, SelectVariant
|
|
741
|
+
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
497
742
|
|
|
498
|
-
class
|
|
743
|
+
class SelectViewMore extends React.Component {
|
|
499
744
|
constructor(props) {
|
|
500
745
|
super(props);
|
|
746
|
+
this.options = [
|
|
747
|
+
<SelectOption key={0} value="Select a title" isPlaceholder />,
|
|
748
|
+
<SelectOption key={1} value="Mr" />,
|
|
749
|
+
<SelectOption key={2} value="Miss" />,
|
|
750
|
+
<SelectOption key={3} value="Mrs" />,
|
|
751
|
+
<SelectOption key={4} value="Ms" />,
|
|
752
|
+
<SelectOption key={5} value="Dr" />,
|
|
753
|
+
<SelectOption key={6} value="Other" />
|
|
754
|
+
];
|
|
755
|
+
|
|
756
|
+
this.toggleRef = React.createRef();
|
|
501
757
|
|
|
502
758
|
this.state = {
|
|
503
759
|
isOpen: false,
|
|
504
|
-
selected:
|
|
760
|
+
selected: null,
|
|
761
|
+
numOptions: 3,
|
|
762
|
+
isLoading: false
|
|
505
763
|
};
|
|
506
764
|
|
|
507
765
|
this.onToggle = (_event, isOpen) => {
|
|
@@ -510,55 +768,64 @@ class CheckboxSelectWithCounts extends React.Component {
|
|
|
510
768
|
});
|
|
511
769
|
};
|
|
512
770
|
|
|
513
|
-
this.onSelect = (event, selection) => {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
this.setState(
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
);
|
|
520
|
-
|
|
521
|
-
this.
|
|
522
|
-
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
523
|
-
() => console.log('selections: ', this.state.selected)
|
|
524
|
-
);
|
|
771
|
+
this.onSelect = (event, selection, isPlaceholder) => {
|
|
772
|
+
if (isPlaceholder) this.clearSelection();
|
|
773
|
+
else {
|
|
774
|
+
this.setState({
|
|
775
|
+
selected: selection,
|
|
776
|
+
isOpen: false
|
|
777
|
+
});
|
|
778
|
+
console.log('selected:', selection);
|
|
779
|
+
this.toggleRef.current.focus();
|
|
525
780
|
}
|
|
526
781
|
};
|
|
527
782
|
|
|
528
783
|
this.clearSelection = () => {
|
|
529
784
|
this.setState({
|
|
530
|
-
selected:
|
|
785
|
+
selected: null,
|
|
786
|
+
isOpen: false
|
|
531
787
|
});
|
|
532
788
|
};
|
|
533
789
|
|
|
534
|
-
this.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
790
|
+
this.simulateNetworkCall = callback => {
|
|
791
|
+
setTimeout(callback, 2000);
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
this.onViewMoreClick = () => {
|
|
795
|
+
// Set select loadingVariant to spinner then simulate network call before loading more options
|
|
796
|
+
this.setState({ isLoading: true });
|
|
797
|
+
this.simulateNetworkCall(() => {
|
|
798
|
+
const newLength =
|
|
799
|
+
this.state.numOptions + 3 <= this.options.length ? this.state.numOptions + 3 : this.options.length;
|
|
800
|
+
this.setState({ numOptions: newLength, isLoading: false });
|
|
801
|
+
});
|
|
802
|
+
};
|
|
541
803
|
}
|
|
542
804
|
|
|
543
805
|
render() {
|
|
544
|
-
const { isOpen, selected } = this.state;
|
|
545
|
-
const titleId = '
|
|
806
|
+
const { isOpen, selected, isToggleIcon, numOptions, loadingVariant, isLoading } = this.state;
|
|
807
|
+
const titleId = 'title-id-view-more';
|
|
546
808
|
return (
|
|
547
809
|
<div>
|
|
548
810
|
<span id={titleId} hidden>
|
|
549
|
-
|
|
811
|
+
Title
|
|
550
812
|
</span>
|
|
551
813
|
<Select
|
|
552
|
-
variant={SelectVariant.
|
|
814
|
+
variant={SelectVariant.single}
|
|
815
|
+
toggleRef={this.toggleRef}
|
|
553
816
|
aria-label="Select Input"
|
|
554
817
|
onToggle={this.onToggle}
|
|
555
818
|
onSelect={this.onSelect}
|
|
556
819
|
selections={selected}
|
|
557
820
|
isOpen={isOpen}
|
|
558
|
-
placeholderText="Filter by status"
|
|
559
821
|
aria-labelledby={titleId}
|
|
822
|
+
{...(!isLoading &&
|
|
823
|
+
numOptions < this.options.length && {
|
|
824
|
+
loadingVariant: { text: 'View more', onClick: this.onViewMoreClick }
|
|
825
|
+
})}
|
|
826
|
+
{...(isLoading && { loadingVariant: 'spinner' })}
|
|
560
827
|
>
|
|
561
|
-
{this.options}
|
|
828
|
+
{this.options.slice(0, numOptions)}
|
|
562
829
|
</Select>
|
|
563
830
|
</div>
|
|
564
831
|
);
|
|
@@ -566,13 +833,17 @@ class CheckboxSelectWithCounts extends React.Component {
|
|
|
566
833
|
}
|
|
567
834
|
```
|
|
568
835
|
|
|
569
|
-
### Checkbox
|
|
836
|
+
### Checkbox select
|
|
837
|
+
|
|
838
|
+
To let users select multiple list options via checkbox input, use a checkbox select. To create a checkbox select, pass `variant={SelectVariant.checkbox}` into the `<Select>` component.
|
|
839
|
+
|
|
840
|
+
By default, a badge is displayed in the menu toggle that indicates the number of items a user has selected.
|
|
570
841
|
|
|
571
842
|
```js
|
|
572
843
|
import React from 'react';
|
|
573
|
-
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
844
|
+
import { Select, SelectOption, SelectVariant, Divider } from '@patternfly/react-core';
|
|
574
845
|
|
|
575
|
-
class
|
|
846
|
+
class CheckboxSelectInput extends React.Component {
|
|
576
847
|
constructor(props) {
|
|
577
848
|
super(props);
|
|
578
849
|
|
|
@@ -609,16 +880,18 @@ class CheckboxSelectInputNoBadge extends React.Component {
|
|
|
609
880
|
};
|
|
610
881
|
|
|
611
882
|
this.options = [
|
|
612
|
-
<SelectOption key={0} value="
|
|
613
|
-
<SelectOption key={1} value="
|
|
614
|
-
<SelectOption key={2} value="
|
|
615
|
-
<
|
|
883
|
+
<SelectOption key={0} value="Active" description="This is a description" />,
|
|
884
|
+
<SelectOption key={1} value="Cancelled" />,
|
|
885
|
+
<SelectOption key={2} value="Paused" />,
|
|
886
|
+
<Divider key={3} />,
|
|
887
|
+
<SelectOption key={4} value="Warning" />,
|
|
888
|
+
<SelectOption key={5} value="Restarted" />
|
|
616
889
|
];
|
|
617
890
|
}
|
|
618
891
|
|
|
619
892
|
render() {
|
|
620
893
|
const { isOpen, selected } = this.state;
|
|
621
|
-
const titleId = 'checkbox-
|
|
894
|
+
const titleId = 'checkbox-select-id';
|
|
622
895
|
return (
|
|
623
896
|
<div>
|
|
624
897
|
<span id={titleId} hidden>
|
|
@@ -630,7 +903,6 @@ class CheckboxSelectInputNoBadge extends React.Component {
|
|
|
630
903
|
onToggle={this.onToggle}
|
|
631
904
|
onSelect={this.onSelect}
|
|
632
905
|
selections={selected}
|
|
633
|
-
isCheckboxSelectionBadgeHidden
|
|
634
906
|
isOpen={isOpen}
|
|
635
907
|
placeholderText="Filter by status"
|
|
636
908
|
aria-labelledby={titleId}
|
|
@@ -643,7 +915,9 @@ class CheckboxSelectInputNoBadge extends React.Component {
|
|
|
643
915
|
}
|
|
644
916
|
```
|
|
645
917
|
|
|
646
|
-
###
|
|
918
|
+
### Checkbox select with grouped items
|
|
919
|
+
|
|
920
|
+
You can use groups alongside checkbox input. The item count badge will display the number of items selected across all groups.
|
|
647
921
|
|
|
648
922
|
```js
|
|
649
923
|
import React from 'react';
|
|
@@ -726,26 +1000,24 @@ class GroupedCheckboxSelectInput extends React.Component {
|
|
|
726
1000
|
}
|
|
727
1001
|
```
|
|
728
1002
|
|
|
729
|
-
###
|
|
1003
|
+
### Checkbox select with custom badge
|
|
1004
|
+
|
|
1005
|
+
To change the default badge text for a checkbox select, use the `customBadgeText` property. The following example uses `customBadgeText` to display "all" in the badge once all menu items are selected.
|
|
730
1006
|
|
|
731
1007
|
```js
|
|
732
1008
|
import React from 'react';
|
|
733
|
-
import { Select, SelectOption, SelectGroup, SelectVariant
|
|
1009
|
+
import { Select, SelectOption, SelectGroup, SelectVariant } from '@patternfly/react-core';
|
|
734
1010
|
|
|
735
|
-
class
|
|
1011
|
+
class FilteringCheckboxSelectInputWithBadging extends React.Component {
|
|
736
1012
|
constructor(props) {
|
|
737
1013
|
super(props);
|
|
738
1014
|
|
|
739
1015
|
this.state = {
|
|
740
1016
|
isOpen: false,
|
|
741
|
-
selected:
|
|
742
|
-
|
|
743
|
-
isInputValuePersisted: false,
|
|
744
|
-
isInputFilterPersisted: false
|
|
1017
|
+
selected: [],
|
|
1018
|
+
customBadgeText: 0
|
|
745
1019
|
};
|
|
746
1020
|
|
|
747
|
-
this.toggleRef = React.createRef();
|
|
748
|
-
|
|
749
1021
|
this.options = [
|
|
750
1022
|
<SelectGroup label="Status" key="group1">
|
|
751
1023
|
<SelectOption key={0} value="Running" />
|
|
@@ -762,12 +1034,30 @@ class FilteringSingleSelectInput extends React.Component {
|
|
|
762
1034
|
];
|
|
763
1035
|
|
|
764
1036
|
this.onToggle = (_event, isOpen) => {
|
|
765
|
-
this.setState({
|
|
1037
|
+
this.setState({
|
|
1038
|
+
isOpen
|
|
1039
|
+
});
|
|
766
1040
|
};
|
|
767
1041
|
|
|
768
1042
|
this.onSelect = (event, selection) => {
|
|
769
|
-
|
|
770
|
-
|
|
1043
|
+
const { selected } = this.state;
|
|
1044
|
+
if (selected.includes(selection)) {
|
|
1045
|
+
this.setState(
|
|
1046
|
+
prevState => ({
|
|
1047
|
+
selected: prevState.selected.filter(item => item !== selection),
|
|
1048
|
+
customBadgeText: this.setBadgeText(prevState.selected.length - 1)
|
|
1049
|
+
}),
|
|
1050
|
+
() => console.log('selections: ', this.state.selected)
|
|
1051
|
+
);
|
|
1052
|
+
} else {
|
|
1053
|
+
this.setState(
|
|
1054
|
+
prevState => ({
|
|
1055
|
+
selected: [...prevState.selected, selection],
|
|
1056
|
+
customBadgeText: this.setBadgeText(prevState.selected.length + 1)
|
|
1057
|
+
}),
|
|
1058
|
+
() => console.log('selections: ', this.state.selected)
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
771
1061
|
};
|
|
772
1062
|
|
|
773
1063
|
this.onFilter = (_, textInput) => {
|
|
@@ -783,48 +1073,39 @@ class FilteringSingleSelectInput extends React.Component {
|
|
|
783
1073
|
});
|
|
784
1074
|
if (filteredGroup.props.children.length > 0) return filteredGroup;
|
|
785
1075
|
})
|
|
786
|
-
.filter(
|
|
1076
|
+
.filter(newGroup => newGroup);
|
|
787
1077
|
return filteredGroups;
|
|
788
1078
|
}
|
|
789
1079
|
};
|
|
790
1080
|
|
|
791
|
-
this.
|
|
792
|
-
this.setState({
|
|
793
|
-
isCreatable: checked
|
|
794
|
-
});
|
|
795
|
-
};
|
|
796
|
-
|
|
797
|
-
this.toggleInputValuePersisted = checked => {
|
|
1081
|
+
this.clearSelection = () => {
|
|
798
1082
|
this.setState({
|
|
799
|
-
|
|
1083
|
+
selected: [],
|
|
1084
|
+
customBadgeText: this.setBadgeText(0)
|
|
800
1085
|
});
|
|
801
1086
|
};
|
|
802
1087
|
|
|
803
|
-
this.
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
1088
|
+
this.setBadgeText = selected => {
|
|
1089
|
+
if (selected === 7) {
|
|
1090
|
+
return 'All';
|
|
1091
|
+
}
|
|
1092
|
+
if (selected === 0) {
|
|
1093
|
+
return 0;
|
|
1094
|
+
}
|
|
1095
|
+
return null;
|
|
807
1096
|
};
|
|
808
1097
|
}
|
|
809
1098
|
|
|
810
1099
|
render() {
|
|
811
|
-
const {
|
|
812
|
-
|
|
813
|
-
selected,
|
|
814
|
-
filteredOptions,
|
|
815
|
-
isInputValuePersisted,
|
|
816
|
-
isInputFilterPersisted,
|
|
817
|
-
isCreatable
|
|
818
|
-
} = this.state;
|
|
819
|
-
const titleId = 'single-filtering-select-id';
|
|
1100
|
+
const { isOpen, selected, filteredOptions, customBadgeText } = this.state;
|
|
1101
|
+
const titleId = 'checkbox-filtering-custom-badging-select-id';
|
|
820
1102
|
return (
|
|
821
1103
|
<div>
|
|
822
1104
|
<span id={titleId} hidden>
|
|
823
|
-
|
|
1105
|
+
Checkbox Title
|
|
824
1106
|
</span>
|
|
825
1107
|
<Select
|
|
826
|
-
variant={SelectVariant.
|
|
827
|
-
toggleRef={this.toggleRef}
|
|
1108
|
+
variant={SelectVariant.checkbox}
|
|
828
1109
|
onToggle={this.onToggle}
|
|
829
1110
|
onSelect={this.onSelect}
|
|
830
1111
|
selections={selected}
|
|
@@ -832,51 +1113,28 @@ class FilteringSingleSelectInput extends React.Component {
|
|
|
832
1113
|
placeholderText="Filter by status"
|
|
833
1114
|
aria-labelledby={titleId}
|
|
834
1115
|
onFilter={this.onFilter}
|
|
1116
|
+
onClear={this.clearSelection}
|
|
835
1117
|
isGrouped
|
|
836
1118
|
hasInlineFilter
|
|
837
|
-
|
|
838
|
-
isInputValuePersisted={isInputValuePersisted}
|
|
839
|
-
isInputFilterPersisted={isInputFilterPersisted}
|
|
1119
|
+
customBadgeText={customBadgeText}
|
|
840
1120
|
>
|
|
841
1121
|
{this.options}
|
|
842
1122
|
</Select>
|
|
843
|
-
<Checkbox
|
|
844
|
-
label="isInputValuePersisted"
|
|
845
|
-
isChecked={isInputValuePersisted}
|
|
846
|
-
onChange={(_event, checked) => this.toggleInputValuePersisted(checked)}
|
|
847
|
-
aria-label="toggle input value persisted"
|
|
848
|
-
id="toggle-inline-filter-input-value-persisted"
|
|
849
|
-
name="toggle-inline-filter-input-value-persisted"
|
|
850
|
-
/>
|
|
851
|
-
<Checkbox
|
|
852
|
-
label="isInputFilterPersisted"
|
|
853
|
-
isChecked={isInputFilterPersisted}
|
|
854
|
-
onChange={(_event, checked) => this.toggleInputFilterPersisted(checked)}
|
|
855
|
-
aria-label="toggle input filter persisted"
|
|
856
|
-
id="toggle-inline-filter-input-filter-persisted"
|
|
857
|
-
name="toggle-inline-filter-input-filter-persisted"
|
|
858
|
-
/>
|
|
859
|
-
<Checkbox
|
|
860
|
-
label="isCreatable"
|
|
861
|
-
isChecked={this.state.isCreatable}
|
|
862
|
-
onChange={(_event, checked) => this.toggleCreatable(checked)}
|
|
863
|
-
aria-label="toggle creatable checkbox"
|
|
864
|
-
id="toggle-inline-filter-creatable-typeahead"
|
|
865
|
-
name="toggle-inline-filter-creatable-typeahead"
|
|
866
|
-
/>
|
|
867
1123
|
</div>
|
|
868
1124
|
);
|
|
869
1125
|
}
|
|
870
1126
|
}
|
|
871
1127
|
```
|
|
872
1128
|
|
|
873
|
-
###
|
|
1129
|
+
### Checkbox select without selected count
|
|
1130
|
+
|
|
1131
|
+
To remove the default item count badge, use the `isCheckboxSelectionBadgeHidden` property.
|
|
874
1132
|
|
|
875
1133
|
```js
|
|
876
1134
|
import React from 'react';
|
|
877
|
-
import { Select, SelectOption,
|
|
1135
|
+
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
878
1136
|
|
|
879
|
-
class
|
|
1137
|
+
class CheckboxSelectInputNoBadge extends React.Component {
|
|
880
1138
|
constructor(props) {
|
|
881
1139
|
super(props);
|
|
882
1140
|
|
|
@@ -885,21 +1143,6 @@ class FilteringCheckboxSelectInput extends React.Component {
|
|
|
885
1143
|
selected: []
|
|
886
1144
|
};
|
|
887
1145
|
|
|
888
|
-
this.options = [
|
|
889
|
-
<SelectGroup label="Status" key="group1">
|
|
890
|
-
<SelectOption key={0} value="Running" />
|
|
891
|
-
<SelectOption key={1} value="Stopped" />
|
|
892
|
-
<SelectOption key={2} value="Down" />
|
|
893
|
-
<SelectOption key={3} value="Degraded" />
|
|
894
|
-
<SelectOption key={4} value="Needs maintenance" />
|
|
895
|
-
</SelectGroup>,
|
|
896
|
-
<SelectGroup label="Vendor names" key="group2">
|
|
897
|
-
<SelectOption key={5} value="Dell" />
|
|
898
|
-
<SelectOption key={6} value="Samsung" isDisabled />
|
|
899
|
-
<SelectOption key={7} value="Hewlett-Packard" />
|
|
900
|
-
</SelectGroup>
|
|
901
|
-
];
|
|
902
|
-
|
|
903
1146
|
this.onToggle = (_event, isOpen) => {
|
|
904
1147
|
this.setState({
|
|
905
1148
|
isOpen
|
|
@@ -921,34 +1164,23 @@ class FilteringCheckboxSelectInput extends React.Component {
|
|
|
921
1164
|
}
|
|
922
1165
|
};
|
|
923
1166
|
|
|
924
|
-
this.onFilter = (_, textInput) => {
|
|
925
|
-
if (textInput === '') {
|
|
926
|
-
return this.options;
|
|
927
|
-
} else {
|
|
928
|
-
let filteredGroups = this.options
|
|
929
|
-
.map(group => {
|
|
930
|
-
let filteredGroup = React.cloneElement(group, {
|
|
931
|
-
children: group.props.children.filter(item => {
|
|
932
|
-
return item.props.value.toLowerCase().includes(textInput.toLowerCase());
|
|
933
|
-
})
|
|
934
|
-
});
|
|
935
|
-
if (filteredGroup.props.children.length > 0) return filteredGroup;
|
|
936
|
-
})
|
|
937
|
-
.filter(newGroup => newGroup);
|
|
938
|
-
return filteredGroups;
|
|
939
|
-
}
|
|
940
|
-
};
|
|
941
|
-
|
|
942
1167
|
this.clearSelection = () => {
|
|
943
1168
|
this.setState({
|
|
944
1169
|
selected: []
|
|
945
1170
|
});
|
|
946
1171
|
};
|
|
1172
|
+
|
|
1173
|
+
this.options = [
|
|
1174
|
+
<SelectOption key={0} value="Debug" />,
|
|
1175
|
+
<SelectOption key={1} value="Info" />,
|
|
1176
|
+
<SelectOption key={2} value="Warn" />,
|
|
1177
|
+
<SelectOption key={3} value="Error" />
|
|
1178
|
+
];
|
|
947
1179
|
}
|
|
948
1180
|
|
|
949
1181
|
render() {
|
|
950
|
-
const { isOpen, selected
|
|
951
|
-
const titleId = '
|
|
1182
|
+
const { isOpen, selected } = this.state;
|
|
1183
|
+
const titleId = 'checkbox-no-badge-select-id';
|
|
952
1184
|
return (
|
|
953
1185
|
<div>
|
|
954
1186
|
<span id={titleId} hidden>
|
|
@@ -956,16 +1188,14 @@ class FilteringCheckboxSelectInput extends React.Component {
|
|
|
956
1188
|
</span>
|
|
957
1189
|
<Select
|
|
958
1190
|
variant={SelectVariant.checkbox}
|
|
1191
|
+
aria-label="Select Input"
|
|
959
1192
|
onToggle={this.onToggle}
|
|
960
1193
|
onSelect={this.onSelect}
|
|
961
1194
|
selections={selected}
|
|
1195
|
+
isCheckboxSelectionBadgeHidden
|
|
962
1196
|
isOpen={isOpen}
|
|
963
1197
|
placeholderText="Filter by status"
|
|
964
1198
|
aria-labelledby={titleId}
|
|
965
|
-
onFilter={this.onFilter}
|
|
966
|
-
onClear={this.clearSelection}
|
|
967
|
-
isGrouped
|
|
968
|
-
hasInlineFilter
|
|
969
1199
|
>
|
|
970
1200
|
{this.options}
|
|
971
1201
|
</Select>
|
|
@@ -975,13 +1205,15 @@ class FilteringCheckboxSelectInput extends React.Component {
|
|
|
975
1205
|
}
|
|
976
1206
|
```
|
|
977
1207
|
|
|
978
|
-
###
|
|
1208
|
+
### Checkbox select with item counts
|
|
1209
|
+
|
|
1210
|
+
To show users the number of items that a `<SelectOption>` would match, use the `itemCount` property. The numerical value you pass into `itemCount` is displayed to the right of each menu item.
|
|
979
1211
|
|
|
980
1212
|
```js
|
|
981
1213
|
import React from 'react';
|
|
982
|
-
import { Select, SelectOption,
|
|
1214
|
+
import { Select, SelectOption, SelectVariant, Divider } from '@patternfly/react-core';
|
|
983
1215
|
|
|
984
|
-
class
|
|
1216
|
+
class CheckboxSelectWithCounts extends React.Component {
|
|
985
1217
|
constructor(props) {
|
|
986
1218
|
super(props);
|
|
987
1219
|
|
|
@@ -990,21 +1222,6 @@ class FilteringCheckboxSelectInputWithPlaceholder extends React.Component {
|
|
|
990
1222
|
selected: []
|
|
991
1223
|
};
|
|
992
1224
|
|
|
993
|
-
this.options = [
|
|
994
|
-
<SelectGroup label="Status" key="group1">
|
|
995
|
-
<SelectOption key={0} value="Running" />
|
|
996
|
-
<SelectOption key={1} value="Stopped" />
|
|
997
|
-
<SelectOption key={2} value="Down" />
|
|
998
|
-
<SelectOption key={3} value="Degraded" />
|
|
999
|
-
<SelectOption key={4} value="Needs maintenance" />
|
|
1000
|
-
</SelectGroup>,
|
|
1001
|
-
<SelectGroup label="Vendor names" key="group2">
|
|
1002
|
-
<SelectOption key={5} value="Dell" />
|
|
1003
|
-
<SelectOption key={6} value="Samsung" isDisabled />
|
|
1004
|
-
<SelectOption key={7} value="Hewlett-Packard" />
|
|
1005
|
-
</SelectGroup>
|
|
1006
|
-
];
|
|
1007
|
-
|
|
1008
1225
|
this.onToggle = (_event, isOpen) => {
|
|
1009
1226
|
this.setState({
|
|
1010
1227
|
isOpen
|
|
@@ -1026,52 +1243,38 @@ class FilteringCheckboxSelectInputWithPlaceholder extends React.Component {
|
|
|
1026
1243
|
}
|
|
1027
1244
|
};
|
|
1028
1245
|
|
|
1029
|
-
this.onFilter = (_, textInput) => {
|
|
1030
|
-
if (textInput === '') {
|
|
1031
|
-
return this.options;
|
|
1032
|
-
} else {
|
|
1033
|
-
let filteredGroups = this.options
|
|
1034
|
-
.map(group => {
|
|
1035
|
-
let filteredGroup = React.cloneElement(group, {
|
|
1036
|
-
children: group.props.children.filter(item => {
|
|
1037
|
-
return item.props.value.toLowerCase().includes(textInput.toLowerCase());
|
|
1038
|
-
})
|
|
1039
|
-
});
|
|
1040
|
-
if (filteredGroup.props.children.length > 0) return filteredGroup;
|
|
1041
|
-
})
|
|
1042
|
-
.filter(newGroup => newGroup);
|
|
1043
|
-
return filteredGroups;
|
|
1044
|
-
}
|
|
1045
|
-
};
|
|
1046
|
-
|
|
1047
1246
|
this.clearSelection = () => {
|
|
1048
1247
|
this.setState({
|
|
1049
1248
|
selected: []
|
|
1050
1249
|
});
|
|
1051
1250
|
};
|
|
1251
|
+
|
|
1252
|
+
this.options = [
|
|
1253
|
+
<SelectOption key={0} value="Active" description="This is a description" itemCount={3} />,
|
|
1254
|
+
<SelectOption key={1} value="Cancelled" itemCount={1} />,
|
|
1255
|
+
<SelectOption key={2} value="Paused" itemCount={15} />,
|
|
1256
|
+
<SelectOption key={3} value="Warning" itemCount={2} />,
|
|
1257
|
+
<SelectOption key={4} value="Restarted" itemCount={8} />
|
|
1258
|
+
];
|
|
1052
1259
|
}
|
|
1053
1260
|
|
|
1054
1261
|
render() {
|
|
1055
|
-
const { isOpen, selected
|
|
1056
|
-
const titleId = 'checkbox-
|
|
1262
|
+
const { isOpen, selected } = this.state;
|
|
1263
|
+
const titleId = 'checkbox-select-with-counts-id';
|
|
1057
1264
|
return (
|
|
1058
1265
|
<div>
|
|
1059
1266
|
<span id={titleId} hidden>
|
|
1060
|
-
Checkbox Title
|
|
1267
|
+
Checkbox With Counts Title
|
|
1061
1268
|
</span>
|
|
1062
1269
|
<Select
|
|
1063
1270
|
variant={SelectVariant.checkbox}
|
|
1271
|
+
aria-label="Select Input"
|
|
1064
1272
|
onToggle={this.onToggle}
|
|
1065
1273
|
onSelect={this.onSelect}
|
|
1066
1274
|
selections={selected}
|
|
1067
1275
|
isOpen={isOpen}
|
|
1068
1276
|
placeholderText="Filter by status"
|
|
1069
1277
|
aria-labelledby={titleId}
|
|
1070
|
-
onFilter={this.onFilter}
|
|
1071
|
-
onClear={this.clearSelection}
|
|
1072
|
-
isGrouped
|
|
1073
|
-
hasInlineFilter
|
|
1074
|
-
inlineFilterPlaceholderText="Filter by status"
|
|
1075
1278
|
>
|
|
1076
1279
|
{this.options}
|
|
1077
1280
|
</Select>
|
|
@@ -1081,121 +1284,83 @@ class FilteringCheckboxSelectInputWithPlaceholder extends React.Component {
|
|
|
1081
1284
|
}
|
|
1082
1285
|
```
|
|
1083
1286
|
|
|
1084
|
-
###
|
|
1287
|
+
### Checkbox select with a footer
|
|
1288
|
+
|
|
1289
|
+
You can combine a footer with checkbox input to allow users to apply an action to multiple items.
|
|
1085
1290
|
|
|
1086
1291
|
```js
|
|
1087
1292
|
import React from 'react';
|
|
1088
|
-
import { Select, SelectOption,
|
|
1293
|
+
import { Select, SelectOption, SelectVariant, Button } from '@patternfly/react-core';
|
|
1089
1294
|
|
|
1090
|
-
class
|
|
1295
|
+
class SelectWithFooterCheckbox extends React.Component {
|
|
1091
1296
|
constructor(props) {
|
|
1092
1297
|
super(props);
|
|
1093
|
-
|
|
1094
1298
|
this.state = {
|
|
1095
1299
|
isOpen: false,
|
|
1096
1300
|
selected: [],
|
|
1097
|
-
|
|
1301
|
+
numOptions: 3,
|
|
1302
|
+
isLoading: false
|
|
1098
1303
|
};
|
|
1099
1304
|
|
|
1305
|
+
this.toggleRef = React.createRef();
|
|
1306
|
+
|
|
1100
1307
|
this.options = [
|
|
1101
|
-
<
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
<SelectOption key={4} value="Needs maintenance" />
|
|
1107
|
-
</SelectGroup>,
|
|
1108
|
-
<SelectGroup label="Vendor names" key="group2">
|
|
1109
|
-
<SelectOption key={5} value="Dell" />
|
|
1110
|
-
<SelectOption key={6} value="Samsung" isDisabled />
|
|
1111
|
-
<SelectOption key={7} value="Hewlett-Packard" />
|
|
1112
|
-
</SelectGroup>
|
|
1308
|
+
<SelectOption key={0} value="Active" description="This is a description" />,
|
|
1309
|
+
<SelectOption key={1} value="Cancelled" />,
|
|
1310
|
+
<SelectOption key={2} value="Paused" />,
|
|
1311
|
+
<SelectOption key={4} value="Warning" />,
|
|
1312
|
+
<SelectOption key={5} value="Restarted" />
|
|
1113
1313
|
];
|
|
1114
1314
|
|
|
1115
1315
|
this.onToggle = (_event, isOpen) => {
|
|
1116
|
-
this.setState({
|
|
1117
|
-
isOpen
|
|
1118
|
-
});
|
|
1316
|
+
this.setState({ isOpen });
|
|
1119
1317
|
};
|
|
1120
1318
|
|
|
1121
1319
|
this.onSelect = (event, selection) => {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
this.setState(
|
|
1125
|
-
prevState => ({
|
|
1126
|
-
selected: prevState.selected.filter(item => item !== selection),
|
|
1127
|
-
customBadgeText: this.setBadgeText(prevState.selected.length - 1)
|
|
1128
|
-
}),
|
|
1129
|
-
() => console.log('selections: ', this.state.selected)
|
|
1130
|
-
);
|
|
1131
|
-
} else {
|
|
1132
|
-
this.setState(
|
|
1133
|
-
prevState => ({
|
|
1134
|
-
selected: [...prevState.selected, selection],
|
|
1135
|
-
customBadgeText: this.setBadgeText(prevState.selected.length + 1)
|
|
1136
|
-
}),
|
|
1137
|
-
() => console.log('selections: ', this.state.selected)
|
|
1138
|
-
);
|
|
1139
|
-
}
|
|
1320
|
+
this.setState({ selected: selection, isOpen: false }), console.log('selected: ', selection);
|
|
1321
|
+
this.toggleRef.current.focus();
|
|
1140
1322
|
};
|
|
1141
1323
|
|
|
1142
1324
|
this.onFilter = (_, textInput) => {
|
|
1143
1325
|
if (textInput === '') {
|
|
1144
1326
|
return this.options;
|
|
1145
1327
|
} else {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
return item.props.value.toLowerCase().includes(textInput.toLowerCase());
|
|
1151
|
-
})
|
|
1152
|
-
});
|
|
1153
|
-
if (filteredGroup.props.children.length > 0) return filteredGroup;
|
|
1154
|
-
})
|
|
1155
|
-
.filter(newGroup => newGroup);
|
|
1156
|
-
return filteredGroups;
|
|
1328
|
+
this.setState(
|
|
1329
|
+
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
1330
|
+
() => console.log('selections: ', this.state.selected)
|
|
1331
|
+
);
|
|
1157
1332
|
}
|
|
1158
1333
|
};
|
|
1159
1334
|
|
|
1160
1335
|
this.clearSelection = () => {
|
|
1161
1336
|
this.setState({
|
|
1162
|
-
selected: []
|
|
1163
|
-
customBadgeText: this.setBadgeText(0)
|
|
1337
|
+
selected: []
|
|
1164
1338
|
});
|
|
1165
1339
|
};
|
|
1166
|
-
|
|
1167
|
-
this.setBadgeText = selected => {
|
|
1168
|
-
if (selected === 7) {
|
|
1169
|
-
return 'All';
|
|
1170
|
-
}
|
|
1171
|
-
if (selected === 0) {
|
|
1172
|
-
return 0;
|
|
1173
|
-
}
|
|
1174
|
-
return null;
|
|
1175
|
-
};
|
|
1176
1340
|
}
|
|
1177
1341
|
|
|
1178
1342
|
render() {
|
|
1179
|
-
const { isOpen, selected,
|
|
1180
|
-
const titleId = '
|
|
1343
|
+
const { isOpen, selected, isDisabled, direction, isToggleIcon } = this.state;
|
|
1344
|
+
const titleId = 'title-id-footer-checkbox';
|
|
1181
1345
|
return (
|
|
1182
1346
|
<div>
|
|
1183
1347
|
<span id={titleId} hidden>
|
|
1184
|
-
|
|
1348
|
+
Title
|
|
1185
1349
|
</span>
|
|
1186
1350
|
<Select
|
|
1187
|
-
variant={SelectVariant.
|
|
1351
|
+
variant={SelectVariant.single}
|
|
1352
|
+
toggleRef={this.toggleRef}
|
|
1188
1353
|
onToggle={this.onToggle}
|
|
1189
1354
|
onSelect={this.onSelect}
|
|
1190
1355
|
selections={selected}
|
|
1191
1356
|
isOpen={isOpen}
|
|
1192
1357
|
placeholderText="Filter by status"
|
|
1193
1358
|
aria-labelledby={titleId}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1359
|
+
footer={
|
|
1360
|
+
<Button variant="link" isInline>
|
|
1361
|
+
Action
|
|
1362
|
+
</Button>
|
|
1363
|
+
}
|
|
1199
1364
|
>
|
|
1200
1365
|
{this.options}
|
|
1201
1366
|
</Select>
|
|
@@ -1205,491 +1370,441 @@ class FilteringCheckboxSelectInputWithBadging extends React.Component {
|
|
|
1205
1370
|
}
|
|
1206
1371
|
```
|
|
1207
1372
|
|
|
1208
|
-
###
|
|
1373
|
+
### Checkbox select with view more
|
|
1374
|
+
|
|
1375
|
+
When a "view more" link is used alongside checkbox input, selections that users make prior to clicking "view more" are persisted after the click.
|
|
1209
1376
|
|
|
1210
1377
|
```js
|
|
1211
1378
|
import React from 'react';
|
|
1212
|
-
import {
|
|
1379
|
+
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
1213
1380
|
|
|
1214
|
-
class
|
|
1381
|
+
class SelectViewMoreCheckbox extends React.Component {
|
|
1215
1382
|
constructor(props) {
|
|
1216
1383
|
super(props);
|
|
1217
|
-
this.defaultOptions = [
|
|
1218
|
-
{ value: 'Alabama' },
|
|
1219
|
-
{ value: 'Florida', description: 'This is a description' },
|
|
1220
|
-
{ value: 'New Jersey' },
|
|
1221
|
-
{ value: 'New Mexico' },
|
|
1222
|
-
{ value: 'New York' },
|
|
1223
|
-
{ value: 'North Carolina' }
|
|
1224
|
-
];
|
|
1225
1384
|
|
|
1226
1385
|
this.state = {
|
|
1227
|
-
options: this.defaultOptions,
|
|
1228
1386
|
isOpen: false,
|
|
1229
|
-
selected:
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
isCreateOptionOnTop: false,
|
|
1233
|
-
isInputValuePersisted: false,
|
|
1234
|
-
isInputFilterPersisted: false,
|
|
1235
|
-
hasOnCreateOption: false,
|
|
1236
|
-
resetOnSelect: true
|
|
1387
|
+
selected: [],
|
|
1388
|
+
numOptions: 3,
|
|
1389
|
+
isLoading: false
|
|
1237
1390
|
};
|
|
1238
1391
|
|
|
1392
|
+
this.options = [
|
|
1393
|
+
<SelectOption key={0} value="Active" description="This is a description" />,
|
|
1394
|
+
<SelectOption key={1} value="Cancelled" />,
|
|
1395
|
+
<SelectOption key={2} value="Paused" />,
|
|
1396
|
+
<SelectOption key={4} value="Warning" />,
|
|
1397
|
+
<SelectOption key={5} value="Restarted" />,
|
|
1398
|
+
<SelectOption key={6} value="Down" />,
|
|
1399
|
+
<SelectOption key={7} value="Disabled" />,
|
|
1400
|
+
<SelectOption key={8} value="Needs maintenance " />,
|
|
1401
|
+
<SelectOption key={9} value="Degraded " />
|
|
1402
|
+
];
|
|
1403
|
+
|
|
1239
1404
|
this.onToggle = (_event, isOpen) => {
|
|
1240
1405
|
this.setState({
|
|
1241
1406
|
isOpen
|
|
1242
1407
|
});
|
|
1243
1408
|
};
|
|
1244
1409
|
|
|
1245
|
-
this.onSelect = (event, selection
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
this.setState(
|
|
1249
|
-
selected: selection,
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1410
|
+
this.onSelect = (event, selection) => {
|
|
1411
|
+
const { selected } = this.state;
|
|
1412
|
+
if (selected.includes(selection)) {
|
|
1413
|
+
this.setState(
|
|
1414
|
+
prevState => ({ selected: prevState.selected.filter(item => item !== selection) }),
|
|
1415
|
+
() => console.log('selections: ', this.state.selected)
|
|
1416
|
+
);
|
|
1417
|
+
} else {
|
|
1418
|
+
this.setState(
|
|
1419
|
+
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
1420
|
+
() => console.log('selections: ', this.state.selected)
|
|
1421
|
+
);
|
|
1253
1422
|
}
|
|
1254
1423
|
};
|
|
1255
1424
|
|
|
1256
|
-
this.
|
|
1425
|
+
this.clearSelection = () => {
|
|
1257
1426
|
this.setState({
|
|
1258
|
-
|
|
1427
|
+
selected: []
|
|
1259
1428
|
});
|
|
1260
1429
|
};
|
|
1261
1430
|
|
|
1262
|
-
this.
|
|
1263
|
-
|
|
1264
|
-
selected: null,
|
|
1265
|
-
isOpen: false,
|
|
1266
|
-
options: this.defaultOptions
|
|
1267
|
-
});
|
|
1268
|
-
};
|
|
1269
|
-
|
|
1270
|
-
this.toggleDisabled = checked => {
|
|
1271
|
-
this.setState({
|
|
1272
|
-
isDisabled: checked
|
|
1273
|
-
});
|
|
1274
|
-
};
|
|
1275
|
-
|
|
1276
|
-
this.toggleCreatable = checked => {
|
|
1277
|
-
this.setState({
|
|
1278
|
-
isCreatable: checked
|
|
1279
|
-
});
|
|
1280
|
-
};
|
|
1281
|
-
|
|
1282
|
-
this.toggleCreateOptionOnTop = checked => {
|
|
1283
|
-
this.setState({
|
|
1284
|
-
isCreateOptionOnTop: checked
|
|
1285
|
-
});
|
|
1286
|
-
};
|
|
1287
|
-
|
|
1288
|
-
this.toggleCreateNew = checked => {
|
|
1289
|
-
this.setState({
|
|
1290
|
-
hasOnCreateOption: checked
|
|
1291
|
-
});
|
|
1292
|
-
};
|
|
1293
|
-
|
|
1294
|
-
this.toggleInputValuePersisted = checked => {
|
|
1295
|
-
this.setState({
|
|
1296
|
-
isInputValuePersisted: checked
|
|
1297
|
-
});
|
|
1298
|
-
};
|
|
1299
|
-
|
|
1300
|
-
this.toggleInputFilterPersisted = checked => {
|
|
1301
|
-
this.setState({
|
|
1302
|
-
isInputFilterPersisted: checked
|
|
1303
|
-
});
|
|
1431
|
+
this.simulateNetworkCall = callback => {
|
|
1432
|
+
setTimeout(callback, 2000);
|
|
1304
1433
|
};
|
|
1305
1434
|
|
|
1306
|
-
this.
|
|
1307
|
-
|
|
1308
|
-
|
|
1435
|
+
this.onViewMoreClick = () => {
|
|
1436
|
+
// Set select loadingVariant to spinner then simulate network call before loading more options
|
|
1437
|
+
this.setState({ isLoading: true });
|
|
1438
|
+
this.simulateNetworkCall(() => {
|
|
1439
|
+
const newLength =
|
|
1440
|
+
this.state.numOptions + 3 <= this.options.length ? this.state.numOptions + 3 : this.options.length;
|
|
1441
|
+
this.setState({ numOptions: newLength, isLoading: false });
|
|
1309
1442
|
});
|
|
1310
1443
|
};
|
|
1311
1444
|
}
|
|
1312
1445
|
|
|
1313
1446
|
render() {
|
|
1314
|
-
const {
|
|
1315
|
-
|
|
1316
|
-
selected,
|
|
1317
|
-
isDisabled,
|
|
1318
|
-
isCreatable,
|
|
1319
|
-
isCreateOptionOnTop,
|
|
1320
|
-
hasOnCreateOption,
|
|
1321
|
-
isInputValuePersisted,
|
|
1322
|
-
isInputFilterPersisted,
|
|
1323
|
-
resetOnSelect,
|
|
1324
|
-
options
|
|
1325
|
-
} = this.state;
|
|
1326
|
-
const titleId = 'typeahead-select-id-1';
|
|
1447
|
+
const { isOpen, selected, numOptions, isLoading } = this.state;
|
|
1448
|
+
const titleId = 'view-more-checkbox-select-id';
|
|
1327
1449
|
return (
|
|
1328
1450
|
<div>
|
|
1329
1451
|
<span id={titleId} hidden>
|
|
1330
|
-
|
|
1452
|
+
Checkbox View more check
|
|
1331
1453
|
</span>
|
|
1332
1454
|
<Select
|
|
1333
|
-
variant={SelectVariant.
|
|
1334
|
-
|
|
1455
|
+
variant={SelectVariant.checkbox}
|
|
1456
|
+
aria-label="Select input"
|
|
1335
1457
|
onToggle={this.onToggle}
|
|
1336
1458
|
onSelect={this.onSelect}
|
|
1337
|
-
onClear={this.clearSelection}
|
|
1338
1459
|
selections={selected}
|
|
1339
1460
|
isOpen={isOpen}
|
|
1461
|
+
placeholderText="Filter by status"
|
|
1340
1462
|
aria-labelledby={titleId}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
isCreateOptionOnTop={isCreateOptionOnTop}
|
|
1347
|
-
onCreateOption={(hasOnCreateOption && this.onCreateOption) || undefined}
|
|
1348
|
-
shouldResetOnSelect={resetOnSelect}
|
|
1463
|
+
{...(!isLoading &&
|
|
1464
|
+
numOptions < this.options.length && {
|
|
1465
|
+
loadingVariant: { text: 'View more', onClick: this.onViewMoreClick }
|
|
1466
|
+
})}
|
|
1467
|
+
{...(isLoading && { loadingVariant: 'spinner' })}
|
|
1349
1468
|
>
|
|
1350
|
-
{options.
|
|
1351
|
-
<SelectOption
|
|
1352
|
-
isDisabled={option.disabled}
|
|
1353
|
-
key={index}
|
|
1354
|
-
value={option.value}
|
|
1355
|
-
{...(option.description && { description: option.description })}
|
|
1356
|
-
/>
|
|
1357
|
-
))}
|
|
1469
|
+
{this.options.slice(0, numOptions)}
|
|
1358
1470
|
</Select>
|
|
1359
|
-
<Checkbox
|
|
1360
|
-
label="isDisabled"
|
|
1361
|
-
isChecked={this.state.isDisabled}
|
|
1362
|
-
onChange={(_event, checked) => this.toggleDisabled(checked)}
|
|
1363
|
-
aria-label="toggle disabled checkbox"
|
|
1364
|
-
id="toggle-disabled-typeahead"
|
|
1365
|
-
name="toggle-disabled-typeahead"
|
|
1366
|
-
/>
|
|
1367
|
-
<Checkbox
|
|
1368
|
-
label="isCreatable"
|
|
1369
|
-
isChecked={this.state.isCreatable}
|
|
1370
|
-
onChange={(_event, checked) => this.toggleCreatable(checked)}
|
|
1371
|
-
aria-label="toggle creatable checkbox"
|
|
1372
|
-
id="toggle-creatable-typeahead"
|
|
1373
|
-
name="toggle-creatable-typeahead"
|
|
1374
|
-
/>
|
|
1375
|
-
<Checkbox
|
|
1376
|
-
label="isCreateOptionOnTop"
|
|
1377
|
-
isChecked={this.state.isCreateOptionOnTop}
|
|
1378
|
-
onChange={(_event, checked) => this.toggleCreateOptionOnTop(checked)}
|
|
1379
|
-
aria-label="toggle createOptionOnTop checkbox"
|
|
1380
|
-
id="toggle-create-option-on-top-typeahead"
|
|
1381
|
-
name="toggle-create-option-on-top-typeahead"
|
|
1382
|
-
/>
|
|
1383
|
-
<Checkbox
|
|
1384
|
-
label="onCreateOption"
|
|
1385
|
-
isChecked={this.state.hasOnCreateOption}
|
|
1386
|
-
onChange={(_event, checked) => this.toggleCreateNew(checked)}
|
|
1387
|
-
aria-label="toggle new checkbox"
|
|
1388
|
-
id="toggle-new-typeahead"
|
|
1389
|
-
name="toggle-new-typeahead"
|
|
1390
|
-
/>
|
|
1391
|
-
<Checkbox
|
|
1392
|
-
label="isInputValuePersisted"
|
|
1393
|
-
isChecked={isInputValuePersisted}
|
|
1394
|
-
onChange={(_event, checked) => this.toggleInputValuePersisted(checked)}
|
|
1395
|
-
aria-label="toggle input value persisted"
|
|
1396
|
-
id="toggle-input-value-persisted"
|
|
1397
|
-
name="toggle-input-value-persisted"
|
|
1398
|
-
/>
|
|
1399
|
-
<Checkbox
|
|
1400
|
-
label="isInputFilterPersisted"
|
|
1401
|
-
isChecked={isInputFilterPersisted}
|
|
1402
|
-
onChange={(_event, checked) => this.toggleInputFilterPersisted(checked)}
|
|
1403
|
-
aria-label="toggle input filter persisted"
|
|
1404
|
-
id="toggle-input-filter-persisted"
|
|
1405
|
-
name="toggle-input-filter-persisted"
|
|
1406
|
-
/>
|
|
1407
|
-
<Checkbox
|
|
1408
|
-
label="shouldResetOnSelect"
|
|
1409
|
-
isChecked={this.state.resetOnSelect}
|
|
1410
|
-
onChange={(_event, checked) => this.toggleResetOnSelect(checked)}
|
|
1411
|
-
aria-label="toggle reset checkbox"
|
|
1412
|
-
id="toggle-reset-typeahead"
|
|
1413
|
-
name="toggle-reset-typeahead"
|
|
1414
|
-
/>
|
|
1415
1471
|
</div>
|
|
1416
1472
|
);
|
|
1417
1473
|
}
|
|
1418
1474
|
}
|
|
1419
1475
|
```
|
|
1420
1476
|
|
|
1421
|
-
###
|
|
1477
|
+
### Filtering with placeholder text
|
|
1478
|
+
|
|
1479
|
+
To preload a filter search bar with placeholder text, use the `inlineFilterPlaceholderText` property. The following example preloads the search bar with "Filter by status".
|
|
1422
1480
|
|
|
1423
1481
|
```js
|
|
1424
1482
|
import React from 'react';
|
|
1425
|
-
import {
|
|
1483
|
+
import { Select, SelectOption, SelectGroup, SelectVariant } from '@patternfly/react-core';
|
|
1426
1484
|
|
|
1427
|
-
class
|
|
1485
|
+
class FilteringCheckboxSelectInputWithPlaceholder extends React.Component {
|
|
1428
1486
|
constructor(props) {
|
|
1429
1487
|
super(props);
|
|
1430
1488
|
|
|
1431
1489
|
this.state = {
|
|
1432
|
-
options: [
|
|
1433
|
-
<SelectGroup label="Status" key="group1">
|
|
1434
|
-
<SelectOption key={0} value="Running" />
|
|
1435
|
-
<SelectOption key={1} value="Stopped" />
|
|
1436
|
-
<SelectOption key={2} value="Down" />
|
|
1437
|
-
<SelectOption key={3} value="Degraded" />
|
|
1438
|
-
<SelectOption key={4} value="Needs maintenance" />
|
|
1439
|
-
</SelectGroup>,
|
|
1440
|
-
<Divider key="divider" />,
|
|
1441
|
-
<SelectGroup label="Vendor names" key="group2">
|
|
1442
|
-
<SelectOption key={5} value="Dell" />
|
|
1443
|
-
<SelectOption key={6} value="Samsung" isDisabled />
|
|
1444
|
-
<SelectOption key={7} value="Hewlett-Packard" />
|
|
1445
|
-
</SelectGroup>
|
|
1446
|
-
],
|
|
1447
|
-
newOptions: [],
|
|
1448
1490
|
isOpen: false,
|
|
1449
|
-
selected:
|
|
1450
|
-
isCreatable: false,
|
|
1451
|
-
hasOnCreateOption: false
|
|
1491
|
+
selected: []
|
|
1452
1492
|
};
|
|
1453
1493
|
|
|
1494
|
+
this.options = [
|
|
1495
|
+
<SelectGroup label="Status" key="group1">
|
|
1496
|
+
<SelectOption key={0} value="Running" />
|
|
1497
|
+
<SelectOption key={1} value="Stopped" />
|
|
1498
|
+
<SelectOption key={2} value="Down" />
|
|
1499
|
+
<SelectOption key={3} value="Degraded" />
|
|
1500
|
+
<SelectOption key={4} value="Needs maintenance" />
|
|
1501
|
+
</SelectGroup>,
|
|
1502
|
+
<SelectGroup label="Vendor names" key="group2">
|
|
1503
|
+
<SelectOption key={5} value="Dell" />
|
|
1504
|
+
<SelectOption key={6} value="Samsung" isDisabled />
|
|
1505
|
+
<SelectOption key={7} value="Hewlett-Packard" />
|
|
1506
|
+
</SelectGroup>
|
|
1507
|
+
];
|
|
1508
|
+
|
|
1454
1509
|
this.onToggle = (_event, isOpen) => {
|
|
1455
1510
|
this.setState({
|
|
1456
1511
|
isOpen
|
|
1457
1512
|
});
|
|
1458
1513
|
};
|
|
1459
1514
|
|
|
1460
|
-
this.onSelect = (event, selection
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
this.setState(
|
|
1464
|
-
selected: selection,
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1515
|
+
this.onSelect = (event, selection) => {
|
|
1516
|
+
const { selected } = this.state;
|
|
1517
|
+
if (selected.includes(selection)) {
|
|
1518
|
+
this.setState(
|
|
1519
|
+
prevState => ({ selected: prevState.selected.filter(item => item !== selection) }),
|
|
1520
|
+
() => console.log('selections: ', this.state.selected)
|
|
1521
|
+
);
|
|
1522
|
+
} else {
|
|
1523
|
+
this.setState(
|
|
1524
|
+
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
1525
|
+
() => console.log('selections: ', this.state.selected)
|
|
1526
|
+
);
|
|
1468
1527
|
}
|
|
1469
1528
|
};
|
|
1470
1529
|
|
|
1471
|
-
this.
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
}
|
|
1530
|
+
this.onFilter = (_, textInput) => {
|
|
1531
|
+
if (textInput === '') {
|
|
1532
|
+
return this.options;
|
|
1533
|
+
} else {
|
|
1534
|
+
let filteredGroups = this.options
|
|
1535
|
+
.map(group => {
|
|
1536
|
+
let filteredGroup = React.cloneElement(group, {
|
|
1537
|
+
children: group.props.children.filter(item => {
|
|
1538
|
+
return item.props.value.toLowerCase().includes(textInput.toLowerCase());
|
|
1539
|
+
})
|
|
1540
|
+
});
|
|
1541
|
+
if (filteredGroup.props.children.length > 0) return filteredGroup;
|
|
1542
|
+
})
|
|
1543
|
+
.filter(newGroup => newGroup);
|
|
1544
|
+
return filteredGroups;
|
|
1545
|
+
}
|
|
1475
1546
|
};
|
|
1476
1547
|
|
|
1477
1548
|
this.clearSelection = () => {
|
|
1478
1549
|
this.setState({
|
|
1479
|
-
selected:
|
|
1480
|
-
isOpen: false
|
|
1481
|
-
});
|
|
1482
|
-
};
|
|
1483
|
-
|
|
1484
|
-
this.toggleCreatable = checked => {
|
|
1485
|
-
this.setState({
|
|
1486
|
-
isCreatable: checked
|
|
1487
|
-
});
|
|
1488
|
-
};
|
|
1489
|
-
|
|
1490
|
-
this.toggleCreateNew = checked => {
|
|
1491
|
-
this.setState({
|
|
1492
|
-
hasOnCreateOption: checked
|
|
1550
|
+
selected: []
|
|
1493
1551
|
});
|
|
1494
1552
|
};
|
|
1495
1553
|
}
|
|
1496
1554
|
|
|
1497
1555
|
render() {
|
|
1498
|
-
const { isOpen, selected,
|
|
1499
|
-
const titleId = '
|
|
1500
|
-
const allOptions =
|
|
1501
|
-
newOptions.length > 0
|
|
1502
|
-
? options.concat(
|
|
1503
|
-
<SelectGroup label="Created" key="create-group">
|
|
1504
|
-
{newOptions}
|
|
1505
|
-
</SelectGroup>
|
|
1506
|
-
)
|
|
1507
|
-
: options;
|
|
1556
|
+
const { isOpen, selected, filteredOptions } = this.state;
|
|
1557
|
+
const titleId = 'checkbox-filtering-with-placeholder-select-id';
|
|
1508
1558
|
return (
|
|
1509
1559
|
<div>
|
|
1510
1560
|
<span id={titleId} hidden>
|
|
1511
|
-
|
|
1561
|
+
Checkbox Title
|
|
1512
1562
|
</span>
|
|
1513
1563
|
<Select
|
|
1514
|
-
variant={SelectVariant.
|
|
1515
|
-
typeAheadAriaLabel="Select a state"
|
|
1564
|
+
variant={SelectVariant.checkbox}
|
|
1516
1565
|
onToggle={this.onToggle}
|
|
1517
1566
|
onSelect={this.onSelect}
|
|
1518
|
-
onClear={this.clearSelection}
|
|
1519
1567
|
selections={selected}
|
|
1520
1568
|
isOpen={isOpen}
|
|
1569
|
+
placeholderText="Filter by status"
|
|
1521
1570
|
aria-labelledby={titleId}
|
|
1522
|
-
|
|
1571
|
+
onFilter={this.onFilter}
|
|
1572
|
+
onClear={this.clearSelection}
|
|
1523
1573
|
isGrouped
|
|
1524
|
-
|
|
1525
|
-
|
|
1574
|
+
hasInlineFilter
|
|
1575
|
+
inlineFilterPlaceholderText="Filter by status"
|
|
1526
1576
|
>
|
|
1527
|
-
{
|
|
1577
|
+
{this.options}
|
|
1528
1578
|
</Select>
|
|
1529
|
-
<Checkbox
|
|
1530
|
-
label="isCreatable"
|
|
1531
|
-
isChecked={this.state.isCreatable}
|
|
1532
|
-
onChange={(_event, checked) => this.toggleCreatable(checked)}
|
|
1533
|
-
aria-label="toggle creatable checkbox"
|
|
1534
|
-
id="toggle-creatable-grouped-typeahead"
|
|
1535
|
-
name="toggle-creatable-grouped-typeahead"
|
|
1536
|
-
/>
|
|
1537
|
-
<Checkbox
|
|
1538
|
-
label="onCreateOption"
|
|
1539
|
-
isChecked={this.state.hasOnCreateOption}
|
|
1540
|
-
onChange={(_event, checked) => this.toggleCreateNew(checked)}
|
|
1541
|
-
aria-label="toggle new checkbox"
|
|
1542
|
-
id="toggle-new-grouped-typeahead"
|
|
1543
|
-
name="toggle-new-grouped-typeahead"
|
|
1544
|
-
/>
|
|
1545
1579
|
</div>
|
|
1546
1580
|
);
|
|
1547
1581
|
}
|
|
1548
1582
|
}
|
|
1549
1583
|
```
|
|
1550
1584
|
|
|
1551
|
-
###
|
|
1585
|
+
### Inline filtering
|
|
1586
|
+
|
|
1587
|
+
To allow users to filter select lists using text input, use the `hasInlineFilter` property. Filtering behavior can be further customized with other properties, as shown in the example below. Select each checkbox to visualize the following behavior:
|
|
1588
|
+
|
|
1589
|
+
- To persist filter results on blur, use the `isInputValuePersisted` property.
|
|
1590
|
+
- To persist a filter that a user has searched, use the `isInputFilterPersisted` property.
|
|
1591
|
+
- To allow users to add new items to a select list, use the `isCreatable` property. When this property is applied and a user searches for an option that doesn't exist, they will be prompted to "create" the item.
|
|
1552
1592
|
|
|
1553
1593
|
```js
|
|
1554
1594
|
import React from 'react';
|
|
1555
|
-
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
1595
|
+
import { Select, SelectOption, SelectGroup, SelectVariant, Checkbox } from '@patternfly/react-core';
|
|
1556
1596
|
|
|
1557
|
-
class
|
|
1597
|
+
class FilteringSingleSelectInput extends React.Component {
|
|
1558
1598
|
constructor(props) {
|
|
1559
1599
|
super(props);
|
|
1560
|
-
|
|
1561
|
-
<SelectOption key={0} value="Alabama" />,
|
|
1562
|
-
<SelectOption key={1} value="Florida" />,
|
|
1563
|
-
<SelectOption key={2} value="New Jersey" />,
|
|
1564
|
-
<SelectOption key={3} value="New Mexico" />,
|
|
1565
|
-
<SelectOption key={4} value="New York" />,
|
|
1566
|
-
<SelectOption key={5} value="North Carolina" />
|
|
1567
|
-
];
|
|
1600
|
+
|
|
1568
1601
|
this.state = {
|
|
1569
1602
|
isOpen: false,
|
|
1570
|
-
selected:
|
|
1603
|
+
selected: '',
|
|
1604
|
+
isCreatable: false,
|
|
1605
|
+
isInputValuePersisted: false,
|
|
1606
|
+
isInputFilterPersisted: false
|
|
1571
1607
|
};
|
|
1572
1608
|
|
|
1609
|
+
this.options = [
|
|
1610
|
+
<SelectGroup label="Status" key="group1">
|
|
1611
|
+
<SelectOption key={0} value="Running" />
|
|
1612
|
+
<SelectOption key={1} value="Stopped" />
|
|
1613
|
+
<SelectOption key={2} value="Down" />
|
|
1614
|
+
<SelectOption key={3} value="Degraded" />
|
|
1615
|
+
<SelectOption key={4} value="Needs maintenance" />
|
|
1616
|
+
</SelectGroup>,
|
|
1617
|
+
<SelectGroup label="Vendor names" key="group2">
|
|
1618
|
+
<SelectOption key={5} value="Dell" />
|
|
1619
|
+
<SelectOption key={6} value="Samsung" isDisabled />
|
|
1620
|
+
<SelectOption key={7} value="Hewlett-Packard" />
|
|
1621
|
+
</SelectGroup>
|
|
1622
|
+
];
|
|
1623
|
+
|
|
1573
1624
|
this.onToggle = (_event, isOpen) => {
|
|
1574
1625
|
this.setState({
|
|
1575
1626
|
isOpen
|
|
1576
1627
|
});
|
|
1577
1628
|
};
|
|
1578
1629
|
|
|
1579
|
-
this.onSelect = (event, selection
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1630
|
+
this.onSelect = (event, selection) => {
|
|
1631
|
+
this.setState({ selected: selection, isOpen: false }), console.log('selected: ', selection);
|
|
1632
|
+
};
|
|
1633
|
+
|
|
1634
|
+
this.onFilter = (_, textInput) => {
|
|
1635
|
+
if (textInput === '') {
|
|
1636
|
+
return this.options;
|
|
1637
|
+
} else {
|
|
1638
|
+
let filteredGroups = this.options
|
|
1639
|
+
.map(group => {
|
|
1640
|
+
let filteredGroup = React.cloneElement(group, {
|
|
1641
|
+
children: group.props.children.filter(item => {
|
|
1642
|
+
return item.props.value.toLowerCase().includes(textInput.toLowerCase());
|
|
1643
|
+
})
|
|
1644
|
+
});
|
|
1645
|
+
if (filteredGroup.props.children.length > 0) return filteredGroup;
|
|
1646
|
+
})
|
|
1647
|
+
.filter(Boolean);
|
|
1648
|
+
return filteredGroups;
|
|
1587
1649
|
}
|
|
1588
1650
|
};
|
|
1589
1651
|
|
|
1590
|
-
this.
|
|
1652
|
+
this.toggleCreatable = (_, checked) => {
|
|
1591
1653
|
this.setState({
|
|
1592
|
-
|
|
1593
|
-
isOpen: false
|
|
1654
|
+
isCreatable: checked
|
|
1594
1655
|
});
|
|
1595
1656
|
};
|
|
1596
1657
|
|
|
1597
|
-
this.
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
}
|
|
1658
|
+
this.toggleInputValuePersisted = (_, checked) => {
|
|
1659
|
+
this.setState({
|
|
1660
|
+
isInputValuePersisted: checked
|
|
1661
|
+
});
|
|
1662
|
+
};
|
|
1601
1663
|
|
|
1602
|
-
|
|
1603
|
-
|
|
1664
|
+
this.toggleInputFilterPersisted = (_, checked) => {
|
|
1665
|
+
this.setState({
|
|
1666
|
+
isInputFilterPersisted: checked
|
|
1667
|
+
});
|
|
1604
1668
|
};
|
|
1605
1669
|
}
|
|
1606
1670
|
|
|
1607
1671
|
render() {
|
|
1608
|
-
const {
|
|
1609
|
-
|
|
1672
|
+
const {
|
|
1673
|
+
isOpen,
|
|
1674
|
+
selected,
|
|
1675
|
+
filteredOptions,
|
|
1676
|
+
isInputValuePersisted,
|
|
1677
|
+
isInputFilterPersisted,
|
|
1678
|
+
isCreatable
|
|
1679
|
+
} = this.state;
|
|
1680
|
+
const titleId = 'single-filtering-select-id';
|
|
1610
1681
|
return (
|
|
1611
1682
|
<div>
|
|
1612
1683
|
<span id={titleId} hidden>
|
|
1613
|
-
|
|
1684
|
+
Single select with filter
|
|
1614
1685
|
</span>
|
|
1615
1686
|
<Select
|
|
1616
|
-
variant={SelectVariant.
|
|
1617
|
-
typeAheadAriaLabel="Select a state"
|
|
1687
|
+
variant={SelectVariant.single}
|
|
1618
1688
|
onToggle={this.onToggle}
|
|
1619
1689
|
onSelect={this.onSelect}
|
|
1620
|
-
onClear={this.clearSelection}
|
|
1621
|
-
onFilter={this.customFilter}
|
|
1622
1690
|
selections={selected}
|
|
1623
1691
|
isOpen={isOpen}
|
|
1692
|
+
placeholderText="Filter by status"
|
|
1624
1693
|
aria-labelledby={titleId}
|
|
1625
|
-
|
|
1694
|
+
onFilter={this.onFilter}
|
|
1695
|
+
isGrouped
|
|
1696
|
+
hasInlineFilter
|
|
1697
|
+
isCreatable={isCreatable}
|
|
1698
|
+
isInputValuePersisted={isInputValuePersisted}
|
|
1699
|
+
isInputFilterPersisted={isInputFilterPersisted}
|
|
1626
1700
|
>
|
|
1627
1701
|
{this.options}
|
|
1628
1702
|
</Select>
|
|
1703
|
+
<Checkbox
|
|
1704
|
+
label="isInputValuePersisted"
|
|
1705
|
+
isChecked={isInputValuePersisted}
|
|
1706
|
+
onChange={this.toggleInputValuePersisted}
|
|
1707
|
+
aria-label="toggle input value persisted"
|
|
1708
|
+
id="toggle-inline-filter-input-value-persisted"
|
|
1709
|
+
name="toggle-inline-filter-input-value-persisted"
|
|
1710
|
+
/>
|
|
1711
|
+
<Checkbox
|
|
1712
|
+
label="isInputFilterPersisted"
|
|
1713
|
+
isChecked={isInputFilterPersisted}
|
|
1714
|
+
onChange={this.toggleInputFilterPersisted}
|
|
1715
|
+
aria-label="toggle input filter persisted"
|
|
1716
|
+
id="toggle-inline-filter-input-filter-persisted"
|
|
1717
|
+
name="toggle-inline-filter-input-filter-persisted"
|
|
1718
|
+
/>
|
|
1719
|
+
<Checkbox
|
|
1720
|
+
label="isCreatable"
|
|
1721
|
+
isChecked={this.state.isCreatable}
|
|
1722
|
+
onChange={this.toggleCreatable}
|
|
1723
|
+
aria-label="toggle creatable checkbox"
|
|
1724
|
+
id="toggle-inline-filter-creatable-typeahead"
|
|
1725
|
+
name="toggle-inline-filter-creatable-typeahead"
|
|
1726
|
+
/>
|
|
1629
1727
|
</div>
|
|
1630
1728
|
);
|
|
1631
1729
|
}
|
|
1632
1730
|
}
|
|
1633
1731
|
```
|
|
1634
1732
|
|
|
1635
|
-
###
|
|
1733
|
+
### Typeahead
|
|
1734
|
+
|
|
1735
|
+
Typeahead is a select variant that replaces the typical button toggle for opening the select menu with a text input and button toggle combo. As a user types in the text input, the select menu will provide suggestions by filtering the select options.
|
|
1736
|
+
|
|
1737
|
+
To make a typeahead, pass `variant=typeahead` into the `<Select>` component. To specify a label for the input field, use the `typeAheadAriaLabel` property.
|
|
1738
|
+
|
|
1739
|
+
A few additional customization options are shown in the example below. Select each checkbox to visualize the following behavior:
|
|
1740
|
+
|
|
1741
|
+
- To place a created item at the top of a typeahead list use the `isCreateOptionOnTop` property.
|
|
1742
|
+
- To trigger a callback for newly created items, use the `onCreateOption` property.
|
|
1743
|
+
- To reset the typeahead value after a user makes a selection, use the `shouldResetOnSelect` property.
|
|
1636
1744
|
|
|
1637
1745
|
```js
|
|
1638
1746
|
import React from 'react';
|
|
1639
1747
|
import { Checkbox, Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
1640
1748
|
|
|
1641
|
-
class
|
|
1749
|
+
class TypeaheadSelectInput extends React.Component {
|
|
1642
1750
|
constructor(props) {
|
|
1643
1751
|
super(props);
|
|
1752
|
+
this.defaultOptions = [
|
|
1753
|
+
{ value: 'Alabama' },
|
|
1754
|
+
{ value: 'Florida', description: 'This is a description' },
|
|
1755
|
+
{ value: 'New Jersey' },
|
|
1756
|
+
{ value: 'New Mexico' },
|
|
1757
|
+
{ value: 'New York' },
|
|
1758
|
+
{ value: 'North Carolina' }
|
|
1759
|
+
];
|
|
1644
1760
|
|
|
1645
1761
|
this.state = {
|
|
1646
|
-
options:
|
|
1647
|
-
{ value: 'Alabama', disabled: false },
|
|
1648
|
-
{ value: 'Florida', disabled: false },
|
|
1649
|
-
{ value: 'New Jersey', disabled: false },
|
|
1650
|
-
{ value: 'New Mexico', disabled: false, description: 'This is a description' },
|
|
1651
|
-
{ value: 'New York', disabled: false },
|
|
1652
|
-
{ value: 'North Carolina', disabled: false }
|
|
1653
|
-
],
|
|
1762
|
+
options: this.defaultOptions,
|
|
1654
1763
|
isOpen: false,
|
|
1655
|
-
selected:
|
|
1764
|
+
selected: null,
|
|
1765
|
+
isDisabled: false,
|
|
1656
1766
|
isCreatable: false,
|
|
1767
|
+
isCreateOptionOnTop: false,
|
|
1768
|
+
isInputValuePersisted: false,
|
|
1769
|
+
isInputFilterPersisted: false,
|
|
1657
1770
|
hasOnCreateOption: false,
|
|
1658
|
-
hasDisabledOption: false,
|
|
1659
1771
|
resetOnSelect: true
|
|
1660
1772
|
};
|
|
1661
1773
|
|
|
1662
|
-
this.onCreateOption = newValue => {
|
|
1663
|
-
this.setState({
|
|
1664
|
-
options: [...this.state.options, { value: newValue }]
|
|
1665
|
-
});
|
|
1666
|
-
};
|
|
1667
|
-
|
|
1668
1774
|
this.onToggle = (_event, isOpen) => {
|
|
1669
1775
|
this.setState({
|
|
1670
1776
|
isOpen
|
|
1671
1777
|
});
|
|
1672
1778
|
};
|
|
1673
1779
|
|
|
1674
|
-
this.onSelect = (event, selection) => {
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
this.setState(
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
);
|
|
1681
|
-
|
|
1682
|
-
this.setState(
|
|
1683
|
-
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
1684
|
-
() => console.log('selections: ', this.state.selected)
|
|
1685
|
-
);
|
|
1780
|
+
this.onSelect = (event, selection, isPlaceholder) => {
|
|
1781
|
+
if (isPlaceholder) this.clearSelection();
|
|
1782
|
+
else {
|
|
1783
|
+
this.setState({
|
|
1784
|
+
selected: selection,
|
|
1785
|
+
isOpen: this.state.resetOnSelect ? false : this.state.isOpen
|
|
1786
|
+
});
|
|
1787
|
+
console.log('selected:', selection);
|
|
1686
1788
|
}
|
|
1687
1789
|
};
|
|
1688
1790
|
|
|
1791
|
+
this.onCreateOption = newValue => {
|
|
1792
|
+
this.setState({
|
|
1793
|
+
options: [...this.state.options, { value: newValue }]
|
|
1794
|
+
});
|
|
1795
|
+
};
|
|
1796
|
+
|
|
1689
1797
|
this.clearSelection = () => {
|
|
1690
1798
|
this.setState({
|
|
1691
|
-
selected:
|
|
1692
|
-
isOpen: false
|
|
1799
|
+
selected: null,
|
|
1800
|
+
isOpen: false,
|
|
1801
|
+
options: this.defaultOptions
|
|
1802
|
+
});
|
|
1803
|
+
};
|
|
1804
|
+
|
|
1805
|
+
this.toggleDisabled = checked => {
|
|
1806
|
+
this.setState({
|
|
1807
|
+
isDisabled: checked
|
|
1693
1808
|
});
|
|
1694
1809
|
};
|
|
1695
1810
|
|
|
@@ -1699,39 +1814,58 @@ class MultiTypeaheadSelectInput extends React.Component {
|
|
|
1699
1814
|
});
|
|
1700
1815
|
};
|
|
1701
1816
|
|
|
1702
|
-
this.
|
|
1817
|
+
this.toggleCreateOptionOnTop = checked => {
|
|
1703
1818
|
this.setState({
|
|
1704
|
-
|
|
1819
|
+
isCreateOptionOnTop: checked
|
|
1705
1820
|
});
|
|
1706
1821
|
};
|
|
1707
1822
|
|
|
1708
|
-
this.
|
|
1709
|
-
this.setState(
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
index === toggleIndex ? { ...option, disabled: !option.disabled } : option
|
|
1713
|
-
)
|
|
1714
|
-
}));
|
|
1823
|
+
this.toggleCreateNew = checked => {
|
|
1824
|
+
this.setState({
|
|
1825
|
+
hasOnCreateOption: checked
|
|
1826
|
+
});
|
|
1715
1827
|
};
|
|
1716
1828
|
|
|
1717
|
-
this.
|
|
1829
|
+
this.toggleInputValuePersisted = checked => {
|
|
1718
1830
|
this.setState({
|
|
1719
|
-
|
|
1831
|
+
isInputValuePersisted: checked
|
|
1832
|
+
});
|
|
1833
|
+
};
|
|
1834
|
+
|
|
1835
|
+
this.toggleInputFilterPersisted = checked => {
|
|
1836
|
+
this.setState({
|
|
1837
|
+
isInputFilterPersisted: checked
|
|
1838
|
+
});
|
|
1839
|
+
};
|
|
1840
|
+
|
|
1841
|
+
this.toggleResetOnSelect = checked => {
|
|
1842
|
+
this.setState({
|
|
1843
|
+
resetOnSelect: checked
|
|
1720
1844
|
});
|
|
1721
1845
|
};
|
|
1722
1846
|
}
|
|
1723
1847
|
|
|
1724
1848
|
render() {
|
|
1725
|
-
const {
|
|
1726
|
-
|
|
1727
|
-
|
|
1849
|
+
const {
|
|
1850
|
+
isOpen,
|
|
1851
|
+
selected,
|
|
1852
|
+
isDisabled,
|
|
1853
|
+
isCreatable,
|
|
1854
|
+
isCreateOptionOnTop,
|
|
1855
|
+
hasOnCreateOption,
|
|
1856
|
+
isInputValuePersisted,
|
|
1857
|
+
isInputFilterPersisted,
|
|
1858
|
+
resetOnSelect,
|
|
1859
|
+
options
|
|
1860
|
+
} = this.state;
|
|
1861
|
+
const titleId = 'typeahead-select-id-1';
|
|
1728
1862
|
return (
|
|
1729
1863
|
<div>
|
|
1730
1864
|
<span id={titleId} hidden>
|
|
1731
1865
|
Select a state
|
|
1732
1866
|
</span>
|
|
1733
1867
|
<Select
|
|
1734
|
-
variant={SelectVariant.
|
|
1868
|
+
variant={SelectVariant.typeahead}
|
|
1735
1869
|
typeAheadAriaLabel="Select a state"
|
|
1736
1870
|
onToggle={this.onToggle}
|
|
1737
1871
|
onSelect={this.onSelect}
|
|
@@ -1739,8 +1873,12 @@ class MultiTypeaheadSelectInput extends React.Component {
|
|
|
1739
1873
|
selections={selected}
|
|
1740
1874
|
isOpen={isOpen}
|
|
1741
1875
|
aria-labelledby={titleId}
|
|
1876
|
+
isInputValuePersisted={isInputValuePersisted}
|
|
1877
|
+
isInputFilterPersisted={isInputFilterPersisted}
|
|
1742
1878
|
placeholderText="Select a state"
|
|
1879
|
+
isDisabled={isDisabled}
|
|
1743
1880
|
isCreatable={isCreatable}
|
|
1881
|
+
isCreateOptionOnTop={isCreateOptionOnTop}
|
|
1744
1882
|
onCreateOption={(hasOnCreateOption && this.onCreateOption) || undefined}
|
|
1745
1883
|
shouldResetOnSelect={resetOnSelect}
|
|
1746
1884
|
>
|
|
@@ -1753,37 +1891,61 @@ class MultiTypeaheadSelectInput extends React.Component {
|
|
|
1753
1891
|
/>
|
|
1754
1892
|
))}
|
|
1755
1893
|
</Select>
|
|
1894
|
+
<Checkbox
|
|
1895
|
+
label="isDisabled"
|
|
1896
|
+
isChecked={this.state.isDisabled}
|
|
1897
|
+
onChange={(_event, checked) => this.toggleDisabled(checked)}
|
|
1898
|
+
aria-label="toggle disabled checkbox"
|
|
1899
|
+
id="toggle-disabled-typeahead"
|
|
1900
|
+
name="toggle-disabled-typeahead"
|
|
1901
|
+
/>
|
|
1756
1902
|
<Checkbox
|
|
1757
1903
|
label="isCreatable"
|
|
1758
1904
|
isChecked={this.state.isCreatable}
|
|
1759
1905
|
onChange={(_event, checked) => this.toggleCreatable(checked)}
|
|
1760
1906
|
aria-label="toggle creatable checkbox"
|
|
1761
|
-
id="toggle-creatable-typeahead
|
|
1762
|
-
name="toggle-creatable-typeahead
|
|
1907
|
+
id="toggle-creatable-typeahead"
|
|
1908
|
+
name="toggle-creatable-typeahead"
|
|
1909
|
+
/>
|
|
1910
|
+
<Checkbox
|
|
1911
|
+
label="isCreateOptionOnTop"
|
|
1912
|
+
isChecked={this.state.isCreateOptionOnTop}
|
|
1913
|
+
onChange={(_event, checked) => this.toggleCreateOptionOnTop(checked)}
|
|
1914
|
+
aria-label="toggle createOptionOnTop checkbox"
|
|
1915
|
+
id="toggle-create-option-on-top-typeahead"
|
|
1916
|
+
name="toggle-create-option-on-top-typeahead"
|
|
1763
1917
|
/>
|
|
1764
1918
|
<Checkbox
|
|
1765
1919
|
label="onCreateOption"
|
|
1766
1920
|
isChecked={this.state.hasOnCreateOption}
|
|
1767
1921
|
onChange={(_event, checked) => this.toggleCreateNew(checked)}
|
|
1768
1922
|
aria-label="toggle new checkbox"
|
|
1769
|
-
id="toggle-new-typeahead
|
|
1770
|
-
name="toggle-new-typeahead
|
|
1923
|
+
id="toggle-new-typeahead"
|
|
1924
|
+
name="toggle-new-typeahead"
|
|
1771
1925
|
/>
|
|
1772
1926
|
<Checkbox
|
|
1773
|
-
label="
|
|
1774
|
-
isChecked={
|
|
1775
|
-
onChange={this.
|
|
1776
|
-
aria-label="toggle
|
|
1777
|
-
id="toggle-
|
|
1778
|
-
name="toggle-
|
|
1927
|
+
label="isInputValuePersisted"
|
|
1928
|
+
isChecked={isInputValuePersisted}
|
|
1929
|
+
onChange={(_event, checked) => this.toggleInputValuePersisted(checked)}
|
|
1930
|
+
aria-label="toggle input value persisted"
|
|
1931
|
+
id="toggle-input-value-persisted"
|
|
1932
|
+
name="toggle-input-value-persisted"
|
|
1933
|
+
/>
|
|
1934
|
+
<Checkbox
|
|
1935
|
+
label="isInputFilterPersisted"
|
|
1936
|
+
isChecked={isInputFilterPersisted}
|
|
1937
|
+
onChange={(_event, checked) => this.toggleInputFilterPersisted(checked)}
|
|
1938
|
+
aria-label="toggle input filter persisted"
|
|
1939
|
+
id="toggle-input-filter-persisted"
|
|
1940
|
+
name="toggle-input-filter-persisted"
|
|
1779
1941
|
/>
|
|
1780
1942
|
<Checkbox
|
|
1781
1943
|
label="shouldResetOnSelect"
|
|
1782
1944
|
isChecked={this.state.resetOnSelect}
|
|
1783
1945
|
onChange={(_event, checked) => this.toggleResetOnSelect(checked)}
|
|
1784
|
-
aria-label="toggle
|
|
1785
|
-
id="toggle-reset-
|
|
1786
|
-
name="toggle-reset-
|
|
1946
|
+
aria-label="toggle reset checkbox"
|
|
1947
|
+
id="toggle-reset-typeahead"
|
|
1948
|
+
name="toggle-reset-typeahead"
|
|
1787
1949
|
/>
|
|
1788
1950
|
</div>
|
|
1789
1951
|
);
|
|
@@ -1791,27 +1953,39 @@ class MultiTypeaheadSelectInput extends React.Component {
|
|
|
1791
1953
|
}
|
|
1792
1954
|
```
|
|
1793
1955
|
|
|
1794
|
-
###
|
|
1956
|
+
### Grouped typeahead
|
|
1957
|
+
|
|
1958
|
+
Typeahead matches items with user input across groups.
|
|
1795
1959
|
|
|
1796
1960
|
```js
|
|
1797
1961
|
import React from 'react';
|
|
1798
|
-
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
1962
|
+
import { Checkbox, Select, SelectGroup, SelectOption, SelectVariant, Divider } from '@patternfly/react-core';
|
|
1799
1963
|
|
|
1800
|
-
class
|
|
1964
|
+
class GroupedTypeaheadSelectInput extends React.Component {
|
|
1801
1965
|
constructor(props) {
|
|
1802
1966
|
super(props);
|
|
1803
1967
|
|
|
1804
1968
|
this.state = {
|
|
1805
1969
|
options: [
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1970
|
+
<SelectGroup label="Status" key="group1">
|
|
1971
|
+
<SelectOption key={0} value="Running" />
|
|
1972
|
+
<SelectOption key={1} value="Stopped" />
|
|
1973
|
+
<SelectOption key={2} value="Down" />
|
|
1974
|
+
<SelectOption key={3} value="Degraded" />
|
|
1975
|
+
<SelectOption key={4} value="Needs maintenance" />
|
|
1976
|
+
</SelectGroup>,
|
|
1977
|
+
<Divider key="divider" />,
|
|
1978
|
+
<SelectGroup label="Vendor names" key="group2">
|
|
1979
|
+
<SelectOption key={5} value="Dell" />
|
|
1980
|
+
<SelectOption key={6} value="Samsung" isDisabled />
|
|
1981
|
+
<SelectOption key={7} value="Hewlett-Packard" />
|
|
1982
|
+
</SelectGroup>
|
|
1812
1983
|
],
|
|
1984
|
+
newOptions: [],
|
|
1813
1985
|
isOpen: false,
|
|
1814
|
-
selected:
|
|
1986
|
+
selected: null,
|
|
1987
|
+
isCreatable: false,
|
|
1988
|
+
hasOnCreateOption: false
|
|
1815
1989
|
};
|
|
1816
1990
|
|
|
1817
1991
|
this.onToggle = (_event, isOpen) => {
|
|
@@ -1820,41 +1994,61 @@ class MultiTypeaheadSelectInputWithChipGroupProps extends React.Component {
|
|
|
1820
1994
|
});
|
|
1821
1995
|
};
|
|
1822
1996
|
|
|
1823
|
-
this.onSelect = (event, selection) => {
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
this.setState(
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
);
|
|
1830
|
-
|
|
1831
|
-
this.setState(
|
|
1832
|
-
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
1833
|
-
() => console.log('selections: ', this.state.selected)
|
|
1834
|
-
);
|
|
1997
|
+
this.onSelect = (event, selection, isPlaceholder) => {
|
|
1998
|
+
if (isPlaceholder) this.clearSelection();
|
|
1999
|
+
else {
|
|
2000
|
+
this.setState({
|
|
2001
|
+
selected: selection,
|
|
2002
|
+
isOpen: false
|
|
2003
|
+
});
|
|
2004
|
+
console.log('selected:', selection);
|
|
1835
2005
|
}
|
|
1836
2006
|
};
|
|
1837
2007
|
|
|
2008
|
+
this.onCreateOption = newValue => {
|
|
2009
|
+
this.setState({
|
|
2010
|
+
newOptions: [...this.state.newOptions, <SelectOption key={newValue} value={newValue} />]
|
|
2011
|
+
});
|
|
2012
|
+
};
|
|
2013
|
+
|
|
1838
2014
|
this.clearSelection = () => {
|
|
1839
2015
|
this.setState({
|
|
1840
|
-
selected:
|
|
2016
|
+
selected: null,
|
|
1841
2017
|
isOpen: false
|
|
1842
2018
|
});
|
|
1843
2019
|
};
|
|
2020
|
+
|
|
2021
|
+
this.toggleCreatable = checked => {
|
|
2022
|
+
this.setState({
|
|
2023
|
+
isCreatable: checked
|
|
2024
|
+
});
|
|
2025
|
+
};
|
|
2026
|
+
|
|
2027
|
+
this.toggleCreateNew = checked => {
|
|
2028
|
+
this.setState({
|
|
2029
|
+
hasOnCreateOption: checked
|
|
2030
|
+
});
|
|
2031
|
+
};
|
|
1844
2032
|
}
|
|
1845
2033
|
|
|
1846
2034
|
render() {
|
|
1847
|
-
const { isOpen, selected, isCreatable, hasOnCreateOption } = this.state;
|
|
1848
|
-
const titleId = '
|
|
1849
|
-
|
|
2035
|
+
const { isOpen, selected, isDisabled, isCreatable, hasOnCreateOption, options, newOptions } = this.state;
|
|
2036
|
+
const titleId = 'grouped-typeahead-select-id';
|
|
2037
|
+
const allOptions =
|
|
2038
|
+
newOptions.length > 0
|
|
2039
|
+
? options.concat(
|
|
2040
|
+
<SelectGroup label="Created" key="create-group">
|
|
2041
|
+
{newOptions}
|
|
2042
|
+
</SelectGroup>
|
|
2043
|
+
)
|
|
2044
|
+
: options;
|
|
1850
2045
|
return (
|
|
1851
2046
|
<div>
|
|
1852
2047
|
<span id={titleId} hidden>
|
|
1853
2048
|
Select a state
|
|
1854
2049
|
</span>
|
|
1855
2050
|
<Select
|
|
1856
|
-
|
|
1857
|
-
variant={SelectVariant.typeaheadMulti}
|
|
2051
|
+
variant={SelectVariant.typeahead}
|
|
1858
2052
|
typeAheadAriaLabel="Select a state"
|
|
1859
2053
|
onToggle={this.onToggle}
|
|
1860
2054
|
onSelect={this.onSelect}
|
|
@@ -1863,43 +2057,56 @@ class MultiTypeaheadSelectInputWithChipGroupProps extends React.Component {
|
|
|
1863
2057
|
isOpen={isOpen}
|
|
1864
2058
|
aria-labelledby={titleId}
|
|
1865
2059
|
placeholderText="Select a state"
|
|
2060
|
+
isGrouped
|
|
2061
|
+
isCreatable={isCreatable}
|
|
2062
|
+
onCreateOption={(hasOnCreateOption && this.onCreateOption) || undefined}
|
|
1866
2063
|
>
|
|
1867
|
-
{
|
|
1868
|
-
<SelectOption
|
|
1869
|
-
isDisabled={option.disabled}
|
|
1870
|
-
key={index}
|
|
1871
|
-
value={option.value}
|
|
1872
|
-
{...(option.description && { description: option.description })}
|
|
1873
|
-
/>
|
|
1874
|
-
))}
|
|
2064
|
+
{allOptions}
|
|
1875
2065
|
</Select>
|
|
2066
|
+
<Checkbox
|
|
2067
|
+
label="isCreatable"
|
|
2068
|
+
isChecked={this.state.isCreatable}
|
|
2069
|
+
onChange={(_event, checked) => this.toggleCreatable(checked)}
|
|
2070
|
+
aria-label="toggle creatable checkbox"
|
|
2071
|
+
id="toggle-creatable-grouped-typeahead"
|
|
2072
|
+
name="toggle-creatable-grouped-typeahead"
|
|
2073
|
+
/>
|
|
2074
|
+
<Checkbox
|
|
2075
|
+
label="onCreateOption"
|
|
2076
|
+
isChecked={this.state.hasOnCreateOption}
|
|
2077
|
+
onChange={(_event, checked) => this.toggleCreateNew(checked)}
|
|
2078
|
+
aria-label="toggle new checkbox"
|
|
2079
|
+
id="toggle-new-grouped-typeahead"
|
|
2080
|
+
name="toggle-new-grouped-typeahead"
|
|
2081
|
+
/>
|
|
1876
2082
|
</div>
|
|
1877
2083
|
);
|
|
1878
2084
|
}
|
|
1879
2085
|
}
|
|
1880
2086
|
```
|
|
1881
2087
|
|
|
1882
|
-
###
|
|
2088
|
+
### Typeahead with custom filtering
|
|
2089
|
+
|
|
2090
|
+
You can add custom filtering to a select list to better fit needs that aren't covered by inline filtering. If you use custom filtering, use the `onFilter` property to trigger a callback with your custom filter implementation.
|
|
1883
2091
|
|
|
1884
2092
|
```js
|
|
1885
2093
|
import React from 'react';
|
|
1886
|
-
import { Select, SelectOption, SelectVariant
|
|
2094
|
+
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
1887
2095
|
|
|
1888
|
-
class
|
|
2096
|
+
class TypeaheadSelectInput extends React.Component {
|
|
1889
2097
|
constructor(props) {
|
|
1890
2098
|
super(props);
|
|
1891
|
-
|
|
2099
|
+
this.options = [
|
|
2100
|
+
<SelectOption key={0} value="Alabama" />,
|
|
2101
|
+
<SelectOption key={1} value="Florida" />,
|
|
2102
|
+
<SelectOption key={2} value="New Jersey" />,
|
|
2103
|
+
<SelectOption key={3} value="New Mexico" />,
|
|
2104
|
+
<SelectOption key={4} value="New York" />,
|
|
2105
|
+
<SelectOption key={5} value="North Carolina" />
|
|
2106
|
+
];
|
|
1892
2107
|
this.state = {
|
|
1893
|
-
options: [
|
|
1894
|
-
{ value: 'Alabama', disabled: false },
|
|
1895
|
-
{ value: 'Florida', disabled: false },
|
|
1896
|
-
{ value: 'New Jersey', disabled: false },
|
|
1897
|
-
{ value: 'New Mexico', disabled: false, description: 'This is a description' },
|
|
1898
|
-
{ value: 'New York', disabled: false },
|
|
1899
|
-
{ value: 'North Carolina', disabled: false }
|
|
1900
|
-
],
|
|
1901
2108
|
isOpen: false,
|
|
1902
|
-
selected:
|
|
2109
|
+
selected: null
|
|
1903
2110
|
};
|
|
1904
2111
|
|
|
1905
2112
|
this.onToggle = (_event, isOpen) => {
|
|
@@ -1908,75 +2115,55 @@ class MultiTypeaheadSelectInputWithChipGroupProps extends React.Component {
|
|
|
1908
2115
|
});
|
|
1909
2116
|
};
|
|
1910
2117
|
|
|
1911
|
-
this.onSelect = (event, selection) => {
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
this.setState(
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
);
|
|
1918
|
-
|
|
1919
|
-
this.setState(
|
|
1920
|
-
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
1921
|
-
() => console.log('selections: ', this.state.selected)
|
|
1922
|
-
);
|
|
2118
|
+
this.onSelect = (event, selection, isPlaceholder) => {
|
|
2119
|
+
if (isPlaceholder) this.clearSelection();
|
|
2120
|
+
else {
|
|
2121
|
+
this.setState({
|
|
2122
|
+
selected: selection,
|
|
2123
|
+
isOpen: false
|
|
2124
|
+
});
|
|
2125
|
+
console.log('selected:', selection);
|
|
1923
2126
|
}
|
|
1924
2127
|
};
|
|
1925
2128
|
|
|
1926
2129
|
this.clearSelection = () => {
|
|
1927
2130
|
this.setState({
|
|
1928
|
-
selected:
|
|
2131
|
+
selected: null,
|
|
1929
2132
|
isOpen: false
|
|
1930
2133
|
});
|
|
1931
2134
|
};
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
onClick={event => this.onSelect(event, currentChip)}
|
|
1941
|
-
>
|
|
1942
|
-
{currentChip}
|
|
1943
|
-
</Chip>
|
|
1944
|
-
))}
|
|
1945
|
-
</ChipGroup>
|
|
1946
|
-
);
|
|
2135
|
+
|
|
2136
|
+
this.customFilter = (_, value) => {
|
|
2137
|
+
if (!value) {
|
|
2138
|
+
return this.options;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
const input = new RegExp(value, 'i');
|
|
2142
|
+
return this.options.filter(child => input.test(child.props.value));
|
|
1947
2143
|
};
|
|
1948
2144
|
}
|
|
1949
2145
|
|
|
1950
2146
|
render() {
|
|
1951
|
-
const { isOpen, selected
|
|
1952
|
-
const titleId = '
|
|
1953
|
-
|
|
2147
|
+
const { isOpen, selected } = this.state;
|
|
2148
|
+
const titleId = 'typeahead-select-id-2';
|
|
1954
2149
|
return (
|
|
1955
2150
|
<div>
|
|
1956
2151
|
<span id={titleId} hidden>
|
|
1957
2152
|
Select a state
|
|
1958
2153
|
</span>
|
|
1959
2154
|
<Select
|
|
1960
|
-
|
|
1961
|
-
variant={SelectVariant.typeaheadMulti}
|
|
2155
|
+
variant={SelectVariant.typeahead}
|
|
1962
2156
|
typeAheadAriaLabel="Select a state"
|
|
1963
2157
|
onToggle={this.onToggle}
|
|
1964
2158
|
onSelect={this.onSelect}
|
|
1965
2159
|
onClear={this.clearSelection}
|
|
2160
|
+
onFilter={this.customFilter}
|
|
1966
2161
|
selections={selected}
|
|
1967
2162
|
isOpen={isOpen}
|
|
1968
2163
|
aria-labelledby={titleId}
|
|
1969
2164
|
placeholderText="Select a state"
|
|
1970
|
-
chipGroupComponent={this.chipGroupComponent()}
|
|
1971
2165
|
>
|
|
1972
|
-
{this.
|
|
1973
|
-
<SelectOption
|
|
1974
|
-
isDisabled={option.disabled}
|
|
1975
|
-
key={index}
|
|
1976
|
-
value={option.value}
|
|
1977
|
-
{...(option.description && { description: option.description })}
|
|
1978
|
-
/>
|
|
1979
|
-
))}
|
|
2166
|
+
{this.options}
|
|
1980
2167
|
</Select>
|
|
1981
2168
|
</div>
|
|
1982
2169
|
);
|
|
@@ -1984,44 +2171,41 @@ class MultiTypeaheadSelectInputWithChipGroupProps extends React.Component {
|
|
|
1984
2171
|
}
|
|
1985
2172
|
```
|
|
1986
2173
|
|
|
1987
|
-
### Multiple
|
|
2174
|
+
### Multiple typeahead
|
|
2175
|
+
|
|
2176
|
+
To create a multiple typeahead select variant, pass `variant={SelectVariant.typeaheadMulti}` into the `<Select>` component. Multiple typeaheads let users select multiple items from a select list. Selected items appear as chips in the select toggle.
|
|
2177
|
+
|
|
2178
|
+
When many items are selected, you can hide overflowing items under a "more" button. The following example hides items after more than 3 are selected. To show hidden items, select the “more” button. Click "show less" to hide extra items again.
|
|
1988
2179
|
|
|
1989
2180
|
```js
|
|
1990
2181
|
import React from 'react';
|
|
1991
|
-
import { Select, SelectOption, SelectVariant
|
|
2182
|
+
import { Checkbox, Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
1992
2183
|
|
|
1993
|
-
class
|
|
2184
|
+
class MultiTypeaheadSelectInput extends React.Component {
|
|
1994
2185
|
constructor(props) {
|
|
1995
2186
|
super(props);
|
|
1996
|
-
this.createState = (name, abbreviation, capital, founded) => {
|
|
1997
|
-
return {
|
|
1998
|
-
name: name,
|
|
1999
|
-
abbreviation: abbreviation,
|
|
2000
|
-
capital: capital,
|
|
2001
|
-
founded: founded,
|
|
2002
|
-
toString: function() {
|
|
2003
|
-
return `${this.name} (${this.abbreviation}) - Founded: ${this.founded}`;
|
|
2004
|
-
},
|
|
2005
|
-
compareTo: function(value) {
|
|
2006
|
-
return this.toString()
|
|
2007
|
-
.toLowerCase()
|
|
2008
|
-
.includes(value.toString().toLowerCase());
|
|
2009
|
-
}
|
|
2010
|
-
};
|
|
2011
|
-
};
|
|
2012
|
-
this.options = [
|
|
2013
|
-
<SelectOption key={0} value={this.createState('Alabama', 'AL', 'Montgomery', 1846)} />,
|
|
2014
|
-
<Divider component="li" key={111} />,
|
|
2015
|
-
<SelectOption key={1} value={this.createState('Florida', 'FL', 'Tailahassee', 1845)} />,
|
|
2016
|
-
<SelectOption key={2} value={this.createState('New Jersey', 'NJ', 'Trenton', 1787)} />,
|
|
2017
|
-
<SelectOption key={3} value={this.createState('New Mexico', 'NM', 'Santa Fe', 1912)} />,
|
|
2018
|
-
<SelectOption key={4} value={this.createState('New York', 'NY', 'Albany', 1788)} />,
|
|
2019
|
-
<SelectOption key={5} value={this.createState('North Carolina', 'NC', 'Raleigh', 1789)} />
|
|
2020
|
-
];
|
|
2021
2187
|
|
|
2022
2188
|
this.state = {
|
|
2189
|
+
options: [
|
|
2190
|
+
{ value: 'Alabama', disabled: false },
|
|
2191
|
+
{ value: 'Florida', disabled: false },
|
|
2192
|
+
{ value: 'New Jersey', disabled: false },
|
|
2193
|
+
{ value: 'New Mexico', disabled: false, description: 'This is a description' },
|
|
2194
|
+
{ value: 'New York', disabled: false },
|
|
2195
|
+
{ value: 'North Carolina', disabled: false }
|
|
2196
|
+
],
|
|
2023
2197
|
isOpen: false,
|
|
2024
|
-
selected: []
|
|
2198
|
+
selected: [],
|
|
2199
|
+
isCreatable: false,
|
|
2200
|
+
hasOnCreateOption: false,
|
|
2201
|
+
hasDisabledOption: false,
|
|
2202
|
+
resetOnSelect: true
|
|
2203
|
+
};
|
|
2204
|
+
|
|
2205
|
+
this.onCreateOption = newValue => {
|
|
2206
|
+
this.setState({
|
|
2207
|
+
options: [...this.state.options, { value: newValue }]
|
|
2208
|
+
});
|
|
2025
2209
|
};
|
|
2026
2210
|
|
|
2027
2211
|
this.onToggle = (_event, isOpen) => {
|
|
@@ -2051,11 +2235,38 @@ class MultiTypeaheadSelectInputCustomObjects extends React.Component {
|
|
|
2051
2235
|
isOpen: false
|
|
2052
2236
|
});
|
|
2053
2237
|
};
|
|
2238
|
+
|
|
2239
|
+
this.toggleCreatable = checked => {
|
|
2240
|
+
this.setState({
|
|
2241
|
+
isCreatable: checked
|
|
2242
|
+
});
|
|
2243
|
+
};
|
|
2244
|
+
|
|
2245
|
+
this.toggleCreateNew = checked => {
|
|
2246
|
+
this.setState({
|
|
2247
|
+
hasOnCreateOption: checked
|
|
2248
|
+
});
|
|
2249
|
+
};
|
|
2250
|
+
|
|
2251
|
+
this.toggleOptionDisabled = toggleIndex => () => {
|
|
2252
|
+
this.setState(prevState => ({
|
|
2253
|
+
hasDisabledOption: !prevState.hasDisabledOption,
|
|
2254
|
+
options: prevState.options.map((option, index) =>
|
|
2255
|
+
index === toggleIndex ? { ...option, disabled: !option.disabled } : option
|
|
2256
|
+
)
|
|
2257
|
+
}));
|
|
2258
|
+
};
|
|
2259
|
+
|
|
2260
|
+
this.toggleResetOnSelect = checked => {
|
|
2261
|
+
this.setState({
|
|
2262
|
+
resetOnSelect: checked
|
|
2263
|
+
});
|
|
2264
|
+
};
|
|
2054
2265
|
}
|
|
2055
2266
|
|
|
2056
2267
|
render() {
|
|
2057
|
-
const { isOpen, selected } = this.state;
|
|
2058
|
-
const titleId = 'multi-typeahead-select-id-
|
|
2268
|
+
const { isOpen, selected, isCreatable, hasOnCreateOption, resetOnSelect, options } = this.state;
|
|
2269
|
+
const titleId = 'multi-typeahead-select-id-1';
|
|
2059
2270
|
|
|
2060
2271
|
return (
|
|
2061
2272
|
<div>
|
|
@@ -2068,41 +2279,83 @@ class MultiTypeaheadSelectInputCustomObjects extends React.Component {
|
|
|
2068
2279
|
onToggle={this.onToggle}
|
|
2069
2280
|
onSelect={this.onSelect}
|
|
2070
2281
|
onClear={this.clearSelection}
|
|
2071
|
-
onFilter={this.customFilter}
|
|
2072
2282
|
selections={selected}
|
|
2073
2283
|
isOpen={isOpen}
|
|
2074
2284
|
aria-labelledby={titleId}
|
|
2075
2285
|
placeholderText="Select a state"
|
|
2286
|
+
isCreatable={isCreatable}
|
|
2287
|
+
onCreateOption={(hasOnCreateOption && this.onCreateOption) || undefined}
|
|
2288
|
+
shouldResetOnSelect={resetOnSelect}
|
|
2076
2289
|
>
|
|
2077
|
-
{
|
|
2290
|
+
{options.map((option, index) => (
|
|
2291
|
+
<SelectOption
|
|
2292
|
+
isDisabled={option.disabled}
|
|
2293
|
+
key={index}
|
|
2294
|
+
value={option.value}
|
|
2295
|
+
{...(option.description && { description: option.description })}
|
|
2296
|
+
/>
|
|
2297
|
+
))}
|
|
2078
2298
|
</Select>
|
|
2299
|
+
<Checkbox
|
|
2300
|
+
label="isCreatable"
|
|
2301
|
+
isChecked={this.state.isCreatable}
|
|
2302
|
+
onChange={(_event, checked) => this.toggleCreatable(checked)}
|
|
2303
|
+
aria-label="toggle creatable checkbox"
|
|
2304
|
+
id="toggle-creatable-typeahead-multi"
|
|
2305
|
+
name="toggle-creatable-typeahead-multi"
|
|
2306
|
+
/>
|
|
2307
|
+
<Checkbox
|
|
2308
|
+
label="onCreateOption"
|
|
2309
|
+
isChecked={this.state.hasOnCreateOption}
|
|
2310
|
+
onChange={(_event, checked) => this.toggleCreateNew(checked)}
|
|
2311
|
+
aria-label="toggle new checkbox"
|
|
2312
|
+
id="toggle-new-typeahead-multi"
|
|
2313
|
+
name="toggle-new-typeahead-multi"
|
|
2314
|
+
/>
|
|
2315
|
+
<Checkbox
|
|
2316
|
+
label="isDisabled (1st option only)"
|
|
2317
|
+
isChecked={this.state.hasDisabledOption}
|
|
2318
|
+
onChange={this.toggleOptionDisabled(0)}
|
|
2319
|
+
aria-label="toggle disable first option"
|
|
2320
|
+
id="toggle-disable-first-option"
|
|
2321
|
+
name="toggle-disable-first-option"
|
|
2322
|
+
/>
|
|
2323
|
+
<Checkbox
|
|
2324
|
+
label="shouldResetOnSelect"
|
|
2325
|
+
isChecked={this.state.resetOnSelect}
|
|
2326
|
+
onChange={(_event, checked) => this.toggleResetOnSelect(checked)}
|
|
2327
|
+
aria-label="toggle multi reset checkbox"
|
|
2328
|
+
id="toggle-reset-multi-typeahead"
|
|
2329
|
+
name="toggle-reset-multi-typeahead"
|
|
2330
|
+
/>
|
|
2079
2331
|
</div>
|
|
2080
2332
|
);
|
|
2081
2333
|
}
|
|
2082
2334
|
}
|
|
2083
2335
|
```
|
|
2084
2336
|
|
|
2085
|
-
###
|
|
2337
|
+
### Multiple typeahead with custom chips
|
|
2338
|
+
|
|
2339
|
+
To customize the appearance of chips, use the `chipGroupProps` property. The `numChips` property allows you to control the number of items shown, while the `expandedText` and `collapsedText` properties allow you to control the labels of the expansion and collapse chips.
|
|
2086
2340
|
|
|
2087
2341
|
```js
|
|
2088
2342
|
import React from 'react';
|
|
2089
2343
|
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
2090
2344
|
|
|
2091
|
-
class
|
|
2345
|
+
class MultiTypeaheadSelectInputWithChipGroupProps extends React.Component {
|
|
2092
2346
|
constructor(props) {
|
|
2093
2347
|
super(props);
|
|
2094
|
-
this.options = [
|
|
2095
|
-
{ value: 'Alabama', disabled: false },
|
|
2096
|
-
{ value: 'Florida', disabled: false },
|
|
2097
|
-
{ value: 'New Jersey', disabled: false },
|
|
2098
|
-
{ value: 'New Mexico', disabled: false },
|
|
2099
|
-
{ value: 'New York', disabled: false },
|
|
2100
|
-
{ value: 'North Carolina', disabled: false }
|
|
2101
|
-
];
|
|
2102
2348
|
|
|
2103
2349
|
this.state = {
|
|
2350
|
+
options: [
|
|
2351
|
+
{ value: 'Alabama', disabled: false },
|
|
2352
|
+
{ value: 'Florida', disabled: false },
|
|
2353
|
+
{ value: 'New Jersey', disabled: false },
|
|
2354
|
+
{ value: 'New Mexico', disabled: false, description: 'This is a description' },
|
|
2355
|
+
{ value: 'New York', disabled: false },
|
|
2356
|
+
{ value: 'North Carolina', disabled: false }
|
|
2357
|
+
],
|
|
2104
2358
|
isOpen: false,
|
|
2105
|
-
isPlain: true,
|
|
2106
2359
|
selected: []
|
|
2107
2360
|
};
|
|
2108
2361
|
|
|
@@ -2136,8 +2389,8 @@ class PlainSelectInput extends React.Component {
|
|
|
2136
2389
|
}
|
|
2137
2390
|
|
|
2138
2391
|
render() {
|
|
2139
|
-
const { isOpen,
|
|
2140
|
-
const titleId = '
|
|
2392
|
+
const { isOpen, selected, isCreatable, hasOnCreateOption } = this.state;
|
|
2393
|
+
const titleId = 'multi-typeahead-custom-chip-group-props-id-1';
|
|
2141
2394
|
|
|
2142
2395
|
return (
|
|
2143
2396
|
<div>
|
|
@@ -2145,6 +2398,7 @@ class PlainSelectInput extends React.Component {
|
|
|
2145
2398
|
Select a state
|
|
2146
2399
|
</span>
|
|
2147
2400
|
<Select
|
|
2401
|
+
chipGroupProps={{ numChips: 1, expandedText: 'Hide', collapsedText: 'Show ${remaining}' }}
|
|
2148
2402
|
variant={SelectVariant.typeaheadMulti}
|
|
2149
2403
|
typeAheadAriaLabel="Select a state"
|
|
2150
2404
|
onToggle={this.onToggle}
|
|
@@ -2152,12 +2406,16 @@ class PlainSelectInput extends React.Component {
|
|
|
2152
2406
|
onClear={this.clearSelection}
|
|
2153
2407
|
selections={selected}
|
|
2154
2408
|
isOpen={isOpen}
|
|
2155
|
-
isPlain={isPlain}
|
|
2156
2409
|
aria-labelledby={titleId}
|
|
2157
2410
|
placeholderText="Select a state"
|
|
2158
2411
|
>
|
|
2159
|
-
{this.options.map((option, index) => (
|
|
2160
|
-
<SelectOption
|
|
2412
|
+
{this.state.options.map((option, index) => (
|
|
2413
|
+
<SelectOption
|
|
2414
|
+
isDisabled={option.disabled}
|
|
2415
|
+
key={index}
|
|
2416
|
+
value={option.value}
|
|
2417
|
+
{...(option.description && { description: option.description })}
|
|
2418
|
+
/>
|
|
2161
2419
|
))}
|
|
2162
2420
|
</Select>
|
|
2163
2421
|
</div>
|
|
@@ -2166,20 +2424,29 @@ class PlainSelectInput extends React.Component {
|
|
|
2166
2424
|
}
|
|
2167
2425
|
```
|
|
2168
2426
|
|
|
2169
|
-
###
|
|
2427
|
+
### Multiple typeahead with chip group
|
|
2428
|
+
|
|
2429
|
+
To customize chips even more, render a [`<ChipGroup>`](/components/chip-group) component and pass it into the `chipGroupComponent` property of the `<Select>` component.
|
|
2170
2430
|
|
|
2171
2431
|
```js
|
|
2172
2432
|
import React from 'react';
|
|
2173
|
-
import
|
|
2174
|
-
import { Select, SelectOption, SelectDirection, Checkbox } from '@patternfly/react-core';
|
|
2433
|
+
import { Select, SelectOption, SelectVariant, ChipGroup, Chip } from '@patternfly/react-core';
|
|
2175
2434
|
|
|
2176
|
-
class
|
|
2435
|
+
class MultiTypeaheadSelectInputWithChipGroupProps extends React.Component {
|
|
2177
2436
|
constructor(props) {
|
|
2178
2437
|
super(props);
|
|
2438
|
+
|
|
2179
2439
|
this.state = {
|
|
2440
|
+
options: [
|
|
2441
|
+
{ value: 'Alabama', disabled: false },
|
|
2442
|
+
{ value: 'Florida', disabled: false },
|
|
2443
|
+
{ value: 'New Jersey', disabled: false },
|
|
2444
|
+
{ value: 'New Mexico', disabled: false, description: 'This is a description' },
|
|
2445
|
+
{ value: 'New York', disabled: false },
|
|
2446
|
+
{ value: 'North Carolina', disabled: false }
|
|
2447
|
+
],
|
|
2180
2448
|
isOpen: false,
|
|
2181
|
-
|
|
2182
|
-
direction: SelectDirection.down
|
|
2449
|
+
selected: []
|
|
2183
2450
|
};
|
|
2184
2451
|
|
|
2185
2452
|
this.onToggle = (_event, isOpen) => {
|
|
@@ -2188,199 +2455,206 @@ class SingleSelectInput extends React.Component {
|
|
|
2188
2455
|
});
|
|
2189
2456
|
};
|
|
2190
2457
|
|
|
2191
|
-
this.
|
|
2192
|
-
this.
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
if (this.state.direction === SelectDirection.up) {
|
|
2199
|
-
this.setState({
|
|
2200
|
-
direction: SelectDirection.down
|
|
2201
|
-
});
|
|
2458
|
+
this.onSelect = (event, selection) => {
|
|
2459
|
+
const { selected } = this.state;
|
|
2460
|
+
if (selected.includes(selection)) {
|
|
2461
|
+
this.setState(
|
|
2462
|
+
prevState => ({ selected: prevState.selected.filter(item => item !== selection) }),
|
|
2463
|
+
() => console.log('selections: ', this.state.selected)
|
|
2464
|
+
);
|
|
2202
2465
|
} else {
|
|
2203
|
-
this.setState(
|
|
2204
|
-
|
|
2205
|
-
|
|
2466
|
+
this.setState(
|
|
2467
|
+
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
2468
|
+
() => console.log('selections: ', this.state.selected)
|
|
2469
|
+
);
|
|
2206
2470
|
}
|
|
2207
2471
|
};
|
|
2208
|
-
}
|
|
2209
2472
|
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2473
|
+
this.clearSelection = () => {
|
|
2474
|
+
this.setState({
|
|
2475
|
+
selected: [],
|
|
2476
|
+
isOpen: false
|
|
2477
|
+
});
|
|
2478
|
+
};
|
|
2479
|
+
this.chipGroupComponent = () => {
|
|
2480
|
+
const { selected } = this.state;
|
|
2481
|
+
return (
|
|
2482
|
+
<ChipGroup>
|
|
2483
|
+
{(selected || []).map((currentChip, index) => (
|
|
2484
|
+
<Chip
|
|
2485
|
+
isReadOnly={index === 0 ? true : false}
|
|
2486
|
+
key={currentChip}
|
|
2487
|
+
onClick={event => this.onSelect(event, currentChip)}
|
|
2488
|
+
>
|
|
2489
|
+
{currentChip}
|
|
2490
|
+
</Chip>
|
|
2491
|
+
))}
|
|
2492
|
+
</ChipGroup>
|
|
2493
|
+
);
|
|
2494
|
+
};
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
render() {
|
|
2498
|
+
const { isOpen, selected, isCreatable, hasOnCreateOption } = this.state;
|
|
2499
|
+
const titleId = 'multi-typeahead-render-chip-group-props-id-1';
|
|
2500
|
+
|
|
2501
|
+
return (
|
|
2502
|
+
<div>
|
|
2503
|
+
<span id={titleId} hidden>
|
|
2504
|
+
Select a state
|
|
2505
|
+
</span>
|
|
2506
|
+
<Select
|
|
2507
|
+
chipGroupProps={{ numChips: 1, expandedText: 'Hide', collapsedText: 'Show ${remaining}' }}
|
|
2508
|
+
variant={SelectVariant.typeaheadMulti}
|
|
2509
|
+
typeAheadAriaLabel="Select a state"
|
|
2510
|
+
onToggle={this.onToggle}
|
|
2511
|
+
onSelect={this.onSelect}
|
|
2512
|
+
onClear={this.clearSelection}
|
|
2513
|
+
selections={selected}
|
|
2514
|
+
isOpen={isOpen}
|
|
2515
|
+
aria-labelledby={titleId}
|
|
2516
|
+
placeholderText="Select a state"
|
|
2517
|
+
chipGroupComponent={this.chipGroupComponent()}
|
|
2518
|
+
>
|
|
2519
|
+
{this.state.options.map((option, index) => (
|
|
2520
|
+
<SelectOption
|
|
2521
|
+
isDisabled={option.disabled}
|
|
2522
|
+
key={index}
|
|
2523
|
+
value={option.value}
|
|
2524
|
+
{...(option.description && { description: option.description })}
|
|
2525
|
+
/>
|
|
2526
|
+
))}
|
|
2527
|
+
</Select>
|
|
2244
2528
|
</div>
|
|
2245
2529
|
);
|
|
2246
2530
|
}
|
|
2247
2531
|
}
|
|
2248
2532
|
```
|
|
2249
2533
|
|
|
2250
|
-
###
|
|
2251
|
-
|
|
2252
|
-
Avoid passing in `document.body` when passing a value to the `menuAppendTo` prop on the Select component, as it can cause accessibility issues. These issues can include, but are not limited to, being unable to enter the contents of the Select options via assistive technologies (like keyboards or screen readers).
|
|
2534
|
+
### Multiple typeahead with custom objects
|
|
2253
2535
|
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
In this example, while, when the dropdown is opened, both Select variants handle focus management within their dropdown contents the same way, you'll notice a difference when you try pressing the Tab key after selecting an option.
|
|
2257
|
-
|
|
2258
|
-
For the `document.body` variant, the focus will be placed at the end of the page, since that is where the dropdown content is appended to in the DOM (rather than focus being placed on the second Select variant as one might expect). For the `"parent"` variant, however, the focus will be placed on the next tab-able element (the "Toggle JS code" button for the code editor in this case).
|
|
2536
|
+
A `<SelectOption>` can have an object passed into the `value` property in order to store additional data beyond just a string value. The object passed in must have a `toString` function that returns a string to display in the `SelectMenu`.
|
|
2259
2537
|
|
|
2260
2538
|
```js
|
|
2261
2539
|
import React from 'react';
|
|
2262
|
-
import { Select, SelectOption,
|
|
2540
|
+
import { Select, SelectOption, SelectVariant, Divider } from '@patternfly/react-core';
|
|
2263
2541
|
|
|
2264
|
-
class
|
|
2542
|
+
class MultiTypeaheadSelectInputCustomObjects extends React.Component {
|
|
2265
2543
|
constructor(props) {
|
|
2266
2544
|
super(props);
|
|
2267
|
-
this.
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
<SelectOption key={
|
|
2545
|
+
this.createState = (name, abbreviation, capital, founded) => {
|
|
2546
|
+
return {
|
|
2547
|
+
name: name,
|
|
2548
|
+
abbreviation: abbreviation,
|
|
2549
|
+
capital: capital,
|
|
2550
|
+
founded: founded,
|
|
2551
|
+
toString: function() {
|
|
2552
|
+
return `${this.name} (${this.abbreviation}) - Founded: ${this.founded}`;
|
|
2553
|
+
},
|
|
2554
|
+
compareTo: function(value) {
|
|
2555
|
+
return this.toString()
|
|
2556
|
+
.toLowerCase()
|
|
2557
|
+
.includes(value.toString().toLowerCase());
|
|
2558
|
+
}
|
|
2559
|
+
};
|
|
2560
|
+
};
|
|
2561
|
+
this.options = [
|
|
2562
|
+
<SelectOption key={0} value={this.createState('Alabama', 'AL', 'Montgomery', 1846)} />,
|
|
2563
|
+
<Divider component="li" key={111} />,
|
|
2564
|
+
<SelectOption key={1} value={this.createState('Florida', 'FL', 'Tailahassee', 1845)} />,
|
|
2565
|
+
<SelectOption key={2} value={this.createState('New Jersey', 'NJ', 'Trenton', 1787)} />,
|
|
2566
|
+
<SelectOption key={3} value={this.createState('New Mexico', 'NM', 'Santa Fe', 1912)} />,
|
|
2567
|
+
<SelectOption key={4} value={this.createState('New York', 'NY', 'Albany', 1788)} />,
|
|
2568
|
+
<SelectOption key={5} value={this.createState('North Carolina', 'NC', 'Raleigh', 1789)} />
|
|
2285
2569
|
];
|
|
2286
2570
|
|
|
2287
2571
|
this.state = {
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
bodySelected: null,
|
|
2291
|
-
parentSelected: null
|
|
2292
|
-
};
|
|
2293
|
-
|
|
2294
|
-
this.onBodyToggle = (_event, isBodyOpen) => {
|
|
2295
|
-
this.setState({
|
|
2296
|
-
isBodyOpen
|
|
2297
|
-
});
|
|
2572
|
+
isOpen: false,
|
|
2573
|
+
selected: []
|
|
2298
2574
|
};
|
|
2299
2575
|
|
|
2300
|
-
this.
|
|
2576
|
+
this.onToggle = (_event, isOpen) => {
|
|
2301
2577
|
this.setState({
|
|
2302
|
-
|
|
2578
|
+
isOpen
|
|
2303
2579
|
});
|
|
2304
2580
|
};
|
|
2305
2581
|
|
|
2306
|
-
this.
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
this.setState(
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
if (isPlaceholder) this.clearSelection();
|
|
2319
|
-
else {
|
|
2320
|
-
this.setState({
|
|
2321
|
-
parentSelected: selection,
|
|
2322
|
-
isParentOpen: false
|
|
2323
|
-
});
|
|
2324
|
-
console.log('selected on parent:', selection);
|
|
2582
|
+
this.onSelect = (event, selection) => {
|
|
2583
|
+
const { selected } = this.state;
|
|
2584
|
+
if (selected.includes(selection)) {
|
|
2585
|
+
this.setState(
|
|
2586
|
+
prevState => ({ selected: prevState.selected.filter(item => item !== selection) }),
|
|
2587
|
+
() => console.log('selections: ', this.state.selected)
|
|
2588
|
+
);
|
|
2589
|
+
} else {
|
|
2590
|
+
this.setState(
|
|
2591
|
+
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
2592
|
+
() => console.log('selections: ', this.state.selected)
|
|
2593
|
+
);
|
|
2325
2594
|
}
|
|
2326
2595
|
};
|
|
2327
2596
|
|
|
2328
2597
|
this.clearSelection = () => {
|
|
2329
2598
|
this.setState({
|
|
2330
|
-
selected:
|
|
2599
|
+
selected: [],
|
|
2331
2600
|
isOpen: false
|
|
2332
2601
|
});
|
|
2333
2602
|
};
|
|
2334
2603
|
}
|
|
2335
2604
|
|
|
2336
2605
|
render() {
|
|
2337
|
-
const {
|
|
2606
|
+
const { isOpen, selected } = this.state;
|
|
2607
|
+
const titleId = 'multi-typeahead-select-id-2';
|
|
2338
2608
|
|
|
2339
2609
|
return (
|
|
2340
|
-
<
|
|
2341
|
-
<
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
isOpen={isParentOpen}
|
|
2360
|
-
menuAppendTo="parent"
|
|
2361
|
-
>
|
|
2362
|
-
{this.parentOptions}
|
|
2363
|
-
</Select>
|
|
2364
|
-
</FlexItem>
|
|
2365
|
-
</Flex>
|
|
2610
|
+
<div>
|
|
2611
|
+
<span id={titleId} hidden>
|
|
2612
|
+
Select a state
|
|
2613
|
+
</span>
|
|
2614
|
+
<Select
|
|
2615
|
+
variant={SelectVariant.typeaheadMulti}
|
|
2616
|
+
typeAheadAriaLabel="Select a state"
|
|
2617
|
+
onToggle={this.onToggle}
|
|
2618
|
+
onSelect={this.onSelect}
|
|
2619
|
+
onClear={this.clearSelection}
|
|
2620
|
+
onFilter={this.customFilter}
|
|
2621
|
+
selections={selected}
|
|
2622
|
+
isOpen={isOpen}
|
|
2623
|
+
aria-labelledby={titleId}
|
|
2624
|
+
placeholderText="Select a state"
|
|
2625
|
+
>
|
|
2626
|
+
{this.options}
|
|
2627
|
+
</Select>
|
|
2628
|
+
</div>
|
|
2366
2629
|
);
|
|
2367
2630
|
}
|
|
2368
2631
|
}
|
|
2369
2632
|
```
|
|
2370
2633
|
|
|
2371
|
-
###
|
|
2634
|
+
### Plain multiple typeahead
|
|
2635
|
+
|
|
2636
|
+
To plainly style a typeahead, use the `isPlain` property.
|
|
2372
2637
|
|
|
2373
2638
|
```js
|
|
2374
2639
|
import React from 'react';
|
|
2375
|
-
import { Select, SelectOption, SelectVariant
|
|
2640
|
+
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
2376
2641
|
|
|
2377
|
-
class
|
|
2642
|
+
class PlainSelectInput extends React.Component {
|
|
2378
2643
|
constructor(props) {
|
|
2379
2644
|
super(props);
|
|
2645
|
+
this.options = [
|
|
2646
|
+
{ value: 'Alabama', disabled: false },
|
|
2647
|
+
{ value: 'Florida', disabled: false },
|
|
2648
|
+
{ value: 'New Jersey', disabled: false },
|
|
2649
|
+
{ value: 'New Mexico', disabled: false },
|
|
2650
|
+
{ value: 'New York', disabled: false },
|
|
2651
|
+
{ value: 'North Carolina', disabled: false }
|
|
2652
|
+
];
|
|
2653
|
+
|
|
2380
2654
|
this.state = {
|
|
2381
2655
|
isOpen: false,
|
|
2382
|
-
|
|
2383
|
-
|
|
2656
|
+
isPlain: true,
|
|
2657
|
+
selected: []
|
|
2384
2658
|
};
|
|
2385
2659
|
|
|
2386
2660
|
this.onToggle = (_event, isOpen) => {
|
|
@@ -2389,103 +2663,74 @@ class FavoritesSelect extends React.Component {
|
|
|
2389
2663
|
});
|
|
2390
2664
|
};
|
|
2391
2665
|
|
|
2392
|
-
this.onSelect = (event, selection
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
this.setState(
|
|
2396
|
-
selected: selection,
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2666
|
+
this.onSelect = (event, selection) => {
|
|
2667
|
+
const { selected } = this.state;
|
|
2668
|
+
if (selected.includes(selection)) {
|
|
2669
|
+
this.setState(
|
|
2670
|
+
prevState => ({ selected: prevState.selected.filter(item => item !== selection) }),
|
|
2671
|
+
() => console.log('selections: ', this.state.selected)
|
|
2672
|
+
);
|
|
2673
|
+
} else {
|
|
2674
|
+
this.setState(
|
|
2675
|
+
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
2676
|
+
() => console.log('selections: ', this.state.selected)
|
|
2677
|
+
);
|
|
2400
2678
|
}
|
|
2401
2679
|
};
|
|
2402
2680
|
|
|
2403
2681
|
this.clearSelection = () => {
|
|
2404
2682
|
this.setState({
|
|
2405
|
-
selected:
|
|
2683
|
+
selected: [],
|
|
2406
2684
|
isOpen: false
|
|
2407
2685
|
});
|
|
2408
2686
|
};
|
|
2409
|
-
|
|
2410
|
-
this.onFavorite = (itemId, isFavorite) => {
|
|
2411
|
-
if (isFavorite) {
|
|
2412
|
-
this.setState({
|
|
2413
|
-
favorites: this.state.favorites.filter(id => id !== itemId)
|
|
2414
|
-
});
|
|
2415
|
-
} else
|
|
2416
|
-
this.setState({
|
|
2417
|
-
favorites: [...this.state.favorites, itemId]
|
|
2418
|
-
});
|
|
2419
|
-
};
|
|
2420
|
-
|
|
2421
|
-
this.options = [
|
|
2422
|
-
<SelectGroup label="Status" key="group1">
|
|
2423
|
-
<SelectOption id={'option-1'} key={0} value="Running" description="This is a description." />
|
|
2424
|
-
<SelectOption id={'option-2'} key={1} value="Stopped" />
|
|
2425
|
-
<SelectOption id={'option-3'} key={2} value="Down (disabled)" isDisabled />
|
|
2426
|
-
<SelectOption id={'option-4'} key={3} value="Degraded" />
|
|
2427
|
-
<SelectOption id={'option-5'} key={4} value="Needs maintenance" />
|
|
2428
|
-
</SelectGroup>,
|
|
2429
|
-
<SelectGroup label="Vendor names" key="group2">
|
|
2430
|
-
<SelectOption id={'option-6'} key={5} value="Dell" />
|
|
2431
|
-
<SelectOption id={'option-7'} key={6} value="Samsung" description="This is a description." />
|
|
2432
|
-
<SelectOption id={'option-8'} key={7} value="Hewlett-Packard" />
|
|
2433
|
-
</SelectGroup>
|
|
2434
|
-
];
|
|
2435
2687
|
}
|
|
2436
2688
|
|
|
2437
2689
|
render() {
|
|
2438
|
-
const { isOpen,
|
|
2439
|
-
const titleId = '
|
|
2690
|
+
const { isOpen, isPlain, selected } = this.state;
|
|
2691
|
+
const titleId = 'plain-typeahead-select-id';
|
|
2692
|
+
|
|
2440
2693
|
return (
|
|
2441
|
-
<
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2694
|
+
<div>
|
|
2695
|
+
<span id={titleId} hidden>
|
|
2696
|
+
Select a state
|
|
2697
|
+
</span>
|
|
2698
|
+
<Select
|
|
2699
|
+
variant={SelectVariant.typeaheadMulti}
|
|
2700
|
+
typeAheadAriaLabel="Select a state"
|
|
2701
|
+
onToggle={this.onToggle}
|
|
2702
|
+
onSelect={this.onSelect}
|
|
2703
|
+
onClear={this.clearSelection}
|
|
2704
|
+
selections={selected}
|
|
2705
|
+
isOpen={isOpen}
|
|
2706
|
+
isPlain={isPlain}
|
|
2707
|
+
aria-labelledby={titleId}
|
|
2708
|
+
placeholderText="Select a state"
|
|
2709
|
+
>
|
|
2710
|
+
{this.options.map((option, index) => (
|
|
2711
|
+
<SelectOption isDisabled={option.disabled} key={index} value={option.value} />
|
|
2712
|
+
))}
|
|
2713
|
+
</Select>
|
|
2714
|
+
</div>
|
|
2457
2715
|
);
|
|
2458
2716
|
}
|
|
2459
2717
|
}
|
|
2460
2718
|
```
|
|
2461
2719
|
|
|
2462
|
-
###
|
|
2720
|
+
### Custom menu content
|
|
2721
|
+
|
|
2722
|
+
To add custom menu content, use the `customContent` property.
|
|
2463
2723
|
|
|
2464
2724
|
```js
|
|
2465
2725
|
import React from 'react';
|
|
2466
2726
|
import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
|
|
2467
|
-
import { Select, SelectOption,
|
|
2727
|
+
import { Select, SelectOption, SelectDirection, Checkbox } from '@patternfly/react-core';
|
|
2468
2728
|
|
|
2469
|
-
class
|
|
2729
|
+
class SingleSelectInput extends React.Component {
|
|
2470
2730
|
constructor(props) {
|
|
2471
2731
|
super(props);
|
|
2472
|
-
this.options = [
|
|
2473
|
-
<SelectOption key={0} value="Select a title" isPlaceholder />,
|
|
2474
|
-
<SelectOption key={1} value="Mr" />,
|
|
2475
|
-
<SelectOption key={2} value="Miss" />,
|
|
2476
|
-
<SelectOption key={3} value="Mrs" />,
|
|
2477
|
-
<SelectOption key={4} value="Ms" />,
|
|
2478
|
-
<Divider component="li" key={5} />,
|
|
2479
|
-
<SelectOption key={6} value="Dr" />,
|
|
2480
|
-
<SelectOption key={7} value="Other" />
|
|
2481
|
-
];
|
|
2482
|
-
|
|
2483
|
-
this.toggleRef = React.createRef();
|
|
2484
|
-
|
|
2485
2732
|
this.state = {
|
|
2486
|
-
isToggleIcon: false,
|
|
2487
2733
|
isOpen: false,
|
|
2488
|
-
selected: null,
|
|
2489
2734
|
isDisabled: false,
|
|
2490
2735
|
direction: SelectDirection.down
|
|
2491
2736
|
};
|
|
@@ -2496,450 +2741,181 @@ class SelectWithFooter extends React.Component {
|
|
|
2496
2741
|
});
|
|
2497
2742
|
};
|
|
2498
2743
|
|
|
2499
|
-
this.
|
|
2500
|
-
|
|
2501
|
-
|
|
2744
|
+
this.toggleDisabled = checked => {
|
|
2745
|
+
this.setState({
|
|
2746
|
+
isDisabled: checked
|
|
2747
|
+
});
|
|
2748
|
+
};
|
|
2749
|
+
|
|
2750
|
+
this.toggleDirection = () => {
|
|
2751
|
+
if (this.state.direction === SelectDirection.up) {
|
|
2502
2752
|
this.setState({
|
|
2503
|
-
|
|
2504
|
-
|
|
2753
|
+
direction: SelectDirection.down
|
|
2754
|
+
});
|
|
2755
|
+
} else {
|
|
2756
|
+
this.setState({
|
|
2757
|
+
direction: SelectDirection.up
|
|
2505
2758
|
});
|
|
2506
|
-
console.log('selected:', selection);
|
|
2507
|
-
this.toggleRef.current.focus();
|
|
2508
2759
|
}
|
|
2509
2760
|
};
|
|
2510
|
-
|
|
2511
|
-
this.clearSelection = () => {
|
|
2512
|
-
this.setState({
|
|
2513
|
-
selected: null,
|
|
2514
|
-
isOpen: false
|
|
2515
|
-
});
|
|
2516
|
-
};
|
|
2517
2761
|
}
|
|
2518
2762
|
|
|
2519
2763
|
render() {
|
|
2520
|
-
const { isOpen, selected, isDisabled, direction
|
|
2521
|
-
const titleId = 'title-id-
|
|
2764
|
+
const { isOpen, selected, isDisabled, direction } = this.state;
|
|
2765
|
+
const titleId = 'title-id-2';
|
|
2522
2766
|
return (
|
|
2523
2767
|
<div>
|
|
2524
2768
|
<span id={titleId} hidden>
|
|
2525
2769
|
Title
|
|
2526
2770
|
</span>
|
|
2527
2771
|
<Select
|
|
2528
|
-
toggleIcon={isToggleIcon && <CubeIcon />}
|
|
2529
|
-
toggleRef={this.toggleRef}
|
|
2530
|
-
variant={SelectVariant.single}
|
|
2531
2772
|
aria-label="Select Input"
|
|
2532
2773
|
onToggle={this.onToggle}
|
|
2533
|
-
onSelect={this.onSelect}
|
|
2534
|
-
selections={selected}
|
|
2535
2774
|
isOpen={isOpen}
|
|
2536
2775
|
aria-labelledby={titleId}
|
|
2537
2776
|
isDisabled={isDisabled}
|
|
2538
2777
|
direction={direction}
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
}
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2778
|
+
customContent="[Panel contents here]"
|
|
2779
|
+
placeholderText="Filter by birth month"
|
|
2780
|
+
/>
|
|
2781
|
+
<Checkbox
|
|
2782
|
+
label="isDisabled"
|
|
2783
|
+
isChecked={this.state.isDisabled}
|
|
2784
|
+
onChange={(_event, checked) => this.toggleDisabled(checked)}
|
|
2785
|
+
aria-label="disabled checkbox panel"
|
|
2786
|
+
id="toggle-disabled-panel"
|
|
2787
|
+
name="toggle-disabled-panel"
|
|
2788
|
+
/>
|
|
2789
|
+
<Checkbox
|
|
2790
|
+
label="Expands up"
|
|
2791
|
+
isChecked={direction === SelectDirection.up}
|
|
2792
|
+
onChange={this.toggleDirection}
|
|
2793
|
+
aria-label="direction checkbox panel"
|
|
2794
|
+
id="toggle-direction-panel"
|
|
2795
|
+
name="toggle-direction-panel"
|
|
2796
|
+
/>
|
|
2549
2797
|
</div>
|
|
2550
2798
|
);
|
|
2551
2799
|
}
|
|
2552
2800
|
}
|
|
2553
2801
|
```
|
|
2554
2802
|
|
|
2555
|
-
###
|
|
2803
|
+
### Appending document body vs parent
|
|
2804
|
+
|
|
2805
|
+
Avoid passing in `document.body` to the `menuAppendTo` property. Doing so can cause accessibility issues because this prevents users from being able to enter the contents of the select options via assistive technologies (like keyboards or screen readers). Instead, pass in `parent` to achieve the same result without sacrificing accessibility.
|
|
2806
|
+
|
|
2807
|
+
The following example demonstrates both methods. When the dropdown is opened, both select variants manage focus the same way, but behave differently when the tab key is pressed after an option is selected.
|
|
2808
|
+
|
|
2809
|
+
- For the `document.body` variant, the focus will be placed at the end of the page, since that is where the dropdown content is appended to in the DOM (rather than focus being placed on the second Select variant as one might expect).
|
|
2810
|
+
- For the `parent` variant, however, the focus will be placed on the next tab-able element (the "Toggle JS code" button for the code editor in this case).
|
|
2556
2811
|
|
|
2557
2812
|
```js
|
|
2558
2813
|
import React from 'react';
|
|
2559
|
-
import { Select, SelectOption,
|
|
2814
|
+
import { Select, SelectOption, Flex, FlexItem } from '@patternfly/react-core';
|
|
2560
2815
|
|
|
2561
|
-
class
|
|
2816
|
+
class SelectDocumentBodyVsParent extends React.Component {
|
|
2562
2817
|
constructor(props) {
|
|
2563
2818
|
super(props);
|
|
2819
|
+
this.bodyOptions = [
|
|
2820
|
+
<SelectOption key={0} value="Select a title - document body" isPlaceholder />,
|
|
2821
|
+
<SelectOption key={1} value="Mr" />,
|
|
2822
|
+
<SelectOption key={2} value="Miss" />,
|
|
2823
|
+
<SelectOption key={3} value="Mrs" />,
|
|
2824
|
+
<SelectOption key={4} value="Ms" />,
|
|
2825
|
+
<SelectOption key={6} value="Dr" />,
|
|
2826
|
+
<SelectOption key={7} value="Other" />
|
|
2827
|
+
];
|
|
2828
|
+
|
|
2829
|
+
this.parentOptions = [
|
|
2830
|
+
<SelectOption key={0} value="Select a title - parent" isPlaceholder />,
|
|
2831
|
+
<SelectOption key={1} value="Mr" />,
|
|
2832
|
+
<SelectOption key={2} value="Miss" />,
|
|
2833
|
+
<SelectOption key={3} value="Mrs" />,
|
|
2834
|
+
<SelectOption key={4} value="Ms" />,
|
|
2835
|
+
<SelectOption key={6} value="Dr" />,
|
|
2836
|
+
<SelectOption key={7} value="Other" />
|
|
2837
|
+
];
|
|
2838
|
+
|
|
2564
2839
|
this.state = {
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2840
|
+
isBodyOpen: false,
|
|
2841
|
+
isParentOpen: false,
|
|
2842
|
+
bodySelected: null,
|
|
2843
|
+
parentSelected: null
|
|
2569
2844
|
};
|
|
2570
2845
|
|
|
2571
|
-
this.
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
<SelectOption key={5} value="Restarted" />
|
|
2577
|
-
];
|
|
2846
|
+
this.onBodyToggle = (_event, isBodyOpen) => {
|
|
2847
|
+
this.setState({
|
|
2848
|
+
isBodyOpen
|
|
2849
|
+
});
|
|
2850
|
+
};
|
|
2578
2851
|
|
|
2579
|
-
this.
|
|
2852
|
+
this.onParentToggle = (_event, isParentOpen) => {
|
|
2580
2853
|
this.setState({
|
|
2581
|
-
|
|
2854
|
+
isParentOpen
|
|
2582
2855
|
});
|
|
2583
2856
|
};
|
|
2584
2857
|
|
|
2585
|
-
this.
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
this.setState(
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
);
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2858
|
+
this.onBodySelect = (event, selection, isPlaceholder) => {
|
|
2859
|
+
if (isPlaceholder) this.clearSelection();
|
|
2860
|
+
else {
|
|
2861
|
+
this.setState({
|
|
2862
|
+
bodySelected: selection,
|
|
2863
|
+
isBodyOpen: false
|
|
2864
|
+
});
|
|
2865
|
+
console.log('selected on document body:', selection);
|
|
2866
|
+
}
|
|
2867
|
+
};
|
|
2868
|
+
|
|
2869
|
+
this.onParentSelect = (event, selection, isPlaceholder) => {
|
|
2870
|
+
if (isPlaceholder) this.clearSelection();
|
|
2871
|
+
else {
|
|
2872
|
+
this.setState({
|
|
2873
|
+
parentSelected: selection,
|
|
2874
|
+
isParentOpen: false
|
|
2875
|
+
});
|
|
2876
|
+
console.log('selected on parent:', selection);
|
|
2597
2877
|
}
|
|
2598
2878
|
};
|
|
2599
2879
|
|
|
2600
2880
|
this.clearSelection = () => {
|
|
2601
2881
|
this.setState({
|
|
2602
|
-
selected:
|
|
2882
|
+
selected: null,
|
|
2883
|
+
isOpen: false
|
|
2603
2884
|
});
|
|
2604
2885
|
};
|
|
2605
2886
|
}
|
|
2606
2887
|
|
|
2607
2888
|
render() {
|
|
2608
|
-
const {
|
|
2609
|
-
|
|
2889
|
+
const { isBodyOpen, isParentOpen, bodySelected, parentSelected } = this.state;
|
|
2890
|
+
|
|
2610
2891
|
return (
|
|
2611
|
-
<
|
|
2612
|
-
<
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
### View more
|
|
2639
|
-
|
|
2640
|
-
```js
|
|
2641
|
-
import React from 'react';
|
|
2642
|
-
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
2643
|
-
|
|
2644
|
-
class SelectViewMore extends React.Component {
|
|
2645
|
-
constructor(props) {
|
|
2646
|
-
super(props);
|
|
2647
|
-
this.options = [
|
|
2648
|
-
<SelectOption key={0} value="Select a title" isPlaceholder />,
|
|
2649
|
-
<SelectOption key={1} value="Mr" />,
|
|
2650
|
-
<SelectOption key={2} value="Miss" />,
|
|
2651
|
-
<SelectOption key={3} value="Mrs" />,
|
|
2652
|
-
<SelectOption key={4} value="Ms" />,
|
|
2653
|
-
<SelectOption key={5} value="Dr" />,
|
|
2654
|
-
<SelectOption key={6} value="Other" />
|
|
2655
|
-
];
|
|
2656
|
-
|
|
2657
|
-
this.toggleRef = React.createRef();
|
|
2658
|
-
|
|
2659
|
-
this.state = {
|
|
2660
|
-
isOpen: false,
|
|
2661
|
-
selected: null,
|
|
2662
|
-
numOptions: 3,
|
|
2663
|
-
isLoading: false
|
|
2664
|
-
};
|
|
2665
|
-
|
|
2666
|
-
this.onToggle = (_event, isOpen) => {
|
|
2667
|
-
this.setState({
|
|
2668
|
-
isOpen
|
|
2669
|
-
});
|
|
2670
|
-
};
|
|
2671
|
-
|
|
2672
|
-
this.onSelect = (event, selection, isPlaceholder) => {
|
|
2673
|
-
if (isPlaceholder) this.clearSelection();
|
|
2674
|
-
else {
|
|
2675
|
-
this.setState({
|
|
2676
|
-
selected: selection,
|
|
2677
|
-
isOpen: false
|
|
2678
|
-
});
|
|
2679
|
-
console.log('selected:', selection);
|
|
2680
|
-
this.toggleRef.current.focus();
|
|
2681
|
-
}
|
|
2682
|
-
};
|
|
2683
|
-
|
|
2684
|
-
this.clearSelection = () => {
|
|
2685
|
-
this.setState({
|
|
2686
|
-
selected: null,
|
|
2687
|
-
isOpen: false
|
|
2688
|
-
});
|
|
2689
|
-
};
|
|
2690
|
-
|
|
2691
|
-
this.simulateNetworkCall = callback => {
|
|
2692
|
-
setTimeout(callback, 2000);
|
|
2693
|
-
};
|
|
2694
|
-
|
|
2695
|
-
this.onViewMoreClick = () => {
|
|
2696
|
-
// Set select loadingVariant to spinner then simulate network call before loading more options
|
|
2697
|
-
this.setState({ isLoading: true });
|
|
2698
|
-
this.simulateNetworkCall(() => {
|
|
2699
|
-
const newLength =
|
|
2700
|
-
this.state.numOptions + 3 <= this.options.length ? this.state.numOptions + 3 : this.options.length;
|
|
2701
|
-
this.setState({ numOptions: newLength, isLoading: false });
|
|
2702
|
-
});
|
|
2703
|
-
};
|
|
2704
|
-
}
|
|
2705
|
-
|
|
2706
|
-
render() {
|
|
2707
|
-
const { isOpen, selected, isToggleIcon, numOptions, loadingVariant, isLoading } = this.state;
|
|
2708
|
-
const titleId = 'title-id-view-more';
|
|
2709
|
-
return (
|
|
2710
|
-
<div>
|
|
2711
|
-
<span id={titleId} hidden>
|
|
2712
|
-
Title
|
|
2713
|
-
</span>
|
|
2714
|
-
<Select
|
|
2715
|
-
variant={SelectVariant.single}
|
|
2716
|
-
toggleRef={this.toggleRef}
|
|
2717
|
-
aria-label="Select Input"
|
|
2718
|
-
onToggle={this.onToggle}
|
|
2719
|
-
onSelect={this.onSelect}
|
|
2720
|
-
selections={selected}
|
|
2721
|
-
isOpen={isOpen}
|
|
2722
|
-
aria-labelledby={titleId}
|
|
2723
|
-
{...(!isLoading &&
|
|
2724
|
-
numOptions < this.options.length && {
|
|
2725
|
-
loadingVariant: { text: 'View more', onClick: this.onViewMoreClick }
|
|
2726
|
-
})}
|
|
2727
|
-
{...(isLoading && { loadingVariant: 'spinner' })}
|
|
2728
|
-
>
|
|
2729
|
-
{this.options.slice(0, numOptions)}
|
|
2730
|
-
</Select>
|
|
2731
|
-
</div>
|
|
2732
|
-
);
|
|
2733
|
-
}
|
|
2734
|
-
}
|
|
2735
|
-
```
|
|
2736
|
-
|
|
2737
|
-
### View more with checkboxes
|
|
2738
|
-
|
|
2739
|
-
```js
|
|
2740
|
-
import React from 'react';
|
|
2741
|
-
import { Select, SelectOption, SelectVariant } from '@patternfly/react-core';
|
|
2742
|
-
|
|
2743
|
-
class SelectViewMoreCheckbox extends React.Component {
|
|
2744
|
-
constructor(props) {
|
|
2745
|
-
super(props);
|
|
2746
|
-
|
|
2747
|
-
this.state = {
|
|
2748
|
-
isOpen: false,
|
|
2749
|
-
selected: [],
|
|
2750
|
-
numOptions: 3,
|
|
2751
|
-
isLoading: false
|
|
2752
|
-
};
|
|
2753
|
-
|
|
2754
|
-
this.options = [
|
|
2755
|
-
<SelectOption key={0} value="Active" description="This is a description" />,
|
|
2756
|
-
<SelectOption key={1} value="Cancelled" />,
|
|
2757
|
-
<SelectOption key={2} value="Paused" />,
|
|
2758
|
-
<SelectOption key={4} value="Warning" />,
|
|
2759
|
-
<SelectOption key={5} value="Restarted" />,
|
|
2760
|
-
<SelectOption key={6} value="Down" />,
|
|
2761
|
-
<SelectOption key={7} value="Disabled" />,
|
|
2762
|
-
<SelectOption key={8} value="Needs maintenance " />,
|
|
2763
|
-
<SelectOption key={9} value="Degraded " />
|
|
2764
|
-
];
|
|
2765
|
-
|
|
2766
|
-
this.onToggle = (_event, isOpen) => {
|
|
2767
|
-
this.setState({
|
|
2768
|
-
isOpen
|
|
2769
|
-
});
|
|
2770
|
-
};
|
|
2771
|
-
|
|
2772
|
-
this.onSelect = (event, selection) => {
|
|
2773
|
-
const { selected } = this.state;
|
|
2774
|
-
if (selected.includes(selection)) {
|
|
2775
|
-
this.setState(
|
|
2776
|
-
prevState => ({ selected: prevState.selected.filter(item => item !== selection) }),
|
|
2777
|
-
() => console.log('selections: ', this.state.selected)
|
|
2778
|
-
);
|
|
2779
|
-
} else {
|
|
2780
|
-
this.setState(
|
|
2781
|
-
prevState => ({ selected: [...prevState.selected, selection] }),
|
|
2782
|
-
() => console.log('selections: ', this.state.selected)
|
|
2783
|
-
);
|
|
2784
|
-
}
|
|
2785
|
-
};
|
|
2786
|
-
|
|
2787
|
-
this.clearSelection = () => {
|
|
2788
|
-
this.setState({
|
|
2789
|
-
selected: []
|
|
2790
|
-
});
|
|
2791
|
-
};
|
|
2792
|
-
|
|
2793
|
-
this.simulateNetworkCall = callback => {
|
|
2794
|
-
setTimeout(callback, 2000);
|
|
2795
|
-
};
|
|
2796
|
-
|
|
2797
|
-
this.onViewMoreClick = () => {
|
|
2798
|
-
// Set select loadingVariant to spinner then simulate network call before loading more options
|
|
2799
|
-
this.setState({ isLoading: true });
|
|
2800
|
-
this.simulateNetworkCall(() => {
|
|
2801
|
-
const newLength =
|
|
2802
|
-
this.state.numOptions + 3 <= this.options.length ? this.state.numOptions + 3 : this.options.length;
|
|
2803
|
-
this.setState({ numOptions: newLength, isLoading: false });
|
|
2804
|
-
});
|
|
2805
|
-
};
|
|
2806
|
-
}
|
|
2807
|
-
|
|
2808
|
-
render() {
|
|
2809
|
-
const { isOpen, selected, numOptions, isLoading } = this.state;
|
|
2810
|
-
const titleId = 'view-more-checkbox-select-id';
|
|
2811
|
-
return (
|
|
2812
|
-
<div>
|
|
2813
|
-
<span id={titleId} hidden>
|
|
2814
|
-
Checkbox View more check
|
|
2815
|
-
</span>
|
|
2816
|
-
<Select
|
|
2817
|
-
variant={SelectVariant.checkbox}
|
|
2818
|
-
aria-label="Select input"
|
|
2819
|
-
onToggle={this.onToggle}
|
|
2820
|
-
onSelect={this.onSelect}
|
|
2821
|
-
selections={selected}
|
|
2822
|
-
isOpen={isOpen}
|
|
2823
|
-
placeholderText="Filter by status"
|
|
2824
|
-
aria-labelledby={titleId}
|
|
2825
|
-
{...(!isLoading &&
|
|
2826
|
-
numOptions < this.options.length && {
|
|
2827
|
-
loadingVariant: { text: 'View more', onClick: this.onViewMoreClick }
|
|
2828
|
-
})}
|
|
2829
|
-
{...(isLoading && { loadingVariant: 'spinner' })}
|
|
2830
|
-
>
|
|
2831
|
-
{this.options.slice(0, numOptions)}
|
|
2832
|
-
</Select>
|
|
2833
|
-
</div>
|
|
2892
|
+
<Flex space={{ default: 'spacerMd' }} direction={{ default: 'column' }}>
|
|
2893
|
+
<FlexItem>
|
|
2894
|
+
<Select
|
|
2895
|
+
aria-label="Select Input for Document Body"
|
|
2896
|
+
onToggle={this.onBodyToggle}
|
|
2897
|
+
onSelect={this.onBodySelect}
|
|
2898
|
+
selections={bodySelected}
|
|
2899
|
+
isOpen={isBodyOpen}
|
|
2900
|
+
menuAppendTo={() => document.body}
|
|
2901
|
+
>
|
|
2902
|
+
{this.bodyOptions}
|
|
2903
|
+
</Select>
|
|
2904
|
+
</FlexItem>
|
|
2905
|
+
<FlexItem>
|
|
2906
|
+
<Select
|
|
2907
|
+
aria-label="Select Input for Parent"
|
|
2908
|
+
onToggle={this.onParentToggle}
|
|
2909
|
+
onSelect={this.onParentSelect}
|
|
2910
|
+
selections={parentSelected}
|
|
2911
|
+
isOpen={isParentOpen}
|
|
2912
|
+
menuAppendTo="parent"
|
|
2913
|
+
>
|
|
2914
|
+
{this.parentOptions}
|
|
2915
|
+
</Select>
|
|
2916
|
+
</FlexItem>
|
|
2917
|
+
</Flex>
|
|
2834
2918
|
);
|
|
2835
2919
|
}
|
|
2836
2920
|
}
|
|
2837
2921
|
```
|
|
2838
|
-
|
|
2839
|
-
### With a style applied to the placeholder text
|
|
2840
|
-
|
|
2841
|
-
```js
|
|
2842
|
-
import React from 'react';
|
|
2843
|
-
import { Select, SelectOption } from '@patternfly/react-core';
|
|
2844
|
-
|
|
2845
|
-
function SelectWithPlaceholderStyle() {
|
|
2846
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
|
2847
|
-
const [selected, setSelected] = React.useState([]);
|
|
2848
|
-
|
|
2849
|
-
const options = [
|
|
2850
|
-
<SelectOption key={0} value="Active" />,
|
|
2851
|
-
<SelectOption key={1} value="Cancelled" />,
|
|
2852
|
-
<SelectOption key={2} value="Paused" />
|
|
2853
|
-
];
|
|
2854
|
-
|
|
2855
|
-
const onToggle = (_event, isOpen) => setIsOpen(isOpen);
|
|
2856
|
-
|
|
2857
|
-
const onSelect = (event, selection, isPlaceholder) => {
|
|
2858
|
-
setSelected(selection);
|
|
2859
|
-
setIsOpen(false);
|
|
2860
|
-
};
|
|
2861
|
-
|
|
2862
|
-
const clearSelection = () => {
|
|
2863
|
-
setSelected(null);
|
|
2864
|
-
setIsOpen(false);
|
|
2865
|
-
};
|
|
2866
|
-
|
|
2867
|
-
const titleId = 'placeholder-style-select-id';
|
|
2868
|
-
|
|
2869
|
-
return (
|
|
2870
|
-
<div>
|
|
2871
|
-
<span id={titleId} hidden>
|
|
2872
|
-
Placeholder styles
|
|
2873
|
-
</span>
|
|
2874
|
-
<Select
|
|
2875
|
-
variant={SelectVariant.single}
|
|
2876
|
-
hasPlaceholderStyle
|
|
2877
|
-
aria-label="Select input"
|
|
2878
|
-
onToggle={onToggle}
|
|
2879
|
-
onSelect={onSelect}
|
|
2880
|
-
onClear={clearSelection}
|
|
2881
|
-
selections={selected}
|
|
2882
|
-
isOpen={isOpen}
|
|
2883
|
-
placeholderText="Filter by status"
|
|
2884
|
-
aria-labelledby={titleId}
|
|
2885
|
-
>
|
|
2886
|
-
{options}
|
|
2887
|
-
</Select>
|
|
2888
|
-
</div>
|
|
2889
|
-
);
|
|
2890
|
-
}
|
|
2891
|
-
```
|
|
2892
|
-
|
|
2893
|
-
### With a style applied to the placeholder option
|
|
2894
|
-
|
|
2895
|
-
```js
|
|
2896
|
-
import React from 'react';
|
|
2897
|
-
import { Select, SelectOption } from '@patternfly/react-core';
|
|
2898
|
-
|
|
2899
|
-
function SelectWithPlaceholderStyle() {
|
|
2900
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
|
2901
|
-
const [selected, setSelected] = React.useState([]);
|
|
2902
|
-
|
|
2903
|
-
const options = [
|
|
2904
|
-
<SelectOption key={0} value="Filter by status" isPlaceholder />,
|
|
2905
|
-
<SelectOption key={1} value="Active" />,
|
|
2906
|
-
<SelectOption key={2} value="Cancelled" />,
|
|
2907
|
-
<SelectOption key={3} value="Paused" />
|
|
2908
|
-
];
|
|
2909
|
-
|
|
2910
|
-
const onToggle = (_event, isOpen) => setIsOpen(isOpen);
|
|
2911
|
-
|
|
2912
|
-
const onSelect = (event, selection, isPlaceholder) => {
|
|
2913
|
-
setSelected(selection);
|
|
2914
|
-
setIsOpen(false);
|
|
2915
|
-
};
|
|
2916
|
-
|
|
2917
|
-
const clearSelection = () => {
|
|
2918
|
-
setSelected(null);
|
|
2919
|
-
setIsOpen(false);
|
|
2920
|
-
};
|
|
2921
|
-
|
|
2922
|
-
const titleId = 'placeholder-style-select-option-id';
|
|
2923
|
-
|
|
2924
|
-
return (
|
|
2925
|
-
<div>
|
|
2926
|
-
<span id={titleId} hidden>
|
|
2927
|
-
Placeholder styles - select option
|
|
2928
|
-
</span>
|
|
2929
|
-
<Select
|
|
2930
|
-
variant={SelectVariant.single}
|
|
2931
|
-
hasPlaceholderStyle
|
|
2932
|
-
aria-label="Select input"
|
|
2933
|
-
onToggle={onToggle}
|
|
2934
|
-
onSelect={onSelect}
|
|
2935
|
-
onClear={clearSelection}
|
|
2936
|
-
selections={selected}
|
|
2937
|
-
isOpen={isOpen}
|
|
2938
|
-
aria-labelledby={titleId}
|
|
2939
|
-
>
|
|
2940
|
-
{options}
|
|
2941
|
-
</Select>
|
|
2942
|
-
</div>
|
|
2943
|
-
);
|
|
2944
|
-
}
|
|
2945
|
-
```
|