playbook_ui 16.6.0.pre.alpha.emptystatepresets15848 → 16.6.0.pre.alpha.play294216115
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/docs/_advanced_table_grouped_headers_composition.jsx +15 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_infinite_scroll.jsx +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_inline_row_loading.jsx +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows.jsx +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_mock_data_inline_loading_empty_children.json +41 -0
- data/app/pb_kits/playbook/pb_bread_crumbs/docs/_bread_crumbs_default.jsx +5 -5
- data/app/pb_kits/playbook/pb_button/_button.scss +24 -23
- data/app/pb_kits/playbook/pb_button/button.rb +3 -1
- data/app/pb_kits/playbook/pb_date_picker/date_picker.test.js +30 -0
- data/app/pb_kits/playbook/pb_dialog/index.js +6 -1
- data/app/pb_kits/playbook/pb_draggable/index.js +6 -1
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +51 -2
- data/app/pb_kits/playbook/pb_empty_state/_empty_state.tsx +9 -22
- data/app/pb_kits/playbook/pb_empty_state/docs/example.yml +0 -2
- data/app/pb_kits/playbook/pb_empty_state/docs/index.js +0 -1
- data/app/pb_kits/playbook/pb_empty_state/empty_state.html.erb +1 -3
- data/app/pb_kits/playbook/pb_empty_state/empty_state.rb +0 -43
- data/app/pb_kits/playbook/pb_icon/_icon.scss +130 -0
- data/app/pb_kits/playbook/pb_icon/_icon.tsx +29 -13
- data/app/pb_kits/playbook/pb_icon/icon.test.js +70 -1
- data/app/pb_kits/playbook/pb_kit/dateTime.ts +4 -22
- data/app/pb_kits/playbook/pb_pagination/_pagination.scss +274 -23
- data/app/pb_kits/playbook/pb_pagination/docs/_pagination_default.html.erb +1 -1
- data/app/pb_kits/playbook/pb_pagination/docs/_pagination_external_control.jsx +22 -1
- data/app/pb_kits/playbook/pb_pagination/docs/_pagination_page_change.jsx +22 -2
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.tsx +68 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_show_placeholder.html.erb +5 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_show_placeholder.jsx +14 -0
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_show_placeholder.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/kit.schema.json +8 -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 +79 -2
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_advanced_templates.jsx +76 -1
- data/app/pb_kits/playbook/pb_select/docs/_select_error.jsx +1 -1
- data/app/pb_kits/playbook/pb_select/docs/_select_inline.jsx +1 -1
- data/app/pb_kits/playbook/pb_select/docs/_select_inline_compact.jsx +1 -1
- data/app/pb_kits/playbook/pb_select/docs/_select_inline_show_arrow.jsx +1 -1
- data/app/pb_kits/playbook/pb_select/docs/_select_multiple.html.erb +3 -3
- data/app/pb_kits/playbook/pb_select/docs/_select_multiple.jsx +5 -5
- data/app/pb_kits/playbook/pb_select/docs/_select_react_hook.jsx +5 -5
- data/app/pb_kits/playbook/pb_select/docs/_select_required_indicator.jsx +1 -1
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_react_hook.jsx +2 -2
- data/app/pb_kits/playbook/tokens/exports/exports.d.ts +1 -5
- data/app/pb_kits/playbook/utilities/icons/playbookIconResolver.ts +69 -0
- data/dist/chunks/{_pb_line_graph-EzcacMw_.js → _pb_line_graph-D7f-RfJJ.js} +1 -1
- data/dist/chunks/_typeahead-BO3J1J3f.js +1 -0
- data/dist/chunks/{globalProps-6Hsm3bJX.js → globalProps-BwwZkfTI.js} +1 -1
- data/dist/chunks/{lib-o4u12zAw.js → lib-Ch18RlJa.js} +1 -1
- data/dist/chunks/vendor.js +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/pagination_renderer.rb +119 -8
- data/lib/playbook/version.rb +1 -1
- metadata +11 -16
- data/app/pb_kits/playbook/pb_advanced_table/docs/_mock_data_inline_loading.js +0 -200
- data/app/pb_kits/playbook/pb_advanced_table/docs/_mock_data_inline_loading_empty_children.js +0 -42
- data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_grouped_headers_composition_mock_data.json +0 -98
- data/app/pb_kits/playbook/pb_empty_state/__mocks__/assetUrl.ts +0 -1
- data/app/pb_kits/playbook/pb_empty_state/docs/_empty_state_presets.html.erb +0 -14
- data/app/pb_kits/playbook/pb_empty_state/docs/_empty_state_presets.jsx +0 -27
- data/app/pb_kits/playbook/pb_empty_state/docs/default_image/this_is_fine.svg +0 -21
- data/app/pb_kits/playbook/pb_empty_state/docs/default_image/travolta_lost.gif +0 -0
- data/app/pb_kits/playbook/pb_pagination/docs/data.js +0 -23
- data/app/pb_kits/playbook/pb_rich_text_editor/docs/templates.js +0 -75
- data/dist/chunks/_typeahead-BYUXg9ZT.js +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f4decbfeb1e045070d591f56daf85d3ef2794bf2855d33e889f00fb2dc694be7
|
|
4
|
+
data.tar.gz: 04b363904b41e8d0b30e2752af2c1e07d6cf6ca38ca5ae0f3576b515fcaa8c23
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 42918e61a6d599a6b5033053eaad2a5d09139d2d977d85f766f0fbd5c65f0e05608bef3c57fa787ce7efd3e847d785ba198472bd532e436ffbc2d7c161ad3314
|
|
7
|
+
data.tar.gz: 13bc1c4045f5d400052204a4a495d345aeb2b814de5ba3d8c87e510327e18ecaa80d18d99b307d75a9d3e8a7c2cf9c2e0b2466ea7a30c41f9d282aad0766275f
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_grouped_headers_composition.jsx
CHANGED
|
@@ -9,7 +9,21 @@ import ListItem from "../../pb_list/_list_item"
|
|
|
9
9
|
import PbReactPopover from "../../pb_popover/_popover"
|
|
10
10
|
import SectionSeparator from "../../pb_section_separator/_section_separator"
|
|
11
11
|
import StarRating from "../../pb_star_rating/_star_rating"
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
const COMPOSITION_MOCK_DATA = [
|
|
14
|
+
{ id: "1", year: "2015", newEnrollments: "12", scheduledMeetings: "40", attendanceRate: "62%", classCompletionRate: "28%" },
|
|
15
|
+
{ id: "2", year: "2016", newEnrollments: "88", scheduledMeetings: "12", attendanceRate: "71%", classCompletionRate: "55%" },
|
|
16
|
+
{ id: "3", year: "2017", newEnrollments: "34", scheduledMeetings: "67", attendanceRate: "58%", classCompletionRate: "41%" },
|
|
17
|
+
{ id: "4", year: "2018", newEnrollments: "05", scheduledMeetings: "91", attendanceRate: "44%", classCompletionRate: "73%" },
|
|
18
|
+
{ id: "5", year: "2019", newEnrollments: "61", scheduledMeetings: "19", attendanceRate: "83%", classCompletionRate: "36%" },
|
|
19
|
+
{ id: "6", year: "2020", newEnrollments: "19", scheduledMeetings: "54", attendanceRate: "67%", classCompletionRate: "62%" },
|
|
20
|
+
{ id: "7", year: "2021", newEnrollments: "73", scheduledMeetings: "08", attendanceRate: "52%", classCompletionRate: "49%" },
|
|
21
|
+
{ id: "8", year: "2022", newEnrollments: "50", scheduledMeetings: "50", attendanceRate: "75%", classCompletionRate: "45%" },
|
|
22
|
+
{ id: "9", year: "2023", newEnrollments: "95", scheduledMeetings: "03", attendanceRate: "69%", classCompletionRate: "81%" },
|
|
23
|
+
{ id: "10", year: "2024", newEnrollments: "27", scheduledMeetings: "76", attendanceRate: "91%", classCompletionRate: "22%" },
|
|
24
|
+
{ id: "11", year: "2025", newEnrollments: "41", scheduledMeetings: "33", attendanceRate: "48%", classCompletionRate: "94%" },
|
|
25
|
+
{ id: "12", year: "2026", newEnrollments: "66", scheduledMeetings: "66", attendanceRate: "55%", classCompletionRate: "58%" },
|
|
26
|
+
]
|
|
13
27
|
|
|
14
28
|
const LEAF_COUNT = "newEnrollments"
|
|
15
29
|
const LEAF_SCHEDULED = "scheduledMeetings"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import AdvancedTable from '../_advanced_table'
|
|
3
|
-
import
|
|
3
|
+
import INFINITE_SCROLL_MOCK_DATA from "./advanced_table_mock_data_infinite_scroll.json"
|
|
4
4
|
|
|
5
5
|
const AdvancedTableInfiniteScroll = (props) => {
|
|
6
6
|
const columnDefinitions = [
|
|
@@ -39,7 +39,7 @@ const AdvancedTableInfiniteScroll = (props) => {
|
|
|
39
39
|
<div>
|
|
40
40
|
<AdvancedTable
|
|
41
41
|
columnDefinitions={columnDefinitions}
|
|
42
|
-
tableData={
|
|
42
|
+
tableData={INFINITE_SCROLL_MOCK_DATA}
|
|
43
43
|
virtualizedRows
|
|
44
44
|
{...props}
|
|
45
45
|
/>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import AdvancedTable from '../../pb_advanced_table/_advanced_table'
|
|
3
3
|
import Caption from '../../pb_caption/_caption'
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import MOCK_DATA_INLINE_LOADING from "./advanced_table_mock_data_inline_loading.json"
|
|
5
|
+
import MOCK_DATA_INLINE_LOADING_EMPTY_CHILDREN from "./advanced_table_mock_data_inline_loading_empty_children.json"
|
|
6
6
|
|
|
7
7
|
const AdvancedTableInlineRowLoading = (props) => {
|
|
8
8
|
const columnDefinitions = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState } from "react"
|
|
2
2
|
import AdvancedTable from '../_advanced_table'
|
|
3
|
-
import
|
|
3
|
+
import MOCK_DATA_WITH_ID from "./advanced_table_mock_data_with_id.json"
|
|
4
4
|
|
|
5
5
|
const AdvancedTableRowPinning = (props) => {
|
|
6
6
|
const columnDefinitions = [
|
|
@@ -43,7 +43,7 @@ const AdvancedTableRowPinning = (props) => {
|
|
|
43
43
|
columnDefinitions={columnDefinitions}
|
|
44
44
|
maxHeight="xs"
|
|
45
45
|
pinnedRows={{value: pinnedRows, onChange: setPinnedRows}}
|
|
46
|
-
tableData={
|
|
46
|
+
tableData={MOCK_DATA_WITH_ID}
|
|
47
47
|
tableProps={{sticky: true}}
|
|
48
48
|
{...props}
|
|
49
49
|
>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"year": "2021",
|
|
4
|
+
"quarter": null,
|
|
5
|
+
"month": null,
|
|
6
|
+
"day": null,
|
|
7
|
+
"newEnrollments": "20",
|
|
8
|
+
"scheduledMeetings": "10",
|
|
9
|
+
"attendanceRate": "51%",
|
|
10
|
+
"completedClasses": "3",
|
|
11
|
+
"classCompletionRate": "33%",
|
|
12
|
+
"graduatedStudents": "19",
|
|
13
|
+
"children": []
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"year": "2022",
|
|
17
|
+
"quarter": null,
|
|
18
|
+
"month": null,
|
|
19
|
+
"day": null,
|
|
20
|
+
"newEnrollments": "25",
|
|
21
|
+
"scheduledMeetings": "17",
|
|
22
|
+
"attendanceRate": "75%",
|
|
23
|
+
"completedClasses": "5",
|
|
24
|
+
"classCompletionRate": "45%",
|
|
25
|
+
"graduatedStudents": "32",
|
|
26
|
+
"children": []
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"year": "2023",
|
|
30
|
+
"quarter": null,
|
|
31
|
+
"month": null,
|
|
32
|
+
"day": null,
|
|
33
|
+
"newEnrollments": "10",
|
|
34
|
+
"scheduledMeetings": "15",
|
|
35
|
+
"attendanceRate": "65%",
|
|
36
|
+
"completedClasses": "4",
|
|
37
|
+
"classCompletionRate": "49%",
|
|
38
|
+
"graduatedStudents": "29",
|
|
39
|
+
"children": []
|
|
40
|
+
}
|
|
41
|
+
]
|
|
@@ -4,7 +4,7 @@ import Icon from "../../pb_icon/_icon"
|
|
|
4
4
|
import Title from "../../pb_title/_title"
|
|
5
5
|
import BreadCrumbItem from '../_bread_crumb_item'
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const LinkSection = (props) => <BreadCrumbItem {...props} />
|
|
8
8
|
const BreadCrumbsDefault = (props) => {
|
|
9
9
|
return (
|
|
10
10
|
<BreadCrumbs
|
|
@@ -35,7 +35,7 @@ const BreadCrumbsDefault = (props) => {
|
|
|
35
35
|
size="1x"
|
|
36
36
|
{...props}
|
|
37
37
|
/>
|
|
38
|
-
<
|
|
38
|
+
<LinkSection
|
|
39
39
|
{...props}
|
|
40
40
|
href="/users"
|
|
41
41
|
>
|
|
@@ -46,20 +46,20 @@ const BreadCrumbsDefault = (props) => {
|
|
|
46
46
|
text="Users"
|
|
47
47
|
{...props}
|
|
48
48
|
/>
|
|
49
|
-
</
|
|
49
|
+
</LinkSection>
|
|
50
50
|
<Icon
|
|
51
51
|
icon="user"
|
|
52
52
|
size="1x"
|
|
53
53
|
{...props}
|
|
54
54
|
/>
|
|
55
|
-
<
|
|
55
|
+
<LinkSection {...props}>
|
|
56
56
|
<Title
|
|
57
57
|
size="4"
|
|
58
58
|
tag="span"
|
|
59
59
|
text="User"
|
|
60
60
|
{...props}
|
|
61
61
|
/>
|
|
62
|
-
</
|
|
62
|
+
</LinkSection>
|
|
63
63
|
</BreadCrumbs>
|
|
64
64
|
)
|
|
65
65
|
}
|
|
@@ -11,6 +11,13 @@ $pb_button_sizes: (
|
|
|
11
11
|
"lg": ($font_large - 2px),
|
|
12
12
|
);
|
|
13
13
|
|
|
14
|
+
// Icon-only: fixed square hit targets (not derived from font padding).
|
|
15
|
+
$pb_button_icon_only_dimensions: (
|
|
16
|
+
"sm": 35px,
|
|
17
|
+
"md": 40px,
|
|
18
|
+
"lg": 45px,
|
|
19
|
+
);
|
|
20
|
+
|
|
14
21
|
// Base button class
|
|
15
22
|
.pb_button_kit {
|
|
16
23
|
@include pb_button;
|
|
@@ -113,32 +120,26 @@ $pb_button_sizes: (
|
|
|
113
120
|
}
|
|
114
121
|
}
|
|
115
122
|
|
|
116
|
-
// Icon-only button (icon prop set, no text) -
|
|
117
|
-
// Rails:
|
|
118
|
-
//
|
|
119
|
-
// text + icon (e.g. "Exit Fullscreen" + FA icon) which can include empty spans.
|
|
123
|
+
// Icon-only button (icon prop set, no text) — fixed squares; icon scales via font-size from size prop.
|
|
124
|
+
// Rails: .pb_button_icon_only; React: class or :has(...) when label is empty.
|
|
125
|
+
// Rails uses a truly empty .pb_button_content; React wraps text in a child span (may be empty).
|
|
120
126
|
&.pb_button_icon_only,
|
|
121
127
|
&:has(.pb_button_content:empty) {
|
|
122
128
|
aspect-ratio: 1;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
&.pb_button_size_lg {
|
|
140
|
-
padding: ($font_large - 2px) !important;
|
|
141
|
-
min-height: (($font_large - 2px) * 2) + ($font_large - 2px);
|
|
129
|
+
box-sizing: border-box;
|
|
130
|
+
$pb_button_icon_only_default: map-get($pb_button_icon_only_dimensions, "md");
|
|
131
|
+
width: $pb_button_icon_only_default;
|
|
132
|
+
min-width: $pb_button_icon_only_default;
|
|
133
|
+
height: $pb_button_icon_only_default;
|
|
134
|
+
min-height: $pb_button_icon_only_default;
|
|
135
|
+
padding: 0 !important;
|
|
136
|
+
@each $name, $dim in $pb_button_icon_only_dimensions {
|
|
137
|
+
&.pb_button_size_#{$name} {
|
|
138
|
+
width: $dim;
|
|
139
|
+
min-width: $dim;
|
|
140
|
+
height: $dim;
|
|
141
|
+
min-height: $dim;
|
|
142
|
+
}
|
|
142
143
|
}
|
|
143
144
|
|
|
144
145
|
// Remove margins from icons
|
|
@@ -73,8 +73,10 @@ module Playbook
|
|
|
73
73
|
emoji_regex.match?(icon)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
# Icon-only = icon with no label. Label may come from `text` or from a block (e.g. CopyButton);
|
|
77
|
+
# block content must not be treated as icon-only when `text` is unset.
|
|
76
78
|
def icon_only?
|
|
77
|
-
icon.present? && text.blank? && variant != "reaction"
|
|
79
|
+
icon.present? && text.blank? && children.blank? && variant != "reaction"
|
|
78
80
|
end
|
|
79
81
|
|
|
80
82
|
def classname
|
|
@@ -310,4 +310,34 @@ describe('DatePicker Kit', () => {
|
|
|
310
310
|
expect(label).toBeInTheDocument()
|
|
311
311
|
expect(kit).not.toHaveTextContent("*")
|
|
312
312
|
})
|
|
313
|
+
|
|
314
|
+
test('Last month quickpick includes the correct last day of previous month', async () => {
|
|
315
|
+
const testId = 'datepicker-last-month'
|
|
316
|
+
render(
|
|
317
|
+
<DatePicker
|
|
318
|
+
allowInput
|
|
319
|
+
data={{ testid: testId }}
|
|
320
|
+
mode="range"
|
|
321
|
+
pickerId="date-picker-last-month"
|
|
322
|
+
placeholder="mm/dd/yyyy to mm/dd/yyyy"
|
|
323
|
+
selectionType="quickpick"
|
|
324
|
+
/>
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
const kit = screen.getByTestId(testId)
|
|
328
|
+
const input = within(kit).getByPlaceholderText('mm/dd/yyyy to mm/dd/yyyy')
|
|
329
|
+
|
|
330
|
+
fireEvent(input, new MouseEvent('click', { bubbles: true, cancelable: true }))
|
|
331
|
+
|
|
332
|
+
const lastMonth = within(kit).getByText('Last month')
|
|
333
|
+
fireEvent(lastMonth, new MouseEvent('click', { bubbles: true, cancelable: true }))
|
|
334
|
+
|
|
335
|
+
await waitFor(() => {
|
|
336
|
+
expect(input).toHaveValue(
|
|
337
|
+
DateTime.getPreviousMonthStartDate(new Date()).formatDate() +
|
|
338
|
+
" to " +
|
|
339
|
+
DateTime.getPreviousMonthEndDate(new Date()).formatDate()
|
|
340
|
+
)
|
|
341
|
+
})
|
|
342
|
+
})
|
|
313
343
|
})
|
|
@@ -16,7 +16,12 @@ export default class PbDialog extends PbEnhancedElement {
|
|
|
16
16
|
this.domContentLoadedHandler = () => this.setupDialog()
|
|
17
17
|
this.turboFrameLoadHandler = () => this.setupDialog()
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
// If DOM is already loaded, setup immediately; otherwise wait for DOMContentLoaded
|
|
20
|
+
if (document.readyState === "loading") {
|
|
21
|
+
window.addEventListener("DOMContentLoaded", this.domContentLoadedHandler)
|
|
22
|
+
} else {
|
|
23
|
+
this.setupDialog()
|
|
24
|
+
}
|
|
20
25
|
window.addEventListener("turbo:frame-load", this.turboFrameLoadHandler)
|
|
21
26
|
|
|
22
27
|
// Code for custom_event_type setup (can take multiple events in a string separated by commas)
|
|
@@ -22,7 +22,12 @@ export default class PbDraggable extends PbEnhancedElement {
|
|
|
22
22
|
this.dragZoneType = "";
|
|
23
23
|
this.dragZoneColor = "";
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// If DOM is already loaded, bind immediately; otherwise wait for DOMContentLoaded
|
|
26
|
+
if (document.readyState === "loading") {
|
|
27
|
+
document.addEventListener("DOMContentLoaded", () => this.bindEventListeners());
|
|
28
|
+
} else {
|
|
29
|
+
this.bindEventListeners();
|
|
30
|
+
}
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
setState(newState) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useState } from "react"
|
|
2
|
-
import { render, screen, fireEvent } from "../utilities/test-utils"
|
|
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"
|
|
6
6
|
|
|
7
7
|
const testId = 'dropdown'
|
|
8
8
|
|
|
@@ -778,3 +778,52 @@ test("requiredIndicator prop renders asterisk when true", () => {
|
|
|
778
778
|
expect(label).toBeInTheDocument();
|
|
779
779
|
expect(kit).toHaveTextContent("*");
|
|
780
780
|
});
|
|
781
|
+
|
|
782
|
+
describe("quickpick Last Month range when current month is shorter than the previous month", () => {
|
|
783
|
+
const quickpickTestId = "dropdown-quickpick-last-month-march"
|
|
784
|
+
|
|
785
|
+
const formatDate = (date) => {
|
|
786
|
+
const month = (date.getMonth() + 1).toString().padStart(2, "0")
|
|
787
|
+
const day = date.getDate().toString().padStart(2, "0")
|
|
788
|
+
const year = date.getFullYear()
|
|
789
|
+
return `${month}/${day}/${year}`
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
beforeEach(() => {
|
|
793
|
+
jest.setSystemTime(new Date(2026, 3, 15, 12, 0, 0))
|
|
794
|
+
})
|
|
795
|
+
|
|
796
|
+
afterEach(() => {
|
|
797
|
+
jest.setSystemTime()
|
|
798
|
+
})
|
|
799
|
+
|
|
800
|
+
test("selecting Last Month matches DateTime previous-month range (full March when today is in April)", async () => {
|
|
801
|
+
const onSelect = jest.fn()
|
|
802
|
+
const now = new Date()
|
|
803
|
+
|
|
804
|
+
render(
|
|
805
|
+
<Dropdown
|
|
806
|
+
data={{ testid: quickpickTestId }}
|
|
807
|
+
onSelect={onSelect}
|
|
808
|
+
variant="quickpick"
|
|
809
|
+
/>
|
|
810
|
+
)
|
|
811
|
+
|
|
812
|
+
const kit = screen.getByTestId(quickpickTestId)
|
|
813
|
+
const lastMonthOption = Array.from(kit.querySelectorAll(".pb_dropdown_option_list")).find(
|
|
814
|
+
(el) => el.textContent === "Last Month"
|
|
815
|
+
)
|
|
816
|
+
|
|
817
|
+
expect(lastMonthOption).toBeTruthy()
|
|
818
|
+
fireEvent.click(lastMonthOption)
|
|
819
|
+
|
|
820
|
+
await waitFor(() => {
|
|
821
|
+
expect(onSelect).toHaveBeenCalled()
|
|
822
|
+
})
|
|
823
|
+
|
|
824
|
+
const [startDate, endDate] = onSelect.mock.calls[0][0].value
|
|
825
|
+
|
|
826
|
+
expect(formatDate(startDate)).toBe(formatDate(DateTime.getPreviousMonthStartDate(now)))
|
|
827
|
+
expect(formatDate(endDate)).toBe(formatDate(DateTime.getPreviousMonthEndDate(now)))
|
|
828
|
+
})
|
|
829
|
+
})
|
|
@@ -12,8 +12,6 @@ import Flex from "../pb_flex/_flex"
|
|
|
12
12
|
import FlexItem from "../pb_flex/_flex_item"
|
|
13
13
|
import Image from "../pb_image/_image"
|
|
14
14
|
import computer from "./docs/default_image/utils"
|
|
15
|
-
import thisIsFineImageUrl from "./docs/default_image/this_is_fine.svg?url"
|
|
16
|
-
import travoltaLostImageUrl from "./docs/default_image/travolta_lost.gif?url"
|
|
17
15
|
|
|
18
16
|
type EventHandler = (React.MouseEventHandler<HTMLElement>)
|
|
19
17
|
|
|
@@ -25,7 +23,6 @@ type EmptyStateProps = {
|
|
|
25
23
|
description?: string,
|
|
26
24
|
header?: string,
|
|
27
25
|
id?: string,
|
|
28
|
-
/** Built-in illustrations: `default`, `this_is_fine`, `travolta_lost`, or a custom image URL */
|
|
29
26
|
image?: string,
|
|
30
27
|
linkButton?: string,
|
|
31
28
|
onLinkButtonClick?: EventHandler,
|
|
@@ -137,22 +134,6 @@ const EmptyState = (props: EmptyStateProps) => {
|
|
|
137
134
|
return `data:image/svg+xml,${encodedSvg}`
|
|
138
135
|
}
|
|
139
136
|
|
|
140
|
-
const resolvePresetImage = (): { alt: string, url: string } | null => {
|
|
141
|
-
if (!image) return null
|
|
142
|
-
if (image === "default") {
|
|
143
|
-
return { alt: "Empty state illustration", url: getSvgAsDataUrl() }
|
|
144
|
-
}
|
|
145
|
-
if (image === "this_is_fine") {
|
|
146
|
-
return { alt: "This is fine illustration", url: thisIsFineImageUrl }
|
|
147
|
-
}
|
|
148
|
-
if (image === "travolta_lost") {
|
|
149
|
-
return { alt: "Confused reaction illustration", url: travoltaLostImageUrl }
|
|
150
|
-
}
|
|
151
|
-
return { alt: "Empty state image", url: image }
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const presetImage = resolvePresetImage()
|
|
155
|
-
|
|
156
137
|
const layout = (
|
|
157
138
|
<div {...ariaProps}
|
|
158
139
|
{...dataProps}
|
|
@@ -167,11 +148,17 @@ const EmptyState = (props: EmptyStateProps) => {
|
|
|
167
148
|
vertical="center"
|
|
168
149
|
>
|
|
169
150
|
|
|
170
|
-
{
|
|
151
|
+
{ image && image === 'default' ? (
|
|
152
|
+
<Image
|
|
153
|
+
alt="test"
|
|
154
|
+
htmlOptions={{ width: configs.imageWidth, height: "auto", alignment: "start" }}
|
|
155
|
+
url={getSvgAsDataUrl()}
|
|
156
|
+
/>
|
|
157
|
+
) : image && image ? (
|
|
171
158
|
<Image
|
|
172
|
-
alt=
|
|
159
|
+
alt="test"
|
|
173
160
|
htmlOptions={{ width: configs.imageWidth, height: "auto", alignment: "start" }}
|
|
174
|
-
url={
|
|
161
|
+
url={image}
|
|
175
162
|
/>
|
|
176
163
|
) : null}
|
|
177
164
|
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
examples:
|
|
2
2
|
rails:
|
|
3
3
|
- empty_state_default: Default
|
|
4
|
-
- empty_state_presets: Illustration presets
|
|
5
4
|
- empty_state_size: Size
|
|
6
5
|
- empty_state_orientation: Orientation
|
|
7
6
|
- empty_state_alignment: Alignment
|
|
8
7
|
|
|
9
8
|
react:
|
|
10
9
|
- empty_state_default: Default
|
|
11
|
-
- empty_state_presets: Illustration presets
|
|
12
10
|
- empty_state_size: Size
|
|
13
11
|
- empty_state_orientation: Orientation
|
|
14
12
|
- empty_state_alignment: Alignment
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { default as EmptyStateDefault } from './_empty_state_default.jsx'
|
|
2
|
-
export { default as EmptyStatePresets } from './_empty_state_presets.jsx'
|
|
3
2
|
export { default as EmptyStateOrientation } from './_empty_state_orientation.jsx'
|
|
4
3
|
export { default as EmptyStateSize } from './_empty_state_size.jsx'
|
|
5
4
|
export { default as EmptyStateAlignment } from './_empty_state_alignment.jsx'
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
<%= pb_content_tag do %>
|
|
2
2
|
<%= pb_rails("flex", props: { align: flex_align, orientation: config[:flex_direction], padding_left: padding_size, padding_right: padding_size, vertical: "center", classname: config[:scss_class], max_width: "100%" }) do %>
|
|
3
|
-
|
|
4
|
-
<%= pb_rails("image", props: { url: resolved_image_url, alt: image_alt_text, html_options: { width: config[:image_width], height: "auto", alignment: "start" } }) %>
|
|
5
|
-
<% end %>
|
|
3
|
+
<%= pb_rails("image", props: { url: image == "default" ? default_image_data_uri : image, alt: "Empty State Image", html_options: { width: config[:image_width], height: "auto", alignment: "start" } }) %>
|
|
6
4
|
<%= pb_rails("flex/flex_item") do %>
|
|
7
5
|
<%= pb_rails("title", props: { text: object.header, size: config[:title_size], padding_bottom: config[:title_padding], text_align: alignment }) %>
|
|
8
6
|
<% if size == "sm" %>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "base64"
|
|
4
|
-
|
|
5
3
|
module Playbook
|
|
6
4
|
module PbEmptyState
|
|
7
5
|
class EmptyState < Playbook::KitBase
|
|
@@ -106,47 +104,6 @@ module Playbook
|
|
|
106
104
|
"data:image/svg+xml,#{encoded}"
|
|
107
105
|
end
|
|
108
106
|
|
|
109
|
-
def resolved_image_url
|
|
110
|
-
case image
|
|
111
|
-
when "default"
|
|
112
|
-
default_image_data_uri
|
|
113
|
-
when "this_is_fine"
|
|
114
|
-
svg_preset_data_uri("this_is_fine.svg")
|
|
115
|
-
when "travolta_lost"
|
|
116
|
-
gif_preset_data_uri("travolta_lost.gif")
|
|
117
|
-
when nil, ""
|
|
118
|
-
nil
|
|
119
|
-
else
|
|
120
|
-
image
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def image_alt_text
|
|
125
|
-
case image
|
|
126
|
-
when "this_is_fine"
|
|
127
|
-
"This is fine illustration"
|
|
128
|
-
when "travolta_lost"
|
|
129
|
-
"Confused reaction illustration"
|
|
130
|
-
when "default"
|
|
131
|
-
"Empty state illustration"
|
|
132
|
-
else
|
|
133
|
-
"Empty state image"
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def svg_preset_data_uri(filename)
|
|
138
|
-
path = File.join(__dir__, "docs", "default_image", filename)
|
|
139
|
-
svg = File.read(path)
|
|
140
|
-
"data:image/svg+xml,#{ERB::Util.url_encode(svg)}"
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def gif_preset_data_uri(filename)
|
|
144
|
-
path = File.join(__dir__, "docs", "default_image", filename)
|
|
145
|
-
binary = File.binread(path)
|
|
146
|
-
b64 = Base64.strict_encode64(binary)
|
|
147
|
-
"data:image/gif;base64,#{b64}"
|
|
148
|
-
end
|
|
149
|
-
|
|
150
107
|
def padding_size
|
|
151
108
|
size == "sm" ? "xs" : "xl"
|
|
152
109
|
end
|
|
@@ -25,6 +25,136 @@ $icon_colors: map-merge($merge_kits8, $accessible_status_icon_background_colors)
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
.pb_playbook_icon {
|
|
29
|
+
display: inline-block;
|
|
30
|
+
line-height: 1;
|
|
31
|
+
|
|
32
|
+
&::before {
|
|
33
|
+
width: 1em;
|
|
34
|
+
height: 1em;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.svg_inverse::before {
|
|
38
|
+
background: #fff;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&.svg_border {
|
|
42
|
+
border-color: #eee;
|
|
43
|
+
border-radius: .1em;
|
|
44
|
+
border-style: solid;
|
|
45
|
+
border-width: .08em;
|
|
46
|
+
padding: .2em .25em .15em;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&.svg_fw {
|
|
50
|
+
text-align: center;
|
|
51
|
+
width: 1.25em;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&.pull_left {
|
|
55
|
+
float: left;
|
|
56
|
+
margin-right: .3em;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&.pull_right {
|
|
60
|
+
float: right;
|
|
61
|
+
margin-left: .3em;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
&.svg_xs {
|
|
65
|
+
font-size: 0.75em;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&.svg_sm {
|
|
69
|
+
font-size: 0.875em;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
&.svg_lg {
|
|
73
|
+
font-size: 1.25em;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&.svg_1x {
|
|
77
|
+
font-size: 1em;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&.svg_2x {
|
|
81
|
+
font-size: 2em;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&.svg_3x {
|
|
85
|
+
font-size: 3em;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&.svg_4x {
|
|
89
|
+
font-size: 4em;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
&.svg_5x {
|
|
93
|
+
font-size: 5em;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
&.svg_6x {
|
|
97
|
+
font-size: 6em;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
&.svg_7x {
|
|
101
|
+
font-size: 7em;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
&.svg_8x {
|
|
105
|
+
font-size: 8em;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
&.svg_9x {
|
|
109
|
+
font-size: 9em;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
&.svg_10x {
|
|
113
|
+
font-size: 10em;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
&.rotate_90 {
|
|
117
|
+
transform: rotate(90deg);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
&.rotate_180 {
|
|
121
|
+
transform: rotate(180deg);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
&.rotate_270 {
|
|
125
|
+
transform: rotate(270deg);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&.flip_horizontal {
|
|
129
|
+
transform: scaleX(-1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
&.flip_vertical {
|
|
133
|
+
transform: scaleY(-1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
&.flip_horizontal.flip_vertical {
|
|
137
|
+
transform: scaleX(-1) scaleY(-1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&.pulse {
|
|
141
|
+
animation-name: pb_icon_spin;
|
|
142
|
+
animation-direction: normal;
|
|
143
|
+
animation-duration: 1s;
|
|
144
|
+
animation-iteration-count: infinite;
|
|
145
|
+
animation-timing-function: steps(8);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
&.spin {
|
|
149
|
+
animation-name: pb_icon_spin;
|
|
150
|
+
animation-delay: 0s;
|
|
151
|
+
animation-direction: normal;
|
|
152
|
+
animation-duration: 2s;
|
|
153
|
+
animation-iteration-count: infinite;
|
|
154
|
+
animation-timing-function: linear;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
28
158
|
// Rails custom icon styles
|
|
29
159
|
svg.pb_custom_icon {
|
|
30
160
|
width: 1em;
|