playbook_ui 16.7.0.pre.alpha.play2924tooltipmisalignment16242 → 16.7.0.pre.alpha.play2924tooltipmisalignment16289
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_date_picker/_date_picker.tsx +22 -3
- data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +10 -7
- data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +14 -1
- data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +57 -0
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.html.erb +0 -2
- data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_inline.jsx +0 -2
- data/app/pb_kits/playbook/pb_date_picker/docs/_playground.json +1 -3
- data/app/pb_kits/playbook/pb_date_picker/docs/_playground.overrides.json +1 -3
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +58 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +2 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +7 -1
- data/app/pb_kits/playbook/pb_select/select.rb +9 -0
- data/app/pb_kits/playbook/pb_text_input/text_input.rb +9 -0
- data/app/pb_kits/playbook/pb_tooltip/_tooltip.scss +2 -2
- data/dist/chunks/vendor.js +2 -2
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9b032b2af16b04367de05d6b9acdfa51697b94da0010ba7189b001adcf0ba447
|
|
4
|
+
data.tar.gz: 322e6db4a0669d03521b9e676a71682b210c316ada7898d94a37eea4cba696fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0f8b662b1de6dcb08081c06101dee838ac36cc3cd616b64214893226942eaef61723bc52e215646b068a0756de9a90f037b2f4c6d04206570babc3f1c01a73a2
|
|
7
|
+
data.tar.gz: b4f795a65bb17995ae668450ea8535f16e2cee02b3e9a451aac53849fa0fc922a345630b0aac60974b8517fb7413de2d3347c5ea8705f551459bab6cbd0e5c47
|
|
@@ -12,6 +12,20 @@ import Caption from '../pb_caption/_caption'
|
|
|
12
12
|
import Body from '../pb_body/_body'
|
|
13
13
|
import colors from "../tokens/exports/_colors.module.scss"
|
|
14
14
|
|
|
15
|
+
function serializeDefaultDateForFilterReset(defaultDate: unknown): string | undefined {
|
|
16
|
+
if (defaultDate === '' || defaultDate == null) return undefined
|
|
17
|
+
if (Array.isArray(defaultDate)) {
|
|
18
|
+
const parts = defaultDate.map((d) => {
|
|
19
|
+
if (d == null || d === '') return ''
|
|
20
|
+
if (d instanceof Date) return d.toISOString()
|
|
21
|
+
return String(d)
|
|
22
|
+
}).filter(Boolean)
|
|
23
|
+
return parts.length ? parts.join(',') : undefined
|
|
24
|
+
}
|
|
25
|
+
if (defaultDate instanceof Date) return defaultDate.toISOString()
|
|
26
|
+
return String(defaultDate)
|
|
27
|
+
}
|
|
28
|
+
|
|
15
29
|
type DatePickerProps = {
|
|
16
30
|
allowInput?: boolean,
|
|
17
31
|
aria?: { [key: string]: string },
|
|
@@ -113,7 +127,11 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
|
|
|
113
127
|
} = props
|
|
114
128
|
|
|
115
129
|
const ariaProps = buildAriaProps(aria)
|
|
116
|
-
const
|
|
130
|
+
const filterResetDefaultSerialized = serializeDefaultDateForFilterReset(defaultDate)
|
|
131
|
+
const dataProps = buildDataProps({
|
|
132
|
+
...data,
|
|
133
|
+
...(filterResetDefaultSerialized ? { 'default-value': filterResetDefaultSerialized } : {}),
|
|
134
|
+
})
|
|
117
135
|
const htmlProps = buildHtmlProps(htmlOptions)
|
|
118
136
|
const inputAriaProps = buildAriaProps(inputAria)
|
|
119
137
|
const inputDataProps = buildDataProps(inputData)
|
|
@@ -180,6 +198,7 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
|
|
|
180
198
|
//@ts-ignore
|
|
181
199
|
globalProps(filteredProps),
|
|
182
200
|
error ? 'error' : null,
|
|
201
|
+
inLine && 'inline-date-picker',
|
|
183
202
|
className
|
|
184
203
|
)
|
|
185
204
|
|
|
@@ -262,7 +281,7 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
|
|
|
262
281
|
}
|
|
263
282
|
</div>
|
|
264
283
|
|
|
265
|
-
{!hideIcon &&
|
|
284
|
+
{!hideIcon && !inLine &&
|
|
266
285
|
<div
|
|
267
286
|
className={iconWrapperClass()}
|
|
268
287
|
id={`cal-icon-${pickerId}`}
|
|
@@ -274,7 +293,7 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
|
|
|
274
293
|
</div>
|
|
275
294
|
}
|
|
276
295
|
|
|
277
|
-
{
|
|
296
|
+
{inLine ?
|
|
278
297
|
<div>
|
|
279
298
|
<div
|
|
280
299
|
className={`${iconWrapperClass()} date-picker-inline-icon-plus`}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
<% date_picker_root_attrs = {
|
|
2
|
+
class: object.classname + object.error_class,
|
|
3
|
+
'data-pb-date-picker' => true,
|
|
4
|
+
'data-validation-message' => object.validation_message,
|
|
5
|
+
}
|
|
6
|
+
date_picker_root_attrs['data-default-value'] = object.serialized_default_date_for_dom if object.serialized_default_date_for_dom.present?
|
|
7
|
+
%>
|
|
8
|
+
<%= pb_content_tag(:div, date_picker_root_attrs) do %>
|
|
6
9
|
<div class="input_wrapper">
|
|
7
10
|
<% if !object.hide_label && object.label %>
|
|
8
11
|
<label for="<%= object.picker_id %>">
|
|
@@ -39,7 +42,7 @@
|
|
|
39
42
|
<input type="hidden" id="<%= "#{object.end_date_id}" %>" name="<%= "#{object.end_date_name}" %>">
|
|
40
43
|
<% end %>
|
|
41
44
|
|
|
42
|
-
<% if !object.hide_icon %>
|
|
45
|
+
<% if !object.hide_icon && !object.inline %>
|
|
43
46
|
<div
|
|
44
47
|
class="<%= object.icon_wrapper_class %>"
|
|
45
48
|
id="cal-icon-<%= object.picker_id %>"
|
|
@@ -52,7 +55,7 @@
|
|
|
52
55
|
<% end %>
|
|
53
56
|
|
|
54
57
|
<!-- Inline -->
|
|
55
|
-
<% if object.
|
|
58
|
+
<% if object.inline %>
|
|
56
59
|
<!-- Plus Icon -->
|
|
57
60
|
<div
|
|
58
61
|
class="<%= object.icon_wrapper_class %> date-picker-inline-icon-plus"
|
|
@@ -92,7 +92,8 @@ module Playbook
|
|
|
92
92
|
|
|
93
93
|
def classname
|
|
94
94
|
default_margin_bottom = margin_bottom.present? ? "" : " mb_sm"
|
|
95
|
-
|
|
95
|
+
inline_class = inline ? " inline-date-picker" : ""
|
|
96
|
+
generate_classname("pb_date_picker_kit") + default_margin_bottom + inline_class
|
|
96
97
|
end
|
|
97
98
|
|
|
98
99
|
def date_picker_config
|
|
@@ -144,6 +145,18 @@ module Playbook
|
|
|
144
145
|
def angle_down_path
|
|
145
146
|
"app/pb_kits/playbook/utilities/icons/angle-down.svg"
|
|
146
147
|
end
|
|
148
|
+
|
|
149
|
+
# Serialized business default for opt-in smart filter reset (Nitro / data-default-value).
|
|
150
|
+
def serialized_default_date_for_dom
|
|
151
|
+
case default_date
|
|
152
|
+
when nil, ""
|
|
153
|
+
nil
|
|
154
|
+
when Array
|
|
155
|
+
default_date.compact_blank.map(&:to_s).join(",")
|
|
156
|
+
else
|
|
157
|
+
default_date.to_s.presence
|
|
158
|
+
end
|
|
159
|
+
end
|
|
147
160
|
end
|
|
148
161
|
end
|
|
149
162
|
end
|
|
@@ -40,6 +40,63 @@ describe('DatePicker Kit', () => {
|
|
|
40
40
|
expect(kit).toHaveClass('pb_date_picker_kit mb_sm')
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
+
test('exposes data-default-value on kit root when defaultDate is set', () => {
|
|
44
|
+
const testId = 'datepicker-def-attr'
|
|
45
|
+
render(
|
|
46
|
+
<DatePicker
|
|
47
|
+
data={{ testid: testId }}
|
|
48
|
+
defaultDate={DEFAULT_DATE}
|
|
49
|
+
pickerId="date-picker-def-attr"
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
const kit = screen.getByTestId(testId)
|
|
53
|
+
expect(kit).toHaveAttribute('data-default-value', DEFAULT_DATE.toISOString())
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('omits data-default-value when defaultDate is empty', () => {
|
|
57
|
+
const testId = 'datepicker-no-def-attr'
|
|
58
|
+
render(
|
|
59
|
+
<DatePicker
|
|
60
|
+
data={{ testid: testId }}
|
|
61
|
+
defaultDate=""
|
|
62
|
+
pickerId="date-picker-no-def-attr"
|
|
63
|
+
/>
|
|
64
|
+
)
|
|
65
|
+
const kit = screen.getByTestId(testId)
|
|
66
|
+
expect(kit).not.toHaveAttribute('data-default-value')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('inLine alone adds inline-date-picker class and inline control icons, not the calendar icon', () => {
|
|
70
|
+
const testId = 'datepicker-inline-only'
|
|
71
|
+
render(
|
|
72
|
+
<DatePicker
|
|
73
|
+
data={{ testid: testId }}
|
|
74
|
+
inLine
|
|
75
|
+
pickerId="date-picker-inline-only"
|
|
76
|
+
/>
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const kit = screen.getByTestId(testId)
|
|
80
|
+
expect(kit).toHaveClass('inline-date-picker')
|
|
81
|
+
expect(kit.querySelector('#cal-icon-date-picker-inline-only')).not.toBeInTheDocument()
|
|
82
|
+
expect(kit.querySelector('#date-picker-inline-only-icon-plus')).toBeInTheDocument()
|
|
83
|
+
expect(kit.querySelector('#date-picker-inline-only-angle-down')).toBeInTheDocument()
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('hideIcon without inLine does not render inline control icons', () => {
|
|
87
|
+
const testId = 'datepicker-hide-icon-only'
|
|
88
|
+
render(
|
|
89
|
+
<DatePicker
|
|
90
|
+
data={{ testid: testId }}
|
|
91
|
+
hideIcon
|
|
92
|
+
pickerId="date-picker-hide-icon-only"
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
const kit = screen.getByTestId(testId)
|
|
97
|
+
expect(kit.querySelector('#date-picker-hide-icon-only-icon-plus')).not.toBeInTheDocument()
|
|
98
|
+
})
|
|
99
|
+
|
|
43
100
|
test('shows DatePicker date format m/d/Y', async () => {
|
|
44
101
|
const testId = 'datepicker-date'
|
|
45
102
|
render(
|
|
@@ -21,6 +21,58 @@ import {
|
|
|
21
21
|
handleClickOutside,
|
|
22
22
|
} from "./utilities";
|
|
23
23
|
|
|
24
|
+
function serializeDropdownFilterResetDefault(
|
|
25
|
+
variant: "default" | "subtle" | "quickpick" | undefined,
|
|
26
|
+
multiSelect: boolean,
|
|
27
|
+
defaultValue: GenericObject | GenericObject[] | string | undefined,
|
|
28
|
+
dropdownOptions: GenericObject[] | GenericObject | undefined,
|
|
29
|
+
): string | undefined {
|
|
30
|
+
const optionList: GenericObject[] = Array.isArray(dropdownOptions)
|
|
31
|
+
? dropdownOptions
|
|
32
|
+
: [];
|
|
33
|
+
const optionDefaultId = (option: GenericObject | undefined): string | undefined => {
|
|
34
|
+
if (!option) return undefined;
|
|
35
|
+
|
|
36
|
+
const id = option.id;
|
|
37
|
+
if (id != null && id !== "") return String(id);
|
|
38
|
+
|
|
39
|
+
const matched = optionList.find((listOption: GenericObject) => (
|
|
40
|
+
(option.value != null && listOption.value === option.value) ||
|
|
41
|
+
(option.label != null && listOption.label === option.label)
|
|
42
|
+
));
|
|
43
|
+
|
|
44
|
+
if (matched?.id != null && matched.id !== "") return String(matched.id);
|
|
45
|
+
return undefined;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
if (variant === "quickpick") {
|
|
49
|
+
if (typeof defaultValue === "string" && defaultValue) {
|
|
50
|
+
const matched = optionList.find(
|
|
51
|
+
(opt: GenericObject) => opt.label?.toLowerCase() === defaultValue.toLowerCase()
|
|
52
|
+
);
|
|
53
|
+
if (matched?.id != null && matched.id !== "") return String(matched.id);
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
if (multiSelect) {
|
|
58
|
+
const arr = Array.isArray(defaultValue)
|
|
59
|
+
? defaultValue
|
|
60
|
+
: defaultValue && typeof defaultValue === "object" && Object.keys(defaultValue).length
|
|
61
|
+
? [defaultValue as GenericObject]
|
|
62
|
+
: [];
|
|
63
|
+
if (!arr.length) return undefined;
|
|
64
|
+
const ids = arr
|
|
65
|
+
.map((v) => optionDefaultId(v as GenericObject))
|
|
66
|
+
.filter((id) => id != null && id !== "");
|
|
67
|
+
return ids.length ? ids.join(",") : undefined;
|
|
68
|
+
}
|
|
69
|
+
if (defaultValue && typeof defaultValue === "object" && !Array.isArray(defaultValue)) {
|
|
70
|
+
const id = optionDefaultId(defaultValue as GenericObject);
|
|
71
|
+
if (id) return id;
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
24
76
|
type CustomQuickPickDate = {
|
|
25
77
|
label: string;
|
|
26
78
|
value: string[] | { timePeriod: string; amount: number };
|
|
@@ -157,6 +209,11 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
157
209
|
initialSelected
|
|
158
210
|
);
|
|
159
211
|
|
|
212
|
+
const filterResetDefaultSerialized = useMemo(
|
|
213
|
+
() => serializeDropdownFilterResetDefault(variant, multiSelect, defaultValue, dropdownOptions),
|
|
214
|
+
[variant, multiSelect, defaultValue, dropdownOptions]
|
|
215
|
+
);
|
|
216
|
+
|
|
160
217
|
const [isInputFocused, setIsInputFocused] = useState(false);
|
|
161
218
|
const [hasTriggerSubcomponent, setHasTriggerSubcomponent] = useState(true);
|
|
162
219
|
const [hasContainerSubcomponent, setHasContainerSubcomponent] =
|
|
@@ -432,6 +489,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
432
489
|
<div {...ariaProps}
|
|
433
490
|
{...dataProps}
|
|
434
491
|
{...htmlProps}
|
|
492
|
+
{...(filterResetDefaultSerialized ? { "data-default-value": filterResetDefaultSerialized } : {})}
|
|
435
493
|
className={classes}
|
|
436
494
|
id={id}
|
|
437
495
|
ref={outerDivRef}
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
<% end %>
|
|
13
13
|
<div class="dropdown_wrapper<%= error_class %>" style="position: relative">
|
|
14
14
|
<input
|
|
15
|
+
<% if input_default_value.present? %>
|
|
15
16
|
data-default-value="<%= input_default_value %>"
|
|
17
|
+
<% end %>
|
|
16
18
|
data-dropdown-selected-option
|
|
17
19
|
name="<%= object.name %><%= '[]' if object.multi_select %>"
|
|
18
20
|
style="display: none"
|
|
@@ -51,6 +51,7 @@ test('generated default kit and classname', () => {
|
|
|
51
51
|
const kit = screen.getByTestId(testId)
|
|
52
52
|
expect(kit).toBeInTheDocument()
|
|
53
53
|
expect(kit).toHaveClass('pb_dropdown_default')
|
|
54
|
+
expect(kit).not.toHaveAttribute('data-default-value')
|
|
54
55
|
})
|
|
55
56
|
|
|
56
57
|
test('generated default Trigger and Container when none passed in', () => {
|
|
@@ -433,12 +434,16 @@ test("defaultValue works with multiSelect", () => {
|
|
|
433
434
|
render(
|
|
434
435
|
<Dropdown
|
|
435
436
|
data={{ testid: testId }}
|
|
436
|
-
defaultValue={[
|
|
437
|
+
defaultValue={[
|
|
438
|
+
{ label: options[0].label, value: options[0].value },
|
|
439
|
+
{ label: options[2].label, value: options[2].value },
|
|
440
|
+
]}
|
|
437
441
|
multiSelect
|
|
438
442
|
options={options}
|
|
439
443
|
/>
|
|
440
444
|
)
|
|
441
445
|
const kit = screen.getByTestId(testId)
|
|
446
|
+
expect(kit).toHaveAttribute("data-default-value", "United-states,pakistan")
|
|
442
447
|
expect(kit.querySelectorAll(".pb_form_pill_kit.pb_form_pill_primary")).toHaveLength(2)
|
|
443
448
|
const option2 = Array.from(kit.querySelectorAll(".pb_dropdown_option_list"));
|
|
444
449
|
const firstOpt = options[0].label
|
|
@@ -499,6 +504,7 @@ test("quickpick variant accepts string defaultValue", () => {
|
|
|
499
504
|
const trigger = kit.querySelector('.pb_dropdown_trigger')
|
|
500
505
|
|
|
501
506
|
expect(trigger).toHaveTextContent("This Month")
|
|
507
|
+
expect(kit).toHaveAttribute("data-default-value", "quickpick-this-month")
|
|
502
508
|
})
|
|
503
509
|
|
|
504
510
|
test("quickpick attaches _dropdownRef to DOM element when id is provided", () => {
|
|
@@ -50,9 +50,18 @@ module Playbook
|
|
|
50
50
|
def validation_data
|
|
51
51
|
fields = input_options[:data] || {}
|
|
52
52
|
fields[:message] = validation_message unless validation_message.blank?
|
|
53
|
+
dv = filter_reset_default_value
|
|
54
|
+
fields[:default_value] = dv if dv.present?
|
|
53
55
|
fields
|
|
54
56
|
end
|
|
55
57
|
|
|
58
|
+
def filter_reset_default_value
|
|
59
|
+
s = selected
|
|
60
|
+
return if s.blank?
|
|
61
|
+
|
|
62
|
+
s.join(",")
|
|
63
|
+
end
|
|
64
|
+
|
|
56
65
|
# Same resolved id as the native +<select>+ (+all_attributes[:id]+) for label +for+.
|
|
57
66
|
def select_input_id
|
|
58
67
|
all_attributes[:id].presence
|
|
@@ -121,9 +121,18 @@ module Playbook
|
|
|
121
121
|
fields[:message] = validation_message unless validation_message.blank?
|
|
122
122
|
fields[:pb_input_mask] = true if mask
|
|
123
123
|
fields[:pb_emoji_mask] = true if emoji_mask
|
|
124
|
+
dv = filter_reset_default_value
|
|
125
|
+
fields[:default_value] = dv if dv.present?
|
|
124
126
|
fields
|
|
125
127
|
end
|
|
126
128
|
|
|
129
|
+
def filter_reset_default_value
|
|
130
|
+
return if value.nil?
|
|
131
|
+
return if value.is_a?(String) && value.empty?
|
|
132
|
+
|
|
133
|
+
value.to_s
|
|
134
|
+
end
|
|
135
|
+
|
|
127
136
|
def error_class
|
|
128
137
|
error ? " error" : ""
|
|
129
138
|
end
|
|
@@ -58,7 +58,7 @@ $arrow_vertical_offset: calc(50% - #{$space_xs * 1.2});
|
|
|
58
58
|
|
|
59
59
|
&.visible,
|
|
60
60
|
&.show {
|
|
61
|
-
z-index: $
|
|
61
|
+
z-index: $z_max;
|
|
62
62
|
padding: $space_xs $space_sm;
|
|
63
63
|
box-shadow: $shadow_deeper;
|
|
64
64
|
border-radius: $border_rad_light;
|
|
@@ -160,7 +160,7 @@ $arrow_vertical_offset: calc(50% - #{$space_xs * 1.2});
|
|
|
160
160
|
|
|
161
161
|
&.visible,
|
|
162
162
|
&.show {
|
|
163
|
-
z-index: $
|
|
163
|
+
z-index: $z_max;
|
|
164
164
|
padding: $space_xs $space_sm;
|
|
165
165
|
box-shadow: $shadow_deeper;
|
|
166
166
|
border-radius: $border_rad_light;
|