playbook_ui 17.2.0.pre.rc.0 → 17.2.0.pre.rc.1
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +9 -18
- data/app/pb_kits/playbook/pb_dropdown/docs/_playground.json +0 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json +1 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +0 -6
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +0 -2
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +1 -13
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +2 -205
- data/app/pb_kits/playbook/pb_dropdown/index.js +1 -240
- data/app/pb_kits/playbook/pb_dropdown/kit.schema.json +6 -40
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +2 -2
- data/app/pb_kits/playbook/pb_table/docs/_sections.yml +1 -0
- data/app/pb_kits/playbook/pb_table/docs/example.yml +11 -11
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +24 -35
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options.html.erb +0 -34
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options.md +0 -4
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_autocomplete.html.erb +0 -35
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_autocomplete.md +0 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_multi_select.html.erb +0 -35
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_multi_select.md +0 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_react_hook.jsx +0 -45
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_react_hook.md +0 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_react_hook.jsx +0 -36
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_react_hook.md +0 -1
- data/app/pb_kits/playbook/pb_dropdown/dropdown_index.test.js +0 -372
- /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_column_rails.html.erb → _table_alignment_column.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_column.md → _table_alignment_column_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_row_rails.html.erb → _table_alignment_row.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_row.md → _table_alignment_row_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_shift_data_rails.html.erb → _table_alignment_shift_data.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_shift_data.md → _table_alignment_shift_data_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_shift_row_rails.html.erb → _table_alignment_shift_row.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_alignment_shift_row.md → _table_alignment_shift_row_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_collapsible_with_custom_content_rails.html.erb → _table_with_collapsible_with_custom_content.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_collapsible_with_custom_content.md → _table_with_collapsible_with_custom_content_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_collapsible_with_nested_rows_rails.html.erb → _table_with_collapsible_with_nested_rows.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_collapsible_with_nested_rows.md → _table_with_collapsible_with_nested_rows_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_collapsible_with_nested_table_rails.html.erb → _table_with_collapsible_with_nested_table.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_collapsible_with_nested_table.md → _table_with_collapsible_with_nested_table_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_filter_variant_rails.html.erb → _table_with_filter_variant.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_filter_variant.md → _table_with_filter_variant_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_filter_variant_with_pagination_rails.html.erb → _table_with_filter_variant_with_pagination.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_filter_variant_with_pagination.md → _table_with_filter_variant_with_pagination_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_filter_with_card_title_props_rails.html.erb → _table_with_filter_with_card_title_props.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_filter_with_card_title_props.md → _table_with_filter_with_card_title_props_react.md} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_subcomponents_rails.html.erb → _table_with_subcomponents.html.erb} +0 -0
- /data/app/pb_kits/playbook/pb_table/docs/{_table_with_subcomponents.md → _table_with_subcomponents_react.md} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b0cfdd29dff7aa690ffa80f529b880a467df847de2897b20978f15aee42493f9
|
|
4
|
+
data.tar.gz: efe2a6be9fa5b594a9ec8cf3dba4085b7bbc3b6e0ce181a60710b0e760165640
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d1000f4e35e8953cbeff95dba2a55f2373c594320e00fc58ac8436eded89a5eb9f5383c85600bf3d747d71148182841ab2a1c5f4124581b5b03596813ea0b353
|
|
7
|
+
data.tar.gz: '068ba2587e7d290077532454b72d6b6cddefa2d919834bc41329259a010b70535ab6ab0636a846973f3c436d6f6cc259a1fb455edade7989f352b15e76c3543d'
|
|
@@ -112,8 +112,6 @@ type DropdownProps = {
|
|
|
112
112
|
isClosed?: boolean;
|
|
113
113
|
label?: string;
|
|
114
114
|
multiSelect?: boolean;
|
|
115
|
-
name?: string;
|
|
116
|
-
onChange?: (event: { target: { name?: string; value: any } }) => void;
|
|
117
115
|
onSelect?: (arg: GenericObject) => null;
|
|
118
116
|
options?: GenericObject;
|
|
119
117
|
placeholder?: string;
|
|
@@ -158,8 +156,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
158
156
|
label,
|
|
159
157
|
multiSelect = false,
|
|
160
158
|
formPillProps,
|
|
161
|
-
name,
|
|
162
|
-
onChange,
|
|
163
159
|
onSelect,
|
|
164
160
|
options,
|
|
165
161
|
placeholder,
|
|
@@ -418,10 +414,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
418
414
|
setIsDropDownClosed(false);
|
|
419
415
|
};
|
|
420
416
|
|
|
421
|
-
const handleSelectionChange = (value: any) => {
|
|
422
|
-
onSelect && onSelect(value);
|
|
423
|
-
onChange && onChange({ target: { name, value } });
|
|
424
|
-
};
|
|
425
417
|
|
|
426
418
|
const handleOptionClick = (clickedItem: GenericObject) => {
|
|
427
419
|
if (disabled) return;
|
|
@@ -434,7 +426,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
434
426
|
const next = exists
|
|
435
427
|
? list.filter((option) => option.value !== clickedItem.value)
|
|
436
428
|
: [...list, clickedItem];
|
|
437
|
-
|
|
429
|
+
onSelect && onSelect(next);
|
|
438
430
|
return next;
|
|
439
431
|
});
|
|
440
432
|
setFilterItem("");
|
|
@@ -447,7 +439,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
447
439
|
if (shouldCloseOnClick) {
|
|
448
440
|
setIsDropDownClosed(true);
|
|
449
441
|
}
|
|
450
|
-
|
|
442
|
+
onSelect && onSelect(clickedItem);
|
|
451
443
|
|
|
452
444
|
// Sync with DatePickers if this is a quickpick variant
|
|
453
445
|
if (variant === "quickpick" && Array.isArray(clickedItem.value)) {
|
|
@@ -476,10 +468,10 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
476
468
|
if (disabled) return;
|
|
477
469
|
if (multiSelect) {
|
|
478
470
|
setSelected([]);
|
|
479
|
-
|
|
471
|
+
onSelect && onSelect([]);
|
|
480
472
|
} else {
|
|
481
473
|
setSelected({});
|
|
482
|
-
|
|
474
|
+
onSelect && onSelect(null);
|
|
483
475
|
setFocusedOptionIndex(-1);
|
|
484
476
|
setFilterItem("");
|
|
485
477
|
|
|
@@ -513,10 +505,10 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
513
505
|
clearSelected: () => {
|
|
514
506
|
if (multiSelect) {
|
|
515
507
|
setSelected([]);
|
|
516
|
-
|
|
508
|
+
onSelect && onSelect([]);
|
|
517
509
|
} else {
|
|
518
510
|
setSelected({});
|
|
519
|
-
|
|
511
|
+
onSelect && onSelect(null);
|
|
520
512
|
}
|
|
521
513
|
setFilterItem("");
|
|
522
514
|
setIsDropDownClosed(true);
|
|
@@ -530,16 +522,16 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
530
522
|
clearSelected: () => {
|
|
531
523
|
if (multiSelect) {
|
|
532
524
|
setSelected([]);
|
|
533
|
-
|
|
525
|
+
onSelect && onSelect([]);
|
|
534
526
|
} else {
|
|
535
527
|
setSelected({});
|
|
536
|
-
|
|
528
|
+
onSelect && onSelect(null);
|
|
537
529
|
}
|
|
538
530
|
setFilterItem("");
|
|
539
531
|
setIsDropDownClosed(true);
|
|
540
532
|
},
|
|
541
533
|
};
|
|
542
|
-
}, [multiSelect,
|
|
534
|
+
}, [multiSelect, onSelect, setSelected, setFilterItem, setIsDropDownClosed]);
|
|
543
535
|
|
|
544
536
|
useImperativeHandle(ref, () => imperativeRef.current);
|
|
545
537
|
|
|
@@ -602,7 +594,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
602
594
|
handleBackspace,
|
|
603
595
|
handleChange,
|
|
604
596
|
handleOptionClick,
|
|
605
|
-
handleSelectionChange,
|
|
606
597
|
handleWrapperClick,
|
|
607
598
|
inputRef,
|
|
608
599
|
inputWrapperRef,
|
|
@@ -70,7 +70,6 @@
|
|
|
70
70
|
"name": "Content",
|
|
71
71
|
"props": [
|
|
72
72
|
"label",
|
|
73
|
-
"name",
|
|
74
73
|
"placeholder",
|
|
75
74
|
"options",
|
|
76
75
|
"defaultValue",
|
|
@@ -112,7 +111,7 @@
|
|
|
112
111
|
},
|
|
113
112
|
{
|
|
114
113
|
"name": "Events",
|
|
115
|
-
"props": ["
|
|
114
|
+
"props": ["onSelect"]
|
|
116
115
|
}
|
|
117
116
|
],
|
|
118
117
|
"presets": [
|
|
@@ -39,9 +39,6 @@ examples:
|
|
|
39
39
|
- dropdown_disabled: Disabled Input
|
|
40
40
|
- dropdown_grouped_options: Grouped Options
|
|
41
41
|
- dropdown_custom_event_type: Custom Event Type
|
|
42
|
-
- dropdown_dynamic_options: Dynamic Options
|
|
43
|
-
- dropdown_dynamic_options_with_autocomplete: Dynamic Options with Autocomplete
|
|
44
|
-
- dropdown_dynamic_options_with_multi_select: Dynamic Options with Multi Select
|
|
45
42
|
|
|
46
43
|
react:
|
|
47
44
|
- dropdown_default: Default
|
|
@@ -84,6 +81,3 @@ examples:
|
|
|
84
81
|
- dropdown_required_indicator: Required Indicator
|
|
85
82
|
- dropdown_disabled: Disabled Input
|
|
86
83
|
- dropdown_grouped_options: Grouped Options
|
|
87
|
-
- dropdown_react_hook: React Hook
|
|
88
|
-
- dropdown_multi_select_react_hook: React Hook Multi Select
|
|
89
|
-
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export { default as DropdownDefault } from './_dropdown_default.jsx'
|
|
2
|
-
export { default as DropdownReactHook } from './_dropdown_react_hook.jsx'
|
|
3
|
-
export { default as DropdownMultiSelectReactHook } from './_dropdown_multi_select_react_hook.jsx'
|
|
4
2
|
export { default as DropdownWithCustomDisplay } from './_dropdown_with_custom_display.jsx'
|
|
5
3
|
export { default as DropdownWithCustomOptions } from './_dropdown_with_custom_options.jsx'
|
|
6
4
|
export { default as DropdownWithCustomTrigger } from './_dropdown_with_custom_trigger.jsx'
|
|
@@ -59,14 +59,6 @@ module Playbook
|
|
|
59
59
|
default: false
|
|
60
60
|
prop :custom_event_type, type: Playbook::Props::String,
|
|
61
61
|
default: ""
|
|
62
|
-
prop :options_by_context, type: Playbook::Props::HashProp,
|
|
63
|
-
default: {}
|
|
64
|
-
prop :context_selector, type: Playbook::Props::String,
|
|
65
|
-
default: ""
|
|
66
|
-
prop :clear_on_context_change, type: Playbook::Props::Boolean,
|
|
67
|
-
default: true
|
|
68
|
-
prop :options_event_type, type: Playbook::Props::String,
|
|
69
|
-
default: ""
|
|
70
62
|
|
|
71
63
|
def data
|
|
72
64
|
Hash(prop(:data)).merge(
|
|
@@ -81,11 +73,7 @@ module Playbook
|
|
|
81
73
|
end_date_id: variant == "quickpick" ? end_date_id : nil,
|
|
82
74
|
controls_start_id: variant == "quickpick" && controls_start_id.present? ? controls_start_id : nil,
|
|
83
75
|
controls_end_id: variant == "quickpick" && controls_end_id.present? ? controls_end_id : nil,
|
|
84
|
-
custom_event_type: custom_event_type.presence
|
|
85
|
-
pb_dropdown_options_by_context: options_by_context.present? ? options_by_context.to_json : nil,
|
|
86
|
-
pb_dropdown_context_selector: context_selector.presence,
|
|
87
|
-
pb_dropdown_clear_on_context_change: clear_on_context_change,
|
|
88
|
-
options_event_type: options_event_type.presence
|
|
76
|
+
custom_event_type: custom_event_type.presence
|
|
89
77
|
).compact
|
|
90
78
|
end
|
|
91
79
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState } from "react"
|
|
2
|
-
import { render, screen, fireEvent, waitFor
|
|
2
|
+
import { render, screen, fireEvent, waitFor } from "../utilities/test-utils"
|
|
3
3
|
|
|
4
4
|
import { Dropdown, Icon, IconCircle } from 'playbook-ui'
|
|
5
5
|
import DateTime from "../pb_kit/dateTime.ts"
|
|
@@ -995,207 +995,4 @@ test('disabled prop disables autocomplete input', () => {
|
|
|
995
995
|
const input = kit.querySelector('.dropdown_input')
|
|
996
996
|
|
|
997
997
|
expect(input).toBeDisabled()
|
|
998
|
-
})
|
|
999
|
-
|
|
1000
|
-
test('onChange uses react-hook-form event shape', () => {
|
|
1001
|
-
const onChange = jest.fn()
|
|
1002
|
-
|
|
1003
|
-
render(
|
|
1004
|
-
<Dropdown
|
|
1005
|
-
data={{ testid: testId }}
|
|
1006
|
-
name="color"
|
|
1007
|
-
onChange={onChange}
|
|
1008
|
-
options={options}
|
|
1009
|
-
/>
|
|
1010
|
-
)
|
|
1011
|
-
|
|
1012
|
-
const kit = screen.getByTestId(testId)
|
|
1013
|
-
fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0])
|
|
1014
|
-
|
|
1015
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
1016
|
-
target: { name: 'color', value: options[0] },
|
|
1017
|
-
})
|
|
1018
|
-
})
|
|
1019
|
-
|
|
1020
|
-
test('react-hook-form onChange receives selected options for multiSelect', () => {
|
|
1021
|
-
const onChange = jest.fn()
|
|
1022
|
-
|
|
1023
|
-
render(
|
|
1024
|
-
<Dropdown
|
|
1025
|
-
data={{ testid: testId }}
|
|
1026
|
-
multiSelect
|
|
1027
|
-
name="languages"
|
|
1028
|
-
onChange={onChange}
|
|
1029
|
-
options={options}
|
|
1030
|
-
/>
|
|
1031
|
-
)
|
|
1032
|
-
|
|
1033
|
-
const kit = screen.getByTestId(testId)
|
|
1034
|
-
fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0])
|
|
1035
|
-
fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0])
|
|
1036
|
-
|
|
1037
|
-
expect(onChange.mock.calls[0][0]).toEqual({
|
|
1038
|
-
target: { name: 'languages', value: [options[0]] },
|
|
1039
|
-
})
|
|
1040
|
-
expect(onChange.mock.calls[1][0]).toEqual({
|
|
1041
|
-
target: { name: 'languages', value: [options[0], options[1]] },
|
|
1042
|
-
})
|
|
1043
|
-
})
|
|
1044
|
-
|
|
1045
|
-
test('onSelect still fires when onChange is provided', () => {
|
|
1046
|
-
const onSelect = jest.fn()
|
|
1047
|
-
const onChange = jest.fn()
|
|
1048
|
-
|
|
1049
|
-
render(
|
|
1050
|
-
<Dropdown
|
|
1051
|
-
data={{ testid: testId }}
|
|
1052
|
-
name="country"
|
|
1053
|
-
onChange={onChange}
|
|
1054
|
-
onSelect={onSelect}
|
|
1055
|
-
options={options}
|
|
1056
|
-
/>
|
|
1057
|
-
)
|
|
1058
|
-
|
|
1059
|
-
const kit = screen.getByTestId(testId)
|
|
1060
|
-
fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0])
|
|
1061
|
-
|
|
1062
|
-
expect(onSelect).toHaveBeenCalledWith(options[0])
|
|
1063
|
-
expect(onChange).toHaveBeenCalledWith({
|
|
1064
|
-
target: { name: 'country', value: options[0] },
|
|
1065
|
-
})
|
|
1066
|
-
})
|
|
1067
|
-
|
|
1068
|
-
test('onSelect-only single select still receives the option object', () => {
|
|
1069
|
-
const onSelect = jest.fn()
|
|
1070
|
-
|
|
1071
|
-
render(
|
|
1072
|
-
<Dropdown
|
|
1073
|
-
data={{ testid: testId }}
|
|
1074
|
-
onSelect={onSelect}
|
|
1075
|
-
options={options}
|
|
1076
|
-
/>
|
|
1077
|
-
)
|
|
1078
|
-
|
|
1079
|
-
const kit = screen.getByTestId(testId)
|
|
1080
|
-
fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0])
|
|
1081
|
-
|
|
1082
|
-
expect(onSelect).toHaveBeenCalledTimes(1)
|
|
1083
|
-
expect(onSelect).toHaveBeenCalledWith(options[0])
|
|
1084
|
-
})
|
|
1085
|
-
|
|
1086
|
-
test('onSelect-only multiSelect still receives the selected options array', () => {
|
|
1087
|
-
const onSelect = jest.fn()
|
|
1088
|
-
|
|
1089
|
-
render(
|
|
1090
|
-
<Dropdown
|
|
1091
|
-
data={{ testid: testId }}
|
|
1092
|
-
multiSelect
|
|
1093
|
-
onSelect={onSelect}
|
|
1094
|
-
options={options}
|
|
1095
|
-
/>
|
|
1096
|
-
)
|
|
1097
|
-
|
|
1098
|
-
const kit = screen.getByTestId(testId)
|
|
1099
|
-
fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0])
|
|
1100
|
-
fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0])
|
|
1101
|
-
|
|
1102
|
-
expect(onSelect.mock.calls[0][0]).toEqual([options[0]])
|
|
1103
|
-
expect(onSelect.mock.calls[1][0]).toEqual([options[0], options[1]])
|
|
1104
|
-
})
|
|
1105
|
-
|
|
1106
|
-
test('onSelect-only clearSelected still receives null', () => {
|
|
1107
|
-
const onSelect = jest.fn()
|
|
1108
|
-
const dropdownRef = React.createRef()
|
|
1109
|
-
|
|
1110
|
-
render(
|
|
1111
|
-
<Dropdown
|
|
1112
|
-
data={{ testid: testId }}
|
|
1113
|
-
defaultValue={options[0]}
|
|
1114
|
-
onSelect={onSelect}
|
|
1115
|
-
options={options}
|
|
1116
|
-
ref={dropdownRef}
|
|
1117
|
-
/>
|
|
1118
|
-
)
|
|
1119
|
-
|
|
1120
|
-
act(() => {
|
|
1121
|
-
dropdownRef.current.clearSelected()
|
|
1122
|
-
})
|
|
1123
|
-
|
|
1124
|
-
expect(onSelect).toHaveBeenCalledWith(null)
|
|
1125
|
-
})
|
|
1126
|
-
|
|
1127
|
-
test('onSelect-only clear icon still receives null', () => {
|
|
1128
|
-
const onSelect = jest.fn()
|
|
1129
|
-
|
|
1130
|
-
render(
|
|
1131
|
-
<Dropdown
|
|
1132
|
-
data={{ testid: testId }}
|
|
1133
|
-
defaultValue={options[0]}
|
|
1134
|
-
onSelect={onSelect}
|
|
1135
|
-
options={options}
|
|
1136
|
-
/>
|
|
1137
|
-
)
|
|
1138
|
-
|
|
1139
|
-
const kit = screen.getByTestId(testId)
|
|
1140
|
-
fireEvent.click(kit.querySelector('[aria-label="times icon"]').closest('div'))
|
|
1141
|
-
|
|
1142
|
-
expect(onSelect).toHaveBeenCalledWith(null)
|
|
1143
|
-
})
|
|
1144
|
-
|
|
1145
|
-
test('onSelect-only removing a multiSelect pill still receives remaining options', () => {
|
|
1146
|
-
const onSelect = jest.fn()
|
|
1147
|
-
|
|
1148
|
-
render(
|
|
1149
|
-
<Dropdown
|
|
1150
|
-
data={{ testid: testId }}
|
|
1151
|
-
defaultValue={[options[0], options[1]]}
|
|
1152
|
-
multiSelect
|
|
1153
|
-
onSelect={onSelect}
|
|
1154
|
-
options={options}
|
|
1155
|
-
/>
|
|
1156
|
-
)
|
|
1157
|
-
|
|
1158
|
-
const kit = screen.getByTestId(testId)
|
|
1159
|
-
fireEvent.click(kit.querySelector('.pb_form_pill_close'))
|
|
1160
|
-
|
|
1161
|
-
expect(onSelect).toHaveBeenCalledWith([options[1]])
|
|
1162
|
-
})
|
|
1163
|
-
|
|
1164
|
-
test('autocomplete typing does not fire onSelect or onChange', () => {
|
|
1165
|
-
const onSelect = jest.fn()
|
|
1166
|
-
const onChange = jest.fn()
|
|
1167
|
-
|
|
1168
|
-
render(
|
|
1169
|
-
<Dropdown
|
|
1170
|
-
autocomplete
|
|
1171
|
-
data={{ testid: testId }}
|
|
1172
|
-
onChange={onChange}
|
|
1173
|
-
onSelect={onSelect}
|
|
1174
|
-
options={options}
|
|
1175
|
-
/>
|
|
1176
|
-
)
|
|
1177
|
-
|
|
1178
|
-
const kit = screen.getByTestId(testId)
|
|
1179
|
-
fireEvent.change(kit.querySelector('.dropdown_input'), { target: { value: 'Can' } })
|
|
1180
|
-
|
|
1181
|
-
expect(onSelect).not.toHaveBeenCalled()
|
|
1182
|
-
expect(onChange).not.toHaveBeenCalled()
|
|
1183
|
-
})
|
|
1184
|
-
|
|
1185
|
-
test('autocomplete selection still fires onSelect', () => {
|
|
1186
|
-
const onSelect = jest.fn()
|
|
1187
|
-
|
|
1188
|
-
render(
|
|
1189
|
-
<Dropdown
|
|
1190
|
-
autocomplete
|
|
1191
|
-
data={{ testid: testId }}
|
|
1192
|
-
onSelect={onSelect}
|
|
1193
|
-
options={options}
|
|
1194
|
-
/>
|
|
1195
|
-
)
|
|
1196
|
-
|
|
1197
|
-
const kit = screen.getByTestId(testId)
|
|
1198
|
-
fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[1])
|
|
1199
|
-
|
|
1200
|
-
expect(onSelect).toHaveBeenCalledWith(options[1])
|
|
1201
|
-
})
|
|
998
|
+
})
|
|
@@ -162,8 +162,6 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
162
162
|
const baseInput = this.baseInput;
|
|
163
163
|
this.wasOriginallyRequired =
|
|
164
164
|
baseInput && baseInput.hasAttribute("required");
|
|
165
|
-
// Apply context options before default value so SSR/default selection matches current context
|
|
166
|
-
this.bindContextSelector();
|
|
167
165
|
this.setDefaultValue();
|
|
168
166
|
this.bindEventListeners();
|
|
169
167
|
this.bindSearchInput();
|
|
@@ -186,13 +184,11 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
186
184
|
this.updateClearButton();
|
|
187
185
|
this.applyDisabledState();
|
|
188
186
|
|
|
189
|
-
// Listen for clear
|
|
187
|
+
// Listen for clear and select events from external source
|
|
190
188
|
this.handleClearEventBound = this.handleClearEvent.bind(this);
|
|
191
189
|
document.addEventListener("pb:dropdown:clear", this.handleClearEventBound);
|
|
192
190
|
this.handleSelectEventBound = this.handleSelectEvent.bind(this);
|
|
193
191
|
document.addEventListener("pb:dropdown:select", this.handleSelectEventBound);
|
|
194
|
-
this.handleUpdateOptionsEventBound = this.handleUpdateOptionsEvent.bind(this);
|
|
195
|
-
document.addEventListener("pb:dropdown:updateOptions", this.handleUpdateOptionsEventBound);
|
|
196
192
|
|
|
197
193
|
// Listen for custom_event_type to clear on custom events
|
|
198
194
|
const customEventTypeString = this.element.dataset.customEventType;
|
|
@@ -206,19 +202,6 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
206
202
|
document.addEventListener(eventType, this.handleCustomClearBound);
|
|
207
203
|
});
|
|
208
204
|
}
|
|
209
|
-
|
|
210
|
-
// Listen for options_event_type to replace options on custom/Turbo events
|
|
211
|
-
const optionsEventTypeString = this.element.dataset.optionsEventType;
|
|
212
|
-
if (optionsEventTypeString) {
|
|
213
|
-
this.optionsEventTypes = optionsEventTypeString
|
|
214
|
-
.split(",")
|
|
215
|
-
.map((e) => e.trim())
|
|
216
|
-
.filter(Boolean);
|
|
217
|
-
this.handleOptionsEventTypeBound = this.handleOptionsEventType.bind(this);
|
|
218
|
-
this.optionsEventTypes.forEach((eventType) => {
|
|
219
|
-
document.addEventListener(eventType, this.handleOptionsEventTypeBound);
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
205
|
}
|
|
223
206
|
|
|
224
207
|
disconnect() {
|
|
@@ -280,22 +263,11 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
280
263
|
if (this.handleSelectEventBound) {
|
|
281
264
|
document.removeEventListener("pb:dropdown:select", this.handleSelectEventBound)
|
|
282
265
|
}
|
|
283
|
-
if (this.handleUpdateOptionsEventBound) {
|
|
284
|
-
document.removeEventListener("pb:dropdown:updateOptions", this.handleUpdateOptionsEventBound)
|
|
285
|
-
}
|
|
286
266
|
if (this.customClearEventTypes && this.handleCustomClearBound) {
|
|
287
267
|
this.customClearEventTypes.forEach((eventType) => {
|
|
288
268
|
document.removeEventListener(eventType, this.handleCustomClearBound)
|
|
289
269
|
})
|
|
290
270
|
}
|
|
291
|
-
if (this.optionsEventTypes && this.handleOptionsEventTypeBound) {
|
|
292
|
-
this.optionsEventTypes.forEach((eventType) => {
|
|
293
|
-
document.removeEventListener(eventType, this.handleOptionsEventTypeBound)
|
|
294
|
-
})
|
|
295
|
-
}
|
|
296
|
-
if (this.contextElement && this.handleContextChangeBound) {
|
|
297
|
-
this.contextElement.removeEventListener("change", this.handleContextChangeBound)
|
|
298
|
-
}
|
|
299
271
|
}
|
|
300
272
|
|
|
301
273
|
updateClearButton() {
|
|
@@ -658,217 +630,6 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
658
630
|
}
|
|
659
631
|
|
|
660
632
|
// ----- External events handling section -----
|
|
661
|
-
|
|
662
|
-
get optionsByContext() {
|
|
663
|
-
return this.element.dataset.pbDropdownOptionsByContext
|
|
664
|
-
? JSON.parse(this.element.dataset.pbDropdownOptionsByContext)
|
|
665
|
-
: null;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
get contextElement() {
|
|
669
|
-
const selector = this.element.dataset.pbDropdownContextSelector;
|
|
670
|
-
if (!selector) return null;
|
|
671
|
-
|
|
672
|
-
return (
|
|
673
|
-
this.element.parentNode?.querySelector(`#${CSS.escape(selector)}`) ||
|
|
674
|
-
this.element.closest(`#${CSS.escape(selector)}`) ||
|
|
675
|
-
document.getElementById(selector)
|
|
676
|
-
);
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
get clearOnContextChange() {
|
|
680
|
-
return this.element.dataset.pbDropdownClearOnContextChange !== "false";
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
bindContextSelector() {
|
|
684
|
-
const contextEl = this.contextElement;
|
|
685
|
-
if (!contextEl || !this.optionsByContext) return;
|
|
686
|
-
|
|
687
|
-
this.handleContextChangeBound = this.handleContextChange.bind(this);
|
|
688
|
-
contextEl.addEventListener("change", this.handleContextChangeBound);
|
|
689
|
-
|
|
690
|
-
// Sync to the current context value on connect (default/restored select), without clearing
|
|
691
|
-
this.applyOptionsForCurrentContext({ clearSelection: false });
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
applyOptionsForCurrentContext({ clearSelection } = {}) {
|
|
695
|
-
if (this.isDisabled || !this.optionsByContext) return;
|
|
696
|
-
|
|
697
|
-
const options = this.optionsByContext[this.contextElement?.value] || [];
|
|
698
|
-
this.replaceOptions(options, {
|
|
699
|
-
clearSelection:
|
|
700
|
-
clearSelection != null ? clearSelection : this.clearOnContextChange,
|
|
701
|
-
});
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
handleContextChange() {
|
|
705
|
-
this.applyOptionsForCurrentContext();
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
normalizeOption(option) {
|
|
709
|
-
const normalized = { ...option };
|
|
710
|
-
if (normalized.id == null && normalized.value != null) {
|
|
711
|
-
normalized.id = normalized.value;
|
|
712
|
-
}
|
|
713
|
-
if (normalized.value == null && normalized.id != null) {
|
|
714
|
-
normalized.value = normalized.id;
|
|
715
|
-
}
|
|
716
|
-
return normalized;
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
getOptionsParent() {
|
|
720
|
-
const container = this.target;
|
|
721
|
-
if (!container) return null;
|
|
722
|
-
|
|
723
|
-
return container.querySelector(".pb_list_kit") || container;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
buildOptionElement(option) {
|
|
727
|
-
const normalized = this.normalizeOption(option);
|
|
728
|
-
const disabled = normalized.disabled === true;
|
|
729
|
-
const optionEl = document.createElement("div");
|
|
730
|
-
optionEl.className = `pb_dropdown_option_list${disabled ? " disabled" : ""}`;
|
|
731
|
-
if (normalized.id != null && normalized.id !== "") {
|
|
732
|
-
optionEl.id = String(normalized.id);
|
|
733
|
-
}
|
|
734
|
-
optionEl.setAttribute("aria-disabled", disabled ? "true" : "false");
|
|
735
|
-
optionEl.dataset.dropdownOptionLabel = JSON.stringify(normalized);
|
|
736
|
-
optionEl.dataset.dropdownOptionDisabled = disabled ? "true" : "false";
|
|
737
|
-
|
|
738
|
-
const listItem = document.createElement("div");
|
|
739
|
-
listItem.className =
|
|
740
|
-
"pb_list_item_kit display_flex justify_content_center p_none cursor_pointer";
|
|
741
|
-
|
|
742
|
-
const wrapper = document.createElement("div");
|
|
743
|
-
wrapper.className = disabled
|
|
744
|
-
? "dropdown_option_wrapper disabled"
|
|
745
|
-
: "dropdown_option_wrapper";
|
|
746
|
-
|
|
747
|
-
const body = document.createElement("div");
|
|
748
|
-
body.className = "pb_body_kit_light";
|
|
749
|
-
body.textContent =
|
|
750
|
-
normalized.label != null ? String(normalized.label) : "";
|
|
751
|
-
|
|
752
|
-
wrapper.appendChild(body);
|
|
753
|
-
listItem.appendChild(wrapper);
|
|
754
|
-
optionEl.appendChild(listItem);
|
|
755
|
-
|
|
756
|
-
return optionEl;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
replaceOptions(options, { clearSelection = true } = {}) {
|
|
760
|
-
if (this.isDisabled || !Array.isArray(options)) return;
|
|
761
|
-
|
|
762
|
-
const parent = this.getOptionsParent();
|
|
763
|
-
if (!parent) return;
|
|
764
|
-
|
|
765
|
-
// Clear option nodes and any SSR empty-state ("No option") placeholder
|
|
766
|
-
parent.replaceChildren();
|
|
767
|
-
this.removeNoOptionsMessage();
|
|
768
|
-
|
|
769
|
-
options.forEach((option) => {
|
|
770
|
-
parent.appendChild(this.buildOptionElement(option));
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
// Clear typed filters and keyboard focus so new options aren't left unfiltered /
|
|
774
|
-
// focused against stale indexes from the previous list
|
|
775
|
-
this.resetInteractiveOptionState();
|
|
776
|
-
|
|
777
|
-
if (clearSelection) {
|
|
778
|
-
this.clearSelection();
|
|
779
|
-
} else {
|
|
780
|
-
this.reconcileSelectionWithOptions();
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
if (this.target?.classList.contains("open")) {
|
|
784
|
-
this.adjustDropdownHeight();
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
resetInteractiveOptionState() {
|
|
789
|
-
this.resetFocus();
|
|
790
|
-
|
|
791
|
-
if (this.searchBar) {
|
|
792
|
-
this.searchBar.value = "";
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
if (this.searchInput) {
|
|
796
|
-
this.searchInput.value = "";
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
reconcileSelectionWithOptions() {
|
|
801
|
-
const optionEls = Array.from(this.queryAllOptions());
|
|
802
|
-
const optionsById = new Map();
|
|
803
|
-
optionEls.forEach((opt) => {
|
|
804
|
-
try {
|
|
805
|
-
const optionData = JSON.parse(opt.dataset.dropdownOptionLabel);
|
|
806
|
-
if (optionData?.id != null) {
|
|
807
|
-
optionsById.set(optionData.id, opt);
|
|
808
|
-
}
|
|
809
|
-
} catch {
|
|
810
|
-
// ignore invalid option payloads
|
|
811
|
-
}
|
|
812
|
-
});
|
|
813
|
-
|
|
814
|
-
if (this.isMultiSelect) {
|
|
815
|
-
const keptIds = Array.from(this.selectedOptions)
|
|
816
|
-
.map((raw) => {
|
|
817
|
-
try {
|
|
818
|
-
return JSON.parse(raw).id;
|
|
819
|
-
} catch {
|
|
820
|
-
return null;
|
|
821
|
-
}
|
|
822
|
-
})
|
|
823
|
-
.filter((id) => id != null && optionsById.has(id));
|
|
824
|
-
|
|
825
|
-
if (keptIds.length === 0) {
|
|
826
|
-
this.clearSelection();
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// Rebuild from current option payloads so labels/values stay in sync
|
|
831
|
-
this.setSelectionByOptionIds(keptIds);
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
const currentId = this.baseInput?.value;
|
|
836
|
-
if (!currentId || !optionsById.has(currentId)) {
|
|
837
|
-
this.clearSelection();
|
|
838
|
-
return;
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
// Re-apply selection so trigger/autocomplete use the updated option payload
|
|
842
|
-
this.setSelectionByOptionId(currentId);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
// Handles pb:dropdown:updateOptions - replace options when event.detail.dropdownId matches.
|
|
846
|
-
// detail: { dropdownId, options: [{ id, label, value }], clearSelection?: boolean }
|
|
847
|
-
handleUpdateOptionsEvent(event) {
|
|
848
|
-
if (this.isDisabled) return;
|
|
849
|
-
const targetId = event.detail?.dropdownId;
|
|
850
|
-
if (!targetId || this.element.id !== targetId) return;
|
|
851
|
-
|
|
852
|
-
const options = event.detail?.options;
|
|
853
|
-
if (!Array.isArray(options)) return;
|
|
854
|
-
|
|
855
|
-
const clearSelection = event.detail?.clearSelection !== false;
|
|
856
|
-
this.replaceOptions(options, { clearSelection });
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// Handles options_event_type events - replace options when detail.options is present.
|
|
860
|
-
handleOptionsEventType(event) {
|
|
861
|
-
if (this.isDisabled) return;
|
|
862
|
-
const targetId = event.detail?.dropdownId;
|
|
863
|
-
if (targetId != null && this.element.id !== targetId) return;
|
|
864
|
-
|
|
865
|
-
const options = event.detail?.options;
|
|
866
|
-
if (!Array.isArray(options)) return;
|
|
867
|
-
|
|
868
|
-
const clearSelection = event.detail?.clearSelection !== false;
|
|
869
|
-
this.replaceOptions(options, { clearSelection });
|
|
870
|
-
}
|
|
871
|
-
|
|
872
633
|
// Handles pb:dropdown:clear - clear this dropdown when event.detail.dropdownId matches.
|
|
873
634
|
handleClearEvent(event) {
|
|
874
635
|
if (this.isDisabled) return;
|