playbook_ui 16.1.0.pre.alpha.play264213818 → 16.1.0.pre.alpha.play277814027
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_advanced_table/Components/RegularTableView.tsx +12 -2
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +33 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background_custom.jsx +71 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling_background_custom.md +4 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_card/docs/_card_light.html.erb +3 -35
- data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +14 -5
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_default.md +1 -0
- data/app/pb_kits/playbook/pb_dialog/_dialog.scss +8 -6
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +6 -0
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +37 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection_rails.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection_react.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_clearable.html.erb +52 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_clearable.jsx +72 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_clearable.md +5 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_constrain_height.jsx +33 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_constrain_height_rails.html.erb +20 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_constrain_height_rails.md +8 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_constrain_height_react.md +8 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_placeholder.html.erb +9 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_placeholder.jsx +33 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_placeholder.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +6 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +4 -1
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +2 -2
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +6 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +94 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown_container.rb +5 -1
- data/app/pb_kits/playbook/pb_dropdown/index.js +59 -4
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +3 -0
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +2 -1
- data/app/pb_kits/playbook/pb_filter/Filter/SortMenu.tsx +1 -1
- data/app/pb_kits/playbook/pb_filter/docs/_filter_default.html.erb +2 -2
- data/app/pb_kits/playbook/pb_filter/docs/_filter_default.jsx +16 -9
- data/app/pb_kits/playbook/pb_filter/filter.rb +2 -2
- data/app/pb_kits/playbook/pb_form/docs/_form_with_required_indicator.html.erb +2 -0
- data/app/pb_kits/playbook/pb_form/pb_form_validation.js +9 -2
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.html.erb +5 -5
- data/app/pb_kits/playbook/pb_form_pill/docs/_form_pill_truncated_text.jsx +4 -4
- data/app/pb_kits/playbook/pb_form_pill/form_pill.rb +4 -0
- data/app/pb_kits/playbook/pb_passphrase/_passphrase.tsx +20 -5
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_meter_settings.jsx +1 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_required_indicator.html.erb +7 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_required_indicator.jsx +24 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/_passphrase_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_passphrase/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.rb +2 -0
- data/app/pb_kits/playbook/pb_passphrase/passphrase.test.jsx +30 -1
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +3 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_required_indicator.html.erb +5 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_required_indicator.jsx +14 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.rb +3 -0
- data/app/pb_kits/playbook/pb_phone_number_input/phone_number_input.test.js +34 -3
- data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +10 -0
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_default.html.erb +3 -3
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_default.jsx +3 -0
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_default.md +1 -0
- data/app/pb_kits/playbook/pb_textarea/textarea.html.erb +25 -9
- data/app/pb_kits/playbook/pb_textarea/textarea.rb +7 -1
- data/app/pb_kits/playbook/pb_time_picker/_time_picker.tsx +97 -11
- data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_on_handler.jsx +5 -2
- data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_required_indicator.html.erb +6 -0
- data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_required_indicator.jsx +16 -0
- data/app/pb_kits/playbook/pb_time_picker/docs/_time_picker_required_indicator.md +3 -0
- data/app/pb_kits/playbook/pb_time_picker/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_time_picker/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_time_picker/time_picker.rb +3 -0
- data/app/pb_kits/playbook/pb_time_picker/time_picker.test.jsx +47 -1
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +24 -1
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +2 -1
- data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.tsx +4 -1
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_truncated_text.html.erb +1 -1
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_truncated_text.jsx +1 -1
- data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +4 -0
- data/dist/chunks/_typeahead-CWA5wlah.js +1 -0
- data/dist/chunks/vendor.js +3 -3
- data/dist/menu.yml +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/forms/builder/phone_number_field.rb +9 -0
- data/lib/playbook/truncate.rb +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +28 -3
- data/dist/chunks/_typeahead-B9a6ZsEP.js +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Dropdown from '../../pb_dropdown/_dropdown'
|
|
3
|
+
|
|
4
|
+
const DropdownWithPlaceholder = (props) => {
|
|
5
|
+
|
|
6
|
+
const options = [
|
|
7
|
+
{
|
|
8
|
+
label: "United States",
|
|
9
|
+
value: "unitedStates",
|
|
10
|
+
id: "us"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
label: "Canada",
|
|
14
|
+
value: "canada",
|
|
15
|
+
id: "ca"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
label: "Pakistan",
|
|
19
|
+
value: "pakistan",
|
|
20
|
+
id: "pk"
|
|
21
|
+
}
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Dropdown
|
|
26
|
+
options={options}
|
|
27
|
+
placeholder="Choose a country"
|
|
28
|
+
{...props}
|
|
29
|
+
/>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default DropdownWithPlaceholder
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
The `placeholder` prop allows you to customize the placeholder text that appears when no option is selected in the dropdown.
|
|
2
|
+
|
|
3
|
+
The placeholder prop works with all dropdown variants (`default`, `subtle`, and `quickpick`). When no option is selected, the placeholder text is displayed. When an option is selected, the placeholder is replaced by the selected option's label. The default placeholder text is "Select..." if no placeholder is provided.
|
|
@@ -21,7 +21,10 @@ examples:
|
|
|
21
21
|
- dropdown_default_value: Default Value
|
|
22
22
|
- dropdown_multi_select_with_default: Multi Select Default Value
|
|
23
23
|
- dropdown_blank_selection: Blank Selection
|
|
24
|
+
- dropdown_with_placeholder: Placeholder
|
|
24
25
|
- dropdown_separators_hidden: Separators Hidden
|
|
26
|
+
- dropdown_with_clearable: Clearable
|
|
27
|
+
- dropdown_with_constrain_height_rails: Constrain Height
|
|
25
28
|
- dropdown_quickpick_rails: Quick Pick Variant
|
|
26
29
|
- dropdown_quickpick_range_end_rails: Quick Pick Variant (Range Ends Today)
|
|
27
30
|
- dropdown_quickpick_default_dates: Quick Pick Variant (Default Dates)
|
|
@@ -52,7 +55,10 @@ examples:
|
|
|
52
55
|
- dropdown_default_value: Default Value
|
|
53
56
|
- dropdown_multi_select_with_default: Multi Select Default Value
|
|
54
57
|
- dropdown_blank_selection: Blank Selection
|
|
58
|
+
- dropdown_with_placeholder: Placeholder
|
|
55
59
|
- dropdown_clear_selection: Clear Selection
|
|
60
|
+
- dropdown_with_clearable: Clearable
|
|
61
|
+
- dropdown_with_constrain_height: Constrain Height
|
|
56
62
|
- dropdown_separators_hidden: Separators Hidden
|
|
57
63
|
- dropdown_with_external_control: useDropdown Hook
|
|
58
64
|
- dropdown_quickpick: Quick Pick Variant
|
|
@@ -11,6 +11,7 @@ export { default as DropdownSubcomponentStructure } from './_dropdown_subcompone
|
|
|
11
11
|
export { default as DropdownError } from './_dropdown_error.jsx'
|
|
12
12
|
export { default as DropdownDefaultValue } from './_dropdown_default_value.jsx'
|
|
13
13
|
export { default as DropdownBlankSelection } from './_dropdown_blank_selection.jsx'
|
|
14
|
+
export { default as DropdownWithPlaceholder } from './_dropdown_with_placeholder.jsx'
|
|
14
15
|
export { default as DropdownClearSelection } from './_dropdown_clear_selection.jsx'
|
|
15
16
|
export { default as DropdownSubtleVariant } from './_dropdown_subtle_variant.jsx'
|
|
16
17
|
export { default as DropdownSeparatorsHidden } from './_dropdown_separators_hidden.jsx'
|
|
@@ -27,4 +28,6 @@ export { default as DropdownQuickpick } from './_dropdown_quickpick.jsx'
|
|
|
27
28
|
export { default as DropdownQuickpickRangeEnd } from './_dropdown_quickpick_range_end.jsx'
|
|
28
29
|
export { default as DropdownQuickpickDefaultDates } from './_dropdown_quickpick_default_dates.jsx'
|
|
29
30
|
export { default as DropdownQuickpickWithDatePickers } from './_dropdown_quickpick_with_date_pickers.jsx'
|
|
30
|
-
export { default as DropdownQuickpickCustom } from './_dropdown_quickpick_custom.jsx'
|
|
31
|
+
export { default as DropdownQuickpickCustom } from './_dropdown_quickpick_custom.jsx'
|
|
32
|
+
export { default as DropdownWithClearable } from './_dropdown_with_clearable.jsx'
|
|
33
|
+
export { default as DropdownWithConstrainHeight } from './_dropdown_with_constrain_height.jsx'
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
<%= content.presence %>
|
|
19
19
|
<%= pb_rails("body", props: { status: "negative", text: object.error }) %>
|
|
20
20
|
<% else %>
|
|
21
|
-
<%= pb_rails("dropdown/dropdown_trigger", props:{ autocomplete: object.autocomplete, multi_select:object.multi_select }) %>
|
|
22
|
-
<%= pb_rails("dropdown/dropdown_container", props: { searchbar: object.searchbar }) do %>
|
|
21
|
+
<%= pb_rails("dropdown/dropdown_trigger", props:{ autocomplete: object.autocomplete, multi_select:object.multi_select, placeholder: object.placeholder }) %>
|
|
22
|
+
<%= pb_rails("dropdown/dropdown_container", props: { searchbar: object.searchbar, constrain_height: object.constrain_height }) do %>
|
|
23
23
|
<% if options_with_blank.present? %>
|
|
24
24
|
<% options_with_blank.each do |option| %>
|
|
25
25
|
<%= pb_rails("dropdown/dropdown_option", props: {option: option}) %>
|
|
@@ -36,6 +36,8 @@ module Playbook
|
|
|
36
36
|
default: ""
|
|
37
37
|
prop :controls_start_id, type: Playbook::Props::String,
|
|
38
38
|
default: ""
|
|
39
|
+
prop :clearable, type: Playbook::Props::Boolean,
|
|
40
|
+
default: true
|
|
39
41
|
prop :start_date_id, type: Playbook::Props::String,
|
|
40
42
|
default: "start_date_id"
|
|
41
43
|
prop :start_date_name, type: Playbook::Props::String,
|
|
@@ -44,12 +46,16 @@ module Playbook
|
|
|
44
46
|
default: "end_date_id"
|
|
45
47
|
prop :end_date_name, type: Playbook::Props::String,
|
|
46
48
|
default: "end_date_name"
|
|
49
|
+
prop :placeholder, type: Playbook::Props::String
|
|
50
|
+
prop :constrain_height, type: Playbook::Props::Boolean,
|
|
51
|
+
default: false
|
|
47
52
|
|
|
48
53
|
def data
|
|
49
54
|
Hash(prop(:data)).merge(
|
|
50
55
|
pb_dropdown: true,
|
|
51
56
|
pb_dropdown_multi_select: multi_select,
|
|
52
57
|
pb_dropdown_variant: variant,
|
|
58
|
+
pb_dropdown_clearable: clearable,
|
|
53
59
|
form_pill_props: form_pill_props.to_json,
|
|
54
60
|
start_date_id: variant == "quickpick" ? start_date_id : nil,
|
|
55
61
|
end_date_id: variant == "quickpick" ? end_date_id : nil,
|
|
@@ -122,6 +122,80 @@ test('generated placeholder prop', () => {
|
|
|
122
122
|
|
|
123
123
|
})
|
|
124
124
|
|
|
125
|
+
test('placeholder prop passed directly to Dropdown', () => {
|
|
126
|
+
render(
|
|
127
|
+
<Dropdown
|
|
128
|
+
data={{ testid: testId }}
|
|
129
|
+
options={options}
|
|
130
|
+
placeholder="Choose a country"
|
|
131
|
+
/>
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
const kit = screen.getByTestId(testId)
|
|
135
|
+
const trigger = kit.querySelector('.pb_dropdown_trigger')
|
|
136
|
+
expect(trigger).toHaveTextContent('Choose a country')
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
test('placeholder works with default variant', () => {
|
|
140
|
+
render(
|
|
141
|
+
<Dropdown
|
|
142
|
+
data={{ testid: testId }}
|
|
143
|
+
options={options}
|
|
144
|
+
placeholder="Select an option"
|
|
145
|
+
variant="default"
|
|
146
|
+
/>
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
const kit = screen.getByTestId(testId)
|
|
150
|
+
const trigger = kit.querySelector('.pb_dropdown_trigger')
|
|
151
|
+
expect(trigger).toHaveTextContent('Select an option')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('placeholder works with subtle variant', () => {
|
|
155
|
+
render(
|
|
156
|
+
<Dropdown
|
|
157
|
+
data={{ testid: testId }}
|
|
158
|
+
options={options}
|
|
159
|
+
placeholder="Pick an option"
|
|
160
|
+
separators={false}
|
|
161
|
+
variant="subtle"
|
|
162
|
+
/>
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
const kit = screen.getByTestId(testId)
|
|
166
|
+
expect(kit).toHaveClass('pb_dropdown_subtle_separators_hidden')
|
|
167
|
+
const trigger = kit.querySelector('.pb_dropdown_trigger')
|
|
168
|
+
expect(trigger).toHaveTextContent('Pick an option')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
test('placeholder works with quickpick variant', () => {
|
|
172
|
+
render(
|
|
173
|
+
<Dropdown
|
|
174
|
+
data={{ testid: testId }}
|
|
175
|
+
placeholder="Select a date range"
|
|
176
|
+
variant="quickpick"
|
|
177
|
+
/>
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
const kit = screen.getByTestId(testId)
|
|
181
|
+
expect(kit).toHaveClass('pb_dropdown_quickpick')
|
|
182
|
+
const trigger = kit.querySelector('.pb_dropdown_trigger')
|
|
183
|
+
expect(trigger).toHaveTextContent('Select a date range')
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
test('placeholder shows default "Select..." when not provided', () => {
|
|
187
|
+
render(
|
|
188
|
+
<Dropdown
|
|
189
|
+
data={{ testid: testId }}
|
|
190
|
+
options={options}
|
|
191
|
+
/>
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
const kit = screen.getByTestId(testId)
|
|
195
|
+
const trigger = kit.querySelector('.pb_dropdown_trigger')
|
|
196
|
+
expect(trigger).toHaveTextContent('Select...')
|
|
197
|
+
})
|
|
198
|
+
|
|
125
199
|
test('generated label prop', () => {
|
|
126
200
|
render (
|
|
127
201
|
<Dropdown
|
|
@@ -466,7 +540,27 @@ test("quickpick clears selection when clicking X icon", () => {
|
|
|
466
540
|
expect(trigger).toHaveTextContent("Select...")
|
|
467
541
|
})
|
|
468
542
|
|
|
543
|
+
test("quickpick hides clear icon when clearable is false", () => {
|
|
544
|
+
render(
|
|
545
|
+
<Dropdown
|
|
546
|
+
clearable={false}
|
|
547
|
+
data={{ testid: testId }}
|
|
548
|
+
defaultValue="This Week"
|
|
549
|
+
variant="quickpick"
|
|
550
|
+
/>
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
const kit = screen.getByTestId(testId)
|
|
554
|
+
const trigger = kit.querySelector('.pb_dropdown_trigger')
|
|
555
|
+
|
|
556
|
+
expect(trigger).toHaveTextContent("This Week")
|
|
557
|
+
|
|
558
|
+
const clearIcon = kit.querySelector('[aria-label="times icon"]')
|
|
559
|
+
expect(clearIcon).not.toBeInTheDocument()
|
|
560
|
+
})
|
|
561
|
+
|
|
469
562
|
test("quickpick returns date array values when option selected", () => {
|
|
563
|
+
// eslint-disable-next-line react/no-multi-comp
|
|
470
564
|
const TestComponent = () => {
|
|
471
565
|
const [selected, setSelected] = useState(null)
|
|
472
566
|
return (
|
|
@@ -5,9 +5,13 @@ module Playbook
|
|
|
5
5
|
class DropdownContainer < Playbook::KitBase
|
|
6
6
|
prop :searchbar, type: Playbook::Props::Boolean,
|
|
7
7
|
default: false
|
|
8
|
+
prop :constrain_height, type: Playbook::Props::Boolean,
|
|
9
|
+
default: false
|
|
8
10
|
|
|
9
11
|
def classname
|
|
10
|
-
|
|
12
|
+
classes = %w[pb_dropdown_container close]
|
|
13
|
+
classes << "constrain_height" if constrain_height
|
|
14
|
+
generate_classname(*classes, separator: " ")
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def data
|
|
@@ -48,6 +48,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
48
48
|
this.updatePills();
|
|
49
49
|
|
|
50
50
|
this.clearBtn = this.element.querySelector(CLEAR_ICON_SELECTOR);
|
|
51
|
+
this.isClearable = this.element.dataset.pbDropdownClearable !== "false";
|
|
51
52
|
if (this.clearBtn) {
|
|
52
53
|
this.clearBtn.style.display = "none";
|
|
53
54
|
this.clearBtn.addEventListener("click", (e) => {
|
|
@@ -60,6 +61,10 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
60
61
|
|
|
61
62
|
updateClearButton() {
|
|
62
63
|
if (!this.clearBtn) return;
|
|
64
|
+
if (!this.isClearable) {
|
|
65
|
+
this.clearBtn.style.display = "none";
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
63
68
|
const hasSelection = this.isMultiSelect
|
|
64
69
|
? this.selectedOptions.size > 0
|
|
65
70
|
: Boolean(this.element.querySelector(DROPDOWN_INPUT).value);
|
|
@@ -109,15 +114,51 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
109
114
|
adjustDropdownHeight() {
|
|
110
115
|
if (this.target.classList.contains("open")) {
|
|
111
116
|
const el = this.target;
|
|
117
|
+
const shouldConstrain = el.classList.contains("constrain_height");
|
|
112
118
|
el.style.height = "auto";
|
|
113
119
|
requestAnimationFrame(() => {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
120
|
+
if (shouldConstrain) {
|
|
121
|
+
// Calculate 18em in pixels (matches SCSS max-height: 18em)
|
|
122
|
+
const fontSize = parseFloat(getComputedStyle(el).fontSize) || 16;
|
|
123
|
+
const maxHeight = fontSize * 18;
|
|
124
|
+
const scrollHeight = el.scrollHeight;
|
|
125
|
+
const newHeight = Math.min(scrollHeight, maxHeight);
|
|
126
|
+
el.offsetHeight; // force reflow
|
|
127
|
+
el.style.height = newHeight + "px";
|
|
128
|
+
} else {
|
|
129
|
+
el.offsetHeight; // force reflow
|
|
130
|
+
el.style.height = el.scrollHeight + "px";
|
|
131
|
+
}
|
|
117
132
|
});
|
|
118
133
|
}
|
|
119
134
|
}
|
|
120
135
|
|
|
136
|
+
adjustDropdownPosition(container) {
|
|
137
|
+
if (!container) return;
|
|
138
|
+
|
|
139
|
+
const wrapper = this.element.querySelector(".dropdown_wrapper");
|
|
140
|
+
if (!wrapper) return;
|
|
141
|
+
|
|
142
|
+
const wrapperRect = wrapper.getBoundingClientRect();
|
|
143
|
+
const h = container.getBoundingClientRect().height || container.scrollHeight;
|
|
144
|
+
const spaceBelow = window.innerHeight - wrapperRect.bottom;
|
|
145
|
+
const spaceAbove = wrapperRect.top;
|
|
146
|
+
|
|
147
|
+
// If not enough space below but enough space above, position above
|
|
148
|
+
if (spaceBelow < h + 10 && spaceAbove >= h + 10) {
|
|
149
|
+
container.style.top = "auto";
|
|
150
|
+
container.style.bottom = "calc(100% + 5px)";
|
|
151
|
+
container.style.marginTop = "0";
|
|
152
|
+
container.style.marginBottom = "0";
|
|
153
|
+
} else {
|
|
154
|
+
// Default: position below
|
|
155
|
+
container.style.top = "";
|
|
156
|
+
container.style.bottom = "";
|
|
157
|
+
container.style.marginTop = "";
|
|
158
|
+
container.style.marginBottom = "";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
121
162
|
handleSearch(term = "") {
|
|
122
163
|
const lcTerm = term.toLowerCase();
|
|
123
164
|
let hasMatch = false
|
|
@@ -365,7 +406,21 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
365
406
|
showElement(elem) {
|
|
366
407
|
elem.classList.remove("close");
|
|
367
408
|
elem.classList.add("open");
|
|
368
|
-
|
|
409
|
+
|
|
410
|
+
const shouldConstrain = elem.classList.contains("constrain_height");
|
|
411
|
+
if (shouldConstrain) {
|
|
412
|
+
// Calculate height respecting max-height constraint (18em)
|
|
413
|
+
const fontSize = parseFloat(getComputedStyle(elem).fontSize) || 16;
|
|
414
|
+
const maxHeight = fontSize * 18; // matches SCSS max-height: 18em
|
|
415
|
+
const scrollHeight = elem.scrollHeight;
|
|
416
|
+
const height = Math.min(scrollHeight, maxHeight);
|
|
417
|
+
elem.style.height = height + "px";
|
|
418
|
+
} else {
|
|
419
|
+
elem.style.height = elem.scrollHeight + "px";
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Auto-position dropdown above if not enough space below
|
|
423
|
+
this.adjustDropdownPosition(elem);
|
|
369
424
|
}
|
|
370
425
|
|
|
371
426
|
hideElement(elem) {
|
|
@@ -19,6 +19,7 @@ type DropdownContainerProps = {
|
|
|
19
19
|
aria?: { [key: string]: string };
|
|
20
20
|
children?: React.ReactChild[] | React.ReactChild;
|
|
21
21
|
className?: string;
|
|
22
|
+
constrainHeight?: boolean;
|
|
22
23
|
dark?: boolean;
|
|
23
24
|
data?: { [key: string]: string };
|
|
24
25
|
htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
|
|
@@ -31,6 +32,7 @@ const DropdownContainer = (props: DropdownContainerProps) => {
|
|
|
31
32
|
aria = {},
|
|
32
33
|
children,
|
|
33
34
|
className,
|
|
35
|
+
constrainHeight = false,
|
|
34
36
|
dark = false,
|
|
35
37
|
data = {},
|
|
36
38
|
htmlOptions = {},
|
|
@@ -54,6 +56,7 @@ const DropdownContainer = (props: DropdownContainerProps) => {
|
|
|
54
56
|
const classes = classnames(
|
|
55
57
|
buildCss("pb_dropdown_container"),
|
|
56
58
|
`${isDropDownClosed ? "close" : "open"}`,
|
|
59
|
+
constrainHeight && "constrain_height",
|
|
57
60
|
globalProps(props),
|
|
58
61
|
className
|
|
59
62
|
);
|
|
@@ -44,6 +44,7 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
44
44
|
|
|
45
45
|
const {
|
|
46
46
|
autocomplete,
|
|
47
|
+
clearable,
|
|
47
48
|
filterItem,
|
|
48
49
|
handleBackspace,
|
|
49
50
|
handleChange,
|
|
@@ -225,7 +226,7 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
225
226
|
key={`${isDropDownClosed ? "chevron-down" : "chevron-up"}`}
|
|
226
227
|
>
|
|
227
228
|
{
|
|
228
|
-
selectedArray.length > 0 && (
|
|
229
|
+
clearable !== false && selectedArray.length > 0 && (
|
|
229
230
|
<div onClick={(e)=>{e.stopPropagation();handleBackspace()}}>
|
|
230
231
|
<Icon
|
|
231
232
|
cursor="pointer"
|
|
@@ -21,7 +21,7 @@ const nextValue = (value: SortValue[], name: string): SortValue => {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const directionIcon = (dir: Direction) => (
|
|
24
|
-
dir == 'asc' ? '
|
|
24
|
+
dir == 'asc' ? 'arrow-up-short-wide' : 'arrow-down-wide-short'
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
const renderOptions = (options: SortOptions, value: SortValue[], handleChange: (arg0: SortValue) => void) => (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<%=
|
|
2
2
|
pb_rails("filter", props: {
|
|
3
3
|
min_width: "360px",
|
|
4
|
-
id: "1",
|
|
4
|
+
id: "filter-demo-1",
|
|
5
5
|
margin_bottom: "xl",
|
|
6
6
|
filters: [
|
|
7
7
|
{ name: "name", value: "John Wick" },
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
<%=
|
|
45
45
|
pb_rails("filter", props: {
|
|
46
46
|
min_width: "360px",
|
|
47
|
-
id: "
|
|
47
|
+
id: "filter-demo-2",
|
|
48
48
|
sort_menu: [
|
|
49
49
|
{ item: "Popularity", link: "?q[sorts]=managers_popularity+asc", active: true, direction: "desc" },
|
|
50
50
|
{ item: "Mananger's Title", link: "?q[sorts]=managers_title+asc", active: false },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react'
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import Button from '../../pb_button/_button'
|
|
4
4
|
import Filter from '../../pb_filter/_filter'
|
|
@@ -6,11 +6,18 @@ import Flex from '../../pb_flex/_flex'
|
|
|
6
6
|
import Select from '../../pb_select/_select'
|
|
7
7
|
import TextInput from '../../pb_text_input/_text_input'
|
|
8
8
|
|
|
9
|
-
const SortingChangeCallback = (sortOptions) => {
|
|
10
|
-
alert(JSON.stringify(sortOptions[0]))
|
|
11
|
-
}
|
|
12
|
-
|
|
13
9
|
const FilterDefault = (props) => {
|
|
10
|
+
const [sortValue, setSortValue] = useState([{ name: 'popularity', dir: 'desc' }])
|
|
11
|
+
const [sortValue2, setSortValue2] = useState([{ name: 'popularity', dir: 'desc' }])
|
|
12
|
+
|
|
13
|
+
const handleSortChange = (sortOptions) => {
|
|
14
|
+
setSortValue(sortOptions)
|
|
15
|
+
alert(JSON.stringify(sortOptions[0]))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const handleSortChange2 = (sortOptions) => {
|
|
19
|
+
setSortValue2(sortOptions)
|
|
20
|
+
}
|
|
14
21
|
const options = [
|
|
15
22
|
{ value: 'USA' },
|
|
16
23
|
{ value: 'Canada' },
|
|
@@ -29,7 +36,7 @@ const FilterDefault = (props) => {
|
|
|
29
36
|
}}
|
|
30
37
|
marginBottom="xl"
|
|
31
38
|
minWidth="375px"
|
|
32
|
-
onSortChange={
|
|
39
|
+
onSortChange={handleSortChange}
|
|
33
40
|
results={1}
|
|
34
41
|
sortOptions={{
|
|
35
42
|
popularity: 'Popularity',
|
|
@@ -38,7 +45,7 @@ const FilterDefault = (props) => {
|
|
|
38
45
|
// eslint-disable-next-line
|
|
39
46
|
manager_name: 'Manager\'s Name',
|
|
40
47
|
}}
|
|
41
|
-
sortValue={
|
|
48
|
+
sortValue={sortValue}
|
|
42
49
|
{...props}
|
|
43
50
|
>
|
|
44
51
|
{({ closePopover }) => (
|
|
@@ -82,7 +89,7 @@ const FilterDefault = (props) => {
|
|
|
82
89
|
<Filter
|
|
83
90
|
double
|
|
84
91
|
minWidth="375px"
|
|
85
|
-
onSortChange={
|
|
92
|
+
onSortChange={handleSortChange2}
|
|
86
93
|
results={0}
|
|
87
94
|
sortOptions={{
|
|
88
95
|
popularity: 'Popularity',
|
|
@@ -91,7 +98,7 @@ const FilterDefault = (props) => {
|
|
|
91
98
|
// eslint-disable-next-line
|
|
92
99
|
manager_name: 'Manager\'s Name',
|
|
93
100
|
}}
|
|
94
|
-
sortValue={
|
|
101
|
+
sortValue={sortValue2}
|
|
95
102
|
{...props}
|
|
96
103
|
>
|
|
97
104
|
{({ closePopover }) => (
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
<%= form.search_field :example_search_field, props: { label: true, required: true, required_indicator: true } %>
|
|
9
9
|
<%= form.password_field :example_password_field, props: { label: true, required: true, required_indicator: true } %>
|
|
10
10
|
<%= form.url_field :example_url_field, props: { label: true, required: true, required_indicator: true } %>
|
|
11
|
+
<%= form.phone_number_field :example_phone_number_field, props: { label: true, required: true, required_indicator: true } %>
|
|
12
|
+
<%= form.time_picker :example_time_picker_required_indicator, props: { label: true, required: true, required_indicator: true } %>
|
|
11
13
|
|
|
12
14
|
<%= form.actions do |action| %>
|
|
13
15
|
<%= action.submit %>
|
|
@@ -26,6 +26,10 @@ class PbFormValidation extends PbEnhancedElement {
|
|
|
26
26
|
const isPhoneNumberInput = field.closest('.pb_phone_number_input')
|
|
27
27
|
if (isPhoneNumberInput) return
|
|
28
28
|
|
|
29
|
+
// Skip TimePicker inputs - they handle their own validation
|
|
30
|
+
const isTimePickerInput = field.closest('.pb_time_picker')
|
|
31
|
+
if (isTimePickerInput) return
|
|
32
|
+
|
|
29
33
|
FIELD_EVENTS.forEach((e) => {
|
|
30
34
|
field.addEventListener(e, debounce((event) => {
|
|
31
35
|
this.validateFormField(event)
|
|
@@ -67,13 +71,16 @@ class PbFormValidation extends PbEnhancedElement {
|
|
|
67
71
|
|
|
68
72
|
// Check if this is a phone number input
|
|
69
73
|
const isPhoneNumberInput = kitElement.classList.contains('pb_phone_number_input')
|
|
74
|
+
|
|
75
|
+
// Check if this is a TimePicker input
|
|
76
|
+
const isTimePickerInput = kitElement.classList.contains('pb_time_picker')
|
|
70
77
|
|
|
71
78
|
// ensure clean error message state
|
|
72
79
|
this.clearError(target)
|
|
73
80
|
kitElement.classList.add('error')
|
|
74
81
|
|
|
75
|
-
// Only add error message if it's NOT a phone number input
|
|
76
|
-
if (!isPhoneNumberInput) {
|
|
82
|
+
// Only add error message if it's NOT a phone number input or TimePicker input
|
|
83
|
+
if (!isPhoneNumberInput && !isTimePickerInput) {
|
|
77
84
|
// set the error message element
|
|
78
85
|
const errorMessageContainer = this.errorMessageContainer
|
|
79
86
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
options: names,
|
|
16
16
|
label: "Truncation Within Typeahead",
|
|
17
17
|
pills: true,
|
|
18
|
-
truncate: 1,
|
|
18
|
+
truncate: "1",
|
|
19
19
|
}) %>
|
|
20
20
|
|
|
21
21
|
<%= pb_rails("caption", props: { text: "Form Pill Truncation" }) %>
|
|
@@ -24,19 +24,19 @@
|
|
|
24
24
|
name: "Princess Amelia Mignonette Grimaldi Thermopolis Renaldo",
|
|
25
25
|
avatar_url: "https://randomuser.me/api/portraits/women/44.jpg",
|
|
26
26
|
tabindex: 0,
|
|
27
|
-
truncate: 1,
|
|
27
|
+
truncate: "1",
|
|
28
28
|
id: "truncation-1"
|
|
29
29
|
}) %>
|
|
30
30
|
<%= pb_rails("form_pill", props: {
|
|
31
31
|
icon: "badge-check",
|
|
32
32
|
text: "icon and a very long tag to show truncation",
|
|
33
33
|
tabindex: 0,
|
|
34
|
-
truncate: 1,
|
|
34
|
+
truncate: "1",
|
|
35
35
|
id: "truncation-2"
|
|
36
36
|
}) %>
|
|
37
37
|
<%= pb_rails("form_pill", props: {
|
|
38
38
|
text: "form pill long tag no tooltip show truncation",
|
|
39
39
|
tabindex: 0,
|
|
40
|
-
truncate: 1,
|
|
40
|
+
truncate: "1",
|
|
41
41
|
}) %>
|
|
42
|
-
<% end %>
|
|
42
|
+
<% end %>
|
|
@@ -21,7 +21,7 @@ const FormPillTruncatedText = (props) => {
|
|
|
21
21
|
isMulti
|
|
22
22
|
label="Truncation Within Typeahead"
|
|
23
23
|
options={names}
|
|
24
|
-
truncate={1}
|
|
24
|
+
truncate={"1"}
|
|
25
25
|
{...props}
|
|
26
26
|
/>
|
|
27
27
|
<Caption text="Form Pill Truncation"/>
|
|
@@ -31,20 +31,20 @@ const FormPillTruncatedText = (props) => {
|
|
|
31
31
|
name="Princess Amelia Mignonette Grimaldi Thermopolis Renaldo"
|
|
32
32
|
onClick={() => alert('Click!')}
|
|
33
33
|
tabIndex={0}
|
|
34
|
-
truncate={1}
|
|
34
|
+
truncate={"1"}
|
|
35
35
|
/>
|
|
36
36
|
<FormPill
|
|
37
37
|
icon="badge-check"
|
|
38
38
|
onClick={() => {alert('Click!')}}
|
|
39
39
|
tabIndex={0}
|
|
40
40
|
text="icon and a very long tag to show truncation"
|
|
41
|
-
truncate={1}
|
|
41
|
+
truncate={"1"}
|
|
42
42
|
/>
|
|
43
43
|
<FormPill
|
|
44
44
|
onClick={() => {alert('Click!')}}
|
|
45
45
|
tabIndex={0}
|
|
46
46
|
text="form pill with a very long tag to show truncation"
|
|
47
|
-
truncate={1}
|
|
47
|
+
truncate={"1"}
|
|
48
48
|
/>
|
|
49
49
|
</Card>
|
|
50
50
|
</>
|
|
@@ -7,6 +7,7 @@ import { globalProps } from "../utilities/globalProps"
|
|
|
7
7
|
import Body from '../pb_body/_body'
|
|
8
8
|
import Caption from '../pb_caption/_caption'
|
|
9
9
|
import CircleIconButton from '../pb_circle_icon_button/_circle_icon_button'
|
|
10
|
+
import colors from '../tokens/exports/_colors.module.scss'
|
|
10
11
|
import Flex from '../pb_flex/_flex'
|
|
11
12
|
import Icon from '../pb_icon/_icon'
|
|
12
13
|
import PbReactPopover from '../pb_popover/_popover'
|
|
@@ -25,6 +26,7 @@ type PassphraseProps = {
|
|
|
25
26
|
inputProps?: GenericObject,
|
|
26
27
|
label?: string,
|
|
27
28
|
onChange: (inputValue: string) => void,
|
|
29
|
+
requiredIndicator?: boolean,
|
|
28
30
|
showTipsBelow?: "always" | "xs" | "sm" | "md" | "lg" | "xl",
|
|
29
31
|
tips?: Array<string>,
|
|
30
32
|
uncontrolled?: boolean,
|
|
@@ -43,6 +45,7 @@ const Passphrase = (props: PassphraseProps): React.ReactElement => {
|
|
|
43
45
|
inputProps = {},
|
|
44
46
|
label = confirmation ? "Confirm Passphrase" : "Passphrase",
|
|
45
47
|
onChange = () => undefined,
|
|
48
|
+
requiredIndicator = false,
|
|
46
49
|
showTipsBelow = "always",
|
|
47
50
|
tips = [],
|
|
48
51
|
uncontrolled = false,
|
|
@@ -99,6 +102,7 @@ const Passphrase = (props: PassphraseProps): React.ReactElement => {
|
|
|
99
102
|
|
|
100
103
|
const shieldIcon = getAllIcons()["shieldCheck"]
|
|
101
104
|
const eyeIcon = getAllIcons()["eye"]
|
|
105
|
+
const hasLabel = label && label !== ""
|
|
102
106
|
|
|
103
107
|
return (
|
|
104
108
|
<div
|
|
@@ -109,11 +113,22 @@ const Passphrase = (props: PassphraseProps): React.ReactElement => {
|
|
|
109
113
|
id={id}
|
|
110
114
|
>
|
|
111
115
|
<label>
|
|
112
|
-
<Flex
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
<Flex
|
|
117
|
+
align="baseline"
|
|
118
|
+
{...(hasLabel ? { marginBottom: "xs" } : {})}
|
|
119
|
+
>
|
|
120
|
+
{hasLabel && (requiredIndicator ? (
|
|
121
|
+
<Caption
|
|
122
|
+
className="passphrase-label"
|
|
123
|
+
>
|
|
124
|
+
{label} <span style={{ color: `${colors.error}` }}>*</span>
|
|
125
|
+
</Caption>
|
|
126
|
+
) : (
|
|
127
|
+
<Caption
|
|
128
|
+
className="passphrase-label"
|
|
129
|
+
text={label}
|
|
130
|
+
/>
|
|
131
|
+
))}
|
|
117
132
|
{tips.length > 0 && !confirmation &&
|
|
118
133
|
<PbReactPopover
|
|
119
134
|
className="passphrase-tips"
|