playbook_ui 11.6.1.pre.alpha.rubocop.pre.performance1 → 11.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/data/menu.yml +0 -13
- data/app/pb_kits/playbook/index.js +1 -1
- data/app/pb_kits/playbook/pb_badge/badge.test.js +80 -0
- data/app/pb_kits/playbook/pb_button/_button.tsx +7 -2
- data/app/pb_kits/playbook/pb_button/_button_mixins.scss +7 -0
- data/app/pb_kits/playbook/pb_button/button.html.erb +11 -0
- data/app/pb_kits/playbook/pb_button/button.rb +3 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_block_content.html.erb +1 -1
- data/app/pb_kits/playbook/pb_button/docs/_button_block_content.jsx +12 -9
- data/app/pb_kits/playbook/pb_button/docs/_button_block_content.md +1 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.html.erb +2 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.jsx +23 -0
- data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.md +1 -0
- data/app/pb_kits/playbook/pb_button/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_button/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_date_picker/{_date_picker.jsx → _date_picker.tsx} +58 -66
- data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +2 -1
- data/app/pb_kits/playbook/pb_date_picker/{date_picker_helper.js → date_picker_helper.ts} +37 -16
- data/app/pb_kits/playbook/pb_date_picker/plugins/timeSelect.ts +171 -0
- data/app/pb_kits/playbook/pb_date_picker/sass_partials/_flatpickr_styles.scss +0 -3
- data/app/pb_kits/playbook/pb_date_range_stacked/{_date_range_stacked.jsx → _date_range_stacked.tsx} +5 -6
- data/app/pb_kits/playbook/pb_date_range_stacked/date_range_stacked.test.js +127 -0
- data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.tsx +90 -0
- data/app/pb_kits/playbook/pb_date_stacked/date_stacked.test.js +151 -0
- data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_align.jsx +1 -1
- data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_bold.jsx +1 -1
- data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_default.jsx +1 -1
- data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_not_current_year.jsx +1 -1
- data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_reverse.jsx +1 -1
- data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_sizes.jsx +1 -1
- data/app/pb_kits/playbook/pb_dialog/{_close_icon.jsx → _close_icon.tsx} +1 -3
- data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +217 -0
- data/app/pb_kits/playbook/pb_dialog/_dialog_context.tsx +3 -0
- data/app/pb_kits/playbook/pb_dialog/child_kits/{_dialog_body.jsx → _dialog_body.tsx} +6 -2
- data/app/pb_kits/playbook/pb_dialog/child_kits/{_dialog_footer.jsx → _dialog_footer.tsx} +8 -11
- data/app/pb_kits/playbook/pb_dialog/child_kits/{_dialog_header.jsx → _dialog_header.tsx} +12 -15
- data/app/pb_kits/playbook/pb_filter/Filter/FilterDouble.jsx +2 -0
- data/app/pb_kits/playbook/pb_filter/Filter/FilterSingle.jsx +2 -0
- data/app/pb_kits/playbook/pb_filter/Filter/FiltersPopover.jsx +2 -2
- data/app/pb_kits/playbook/pb_filter/docs/_filter_min_width.html.erb +1 -0
- data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.html.erb +34 -0
- data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.jsx +66 -0
- data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.md +4 -0
- data/app/pb_kits/playbook/pb_filter/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_filter/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_filter/filter.html.erb +2 -2
- data/app/pb_kits/playbook/pb_filter/filter.rb +3 -0
- data/app/pb_kits/playbook/pb_filter/filter.test.js +76 -0
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.html.erb +32 -0
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.jsx +101 -0
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.md +1 -0
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_sizing.html.erb +2 -1
- data/app/pb_kits/playbook/pb_gauge/docs/_gauge_sizing.jsx +2 -0
- data/app/pb_kits/playbook/pb_gauge/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_gauge/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.tsx +129 -0
- data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_default.jsx +1 -1
- data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_emphasis.jsx +2 -2
- data/app/pb_kits/playbook/pb_home_address_street/home_adress_street.test.js +60 -0
- data/app/pb_kits/playbook/pb_icon_stat_value/{_icon_stat_value.jsx → _icon_stat_value.tsx} +2 -4
- data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.test.js +154 -0
- data/app/pb_kits/playbook/pb_icon_value/{_icon_value.jsx → _icon_value.tsx} +2 -4
- data/app/pb_kits/playbook/pb_icon_value/icon_value.test.js +77 -0
- data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +123 -0
- data/app/pb_kits/playbook/pb_label_value/label_value.test.js +109 -0
- data/app/pb_kits/playbook/pb_layout/layout.test.js +1 -2
- data/app/pb_kits/playbook/pb_lightbox/Carousel/Slides.tsx +33 -0
- data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnails.tsx +1 -3
- data/app/pb_kits/playbook/pb_lightbox/Carousel/index.tsx +3 -1
- data/app/pb_kits/playbook/pb_lightbox/{_lightbox_header.tsx → Header/_lightbox_header.tsx} +8 -8
- data/app/pb_kits/playbook/pb_lightbox/{_lightbox_header_icon.tsx → Header/_lightbox_header_icon.tsx} +2 -2
- data/app/pb_kits/playbook/pb_lightbox/_lightbox.tsx +2 -1
- data/app/pb_kits/playbook/pb_lightbox/lightbox.scss +8 -60
- data/app/pb_kits/playbook/pb_popover/popover.rb +1 -1
- data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +5 -5
- data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +0 -1
- data/app/pb_kits/playbook/pb_title/_title.tsx +1 -1
- data/app/pb_kits/playbook/playbook-rails.js +1 -1
- data/app/pb_kits/playbook/plugins/pb_chart.js +5 -0
- data/app/pb_kits/playbook/tokens/_spacing.scss +2 -0
- data/app/pb_kits/playbook/utilities/_spacing.scss +1 -0
- data/app/pb_kits/playbook/utilities/text.ts +1 -1
- data/lib/playbook/spacing.rb +1 -1
- data/lib/playbook/version.rb +2 -2
- metadata +39 -21
- data/app/pb_kits/playbook/pb_date_picker/plugins/timeSelect.js +0 -137
- data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.jsx +0 -103
- data/app/pb_kits/playbook/pb_dialog/_dialog.jsx +0 -223
- data/app/pb_kits/playbook/pb_dialog/_dialog_context.jsx +0 -3
- data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.jsx +0 -127
- data/app/pb_kits/playbook/pb_label_value/_label_value.jsx +0 -155
@@ -0,0 +1,217 @@
|
|
1
|
+
/* eslint-disable react/jsx-handler-names */
|
2
|
+
/* eslint-disable react/no-multi-comp */
|
3
|
+
|
4
|
+
import React, { useState } from "react";
|
5
|
+
import classnames from "classnames";
|
6
|
+
import Modal from "react-modal";
|
7
|
+
|
8
|
+
import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
|
9
|
+
import { globalProps } from "../utilities/globalProps";
|
10
|
+
|
11
|
+
import Body from "../pb_body/_body";
|
12
|
+
import Button from "../pb_button/_button";
|
13
|
+
import DialogHeader from "./child_kits/_dialog_header";
|
14
|
+
import DialogFooter from "./child_kits/_dialog_footer";
|
15
|
+
import DialogBody from "./child_kits/_dialog_body";
|
16
|
+
import Flex from "../pb_flex/_flex";
|
17
|
+
import IconCircle from "../pb_icon_circle/_icon_circle";
|
18
|
+
import Title from "../pb_title/_title";
|
19
|
+
import { DialogContext } from "./_dialog_context";
|
20
|
+
|
21
|
+
type DialogProps = {
|
22
|
+
aria?: { [key: string]: string };
|
23
|
+
cancelButton?: string;
|
24
|
+
children: React.ReactNode | React.ReactNode[] | string;
|
25
|
+
className?: string;
|
26
|
+
closeable: boolean;
|
27
|
+
confirmButton?: string;
|
28
|
+
data?: object;
|
29
|
+
id?: string;
|
30
|
+
loading?: boolean;
|
31
|
+
onCancel?: () => void;
|
32
|
+
onChange?: () => void;
|
33
|
+
onClose?: () => void;
|
34
|
+
onConfirm?: () => void;
|
35
|
+
opened: boolean;
|
36
|
+
portalClassName?: string;
|
37
|
+
shouldCloseOnOverlayClick: boolean;
|
38
|
+
size?: "sm" | "md" | "lg" | "status_size" | "content";
|
39
|
+
status?: "info" | "caution" | "delete" | "error" | "success";
|
40
|
+
text?: string;
|
41
|
+
title?: string;
|
42
|
+
trigger?: string;
|
43
|
+
};
|
44
|
+
|
45
|
+
const Dialog = (props: DialogProps) => {
|
46
|
+
const {
|
47
|
+
aria = {},
|
48
|
+
cancelButton,
|
49
|
+
confirmButton,
|
50
|
+
className,
|
51
|
+
data = {},
|
52
|
+
id,
|
53
|
+
size = "md",
|
54
|
+
children,
|
55
|
+
loading = false,
|
56
|
+
opened,
|
57
|
+
onCancel = () => {},
|
58
|
+
onConfirm = () => {},
|
59
|
+
onClose = () => {},
|
60
|
+
portalClassName,
|
61
|
+
shouldCloseOnOverlayClick = true,
|
62
|
+
status,
|
63
|
+
text,
|
64
|
+
title,
|
65
|
+
trigger,
|
66
|
+
} = props;
|
67
|
+
const ariaProps = buildAriaProps(aria);
|
68
|
+
const dataProps = buildDataProps(data);
|
69
|
+
const dialogClassNames = {
|
70
|
+
base: classnames("pb_dialog", buildCss("pb_dialog", size)),
|
71
|
+
afterOpen: "pb_dialog_after_open",
|
72
|
+
beforeClose: "pb_dialog_before_close",
|
73
|
+
};
|
74
|
+
|
75
|
+
const overlayClassNames = {
|
76
|
+
base: "pb_dialog_overlay",
|
77
|
+
afterOpen: "pb_dialog_overlay_after_open",
|
78
|
+
beforeClose: "pb_dialog_overlay_before_close",
|
79
|
+
};
|
80
|
+
|
81
|
+
const classes = classnames(
|
82
|
+
buildCss("pb_dialog_wrapper"),
|
83
|
+
globalProps(props),
|
84
|
+
className
|
85
|
+
);
|
86
|
+
|
87
|
+
const [triggerOpened, setTriggerOpened] = useState(false),
|
88
|
+
modalIsOpened = trigger ? triggerOpened : opened;
|
89
|
+
|
90
|
+
const api = {
|
91
|
+
onClose: trigger
|
92
|
+
? function () {
|
93
|
+
setTriggerOpened(false);
|
94
|
+
}
|
95
|
+
: onClose,
|
96
|
+
};
|
97
|
+
|
98
|
+
if (trigger) {
|
99
|
+
const modalTrigger = document.querySelector(trigger);
|
100
|
+
modalTrigger.addEventListener(
|
101
|
+
"click",
|
102
|
+
() => {
|
103
|
+
setTriggerOpened(true);
|
104
|
+
document
|
105
|
+
.querySelector("#cancel-button")
|
106
|
+
.addEventListener("click", () => {
|
107
|
+
setTriggerOpened(false);
|
108
|
+
});
|
109
|
+
},
|
110
|
+
{ once: true }
|
111
|
+
);
|
112
|
+
}
|
113
|
+
|
114
|
+
type sweetAlertStatusProps = {
|
115
|
+
[key: string]: {
|
116
|
+
icon: string,
|
117
|
+
variant: "default" | "yellow" | "red" | "green" | "royal" | "blue" | "purple" | "teal",
|
118
|
+
size: "sm" | "md" | "lg" | "base" | "xs" | "xl";
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
const sweetAlertStatus: sweetAlertStatusProps = {
|
123
|
+
default: {
|
124
|
+
icon: "exclamation-circle",
|
125
|
+
variant: "default",
|
126
|
+
size: "lg",
|
127
|
+
},
|
128
|
+
info: {
|
129
|
+
icon: "info-circle",
|
130
|
+
variant: "default",
|
131
|
+
size: "lg",
|
132
|
+
},
|
133
|
+
caution: {
|
134
|
+
icon: "exclamation-triangle",
|
135
|
+
variant: "yellow",
|
136
|
+
size: "lg",
|
137
|
+
},
|
138
|
+
delete: {
|
139
|
+
icon: "trash-alt",
|
140
|
+
variant: "red",
|
141
|
+
size: "lg",
|
142
|
+
},
|
143
|
+
error: {
|
144
|
+
icon: "times-circle",
|
145
|
+
variant: "red",
|
146
|
+
size: "lg",
|
147
|
+
},
|
148
|
+
success: {
|
149
|
+
icon: "check-circle",
|
150
|
+
variant: "green",
|
151
|
+
size: "lg",
|
152
|
+
},
|
153
|
+
};
|
154
|
+
|
155
|
+
return (
|
156
|
+
<DialogContext.Provider value={api}>
|
157
|
+
<div {...ariaProps} {...dataProps} className={classes}>
|
158
|
+
<Modal
|
159
|
+
ariaHideApp={false}
|
160
|
+
className={dialogClassNames}
|
161
|
+
closeTimeoutMS={200}
|
162
|
+
contentLabel="Minimal Modal Example"
|
163
|
+
id={id}
|
164
|
+
isOpen={modalIsOpened}
|
165
|
+
onRequestClose={onClose}
|
166
|
+
overlayClassName={overlayClassNames}
|
167
|
+
portalClassName={portalClassName}
|
168
|
+
shouldCloseOnOverlayClick={shouldCloseOnOverlayClick}
|
169
|
+
>
|
170
|
+
<>
|
171
|
+
{title && !status ? <Dialog.Header>{title}</Dialog.Header> : null}
|
172
|
+
{!status && text ? <Dialog.Body>{text}</Dialog.Body> : null}
|
173
|
+
{status && (
|
174
|
+
<Dialog.Body padding="md">
|
175
|
+
<Flex align="center" orientation="column">
|
176
|
+
<IconCircle
|
177
|
+
icon={sweetAlertStatus[status].icon}
|
178
|
+
size={sweetAlertStatus[status].size}
|
179
|
+
variant={sweetAlertStatus[status].variant}
|
180
|
+
/>
|
181
|
+
<Title marginTop="sm" size={3}>
|
182
|
+
{title}
|
183
|
+
</Title>
|
184
|
+
<Body marginTop="xs" text={text} />
|
185
|
+
</Flex>
|
186
|
+
</Dialog.Body>
|
187
|
+
)}
|
188
|
+
{cancelButton && confirmButton ? (
|
189
|
+
<Dialog.Footer>
|
190
|
+
<Button
|
191
|
+
loading={loading}
|
192
|
+
onClick={onConfirm}
|
193
|
+
htmlType="button"
|
194
|
+
variant="primary">
|
195
|
+
{confirmButton}
|
196
|
+
</Button>
|
197
|
+
<Button
|
198
|
+
id="cancel-button"
|
199
|
+
onClick={onCancel}
|
200
|
+
variant="link"
|
201
|
+
htmlType="button">
|
202
|
+
{cancelButton}
|
203
|
+
</Button>
|
204
|
+
</Dialog.Footer>
|
205
|
+
) : null}
|
206
|
+
{children}
|
207
|
+
</>
|
208
|
+
</Modal>
|
209
|
+
</div>
|
210
|
+
</DialogContext.Provider>
|
211
|
+
);
|
212
|
+
};
|
213
|
+
Dialog.Header = DialogHeader;
|
214
|
+
Dialog.Body = DialogBody;
|
215
|
+
Dialog.Footer = DialogFooter;
|
216
|
+
|
217
|
+
export default Dialog;
|
@@ -1,10 +1,14 @@
|
|
1
|
-
/* @flow */
|
2
|
-
|
3
1
|
import React from 'react'
|
4
2
|
import classnames from 'classnames'
|
5
3
|
import { buildCss } from '../../utilities/props'
|
6
4
|
import { globalProps } from '../../utilities/globalProps'
|
7
5
|
|
6
|
+
type DialogBodyProps = {
|
7
|
+
children: React.ReactNode | React.ReactNode[] | string,
|
8
|
+
padding?: "xxs" | "xs" | "sm" | "md" | "lg" | "xl",
|
9
|
+
className?: string
|
10
|
+
}
|
11
|
+
|
8
12
|
// Body component
|
9
13
|
const DialogBody = (props: DialogBodyProps) => {
|
10
14
|
const { children, padding = "sm", className } = props
|
@@ -1,10 +1,8 @@
|
|
1
|
-
/* @flow */
|
2
|
-
|
3
1
|
import React from 'react'
|
4
2
|
import classnames from 'classnames'
|
5
3
|
|
6
4
|
import { buildCss } from '../../utilities/props'
|
7
|
-
import { globalProps } from '../../utilities/globalProps'
|
5
|
+
import { GlobalProps, globalProps } from '../../utilities/globalProps'
|
8
6
|
|
9
7
|
import Flex from '../../pb_flex/_flex'
|
10
8
|
import SectionSeparator from '../../pb_section_separator/_section_separator'
|
@@ -12,17 +10,16 @@ import SectionSeparator from '../../pb_section_separator/_section_separator'
|
|
12
10
|
|
13
11
|
type DialogFooterProps = {
|
14
12
|
aria?: object,
|
15
|
-
children:
|
13
|
+
children: React.ReactChild[] | React.ReactChild | string,
|
16
14
|
className?: string,
|
17
|
-
closeable: boolean,
|
18
15
|
data?: object,
|
19
16
|
id?: string,
|
20
17
|
padding?: string,
|
21
18
|
paddingBottom?: string,
|
22
19
|
paddingX?: string,
|
23
|
-
separator
|
24
|
-
spacing?:
|
25
|
-
}
|
20
|
+
separator?: boolean,
|
21
|
+
spacing?: "none" | "between" | "around" | "evenly",
|
22
|
+
} & GlobalProps
|
26
23
|
|
27
24
|
// Footer component
|
28
25
|
const DialogFooter = (props: DialogFooterProps) => {
|
@@ -41,9 +38,9 @@ const DialogFooter = (props: DialogFooterProps) => {
|
|
41
38
|
|
42
39
|
return (
|
43
40
|
<>
|
44
|
-
|
45
|
-
<SectionSeparator />
|
46
|
-
|
41
|
+
{separator &&
|
42
|
+
<SectionSeparator aria={{dd: 'ff'}} className="dd" data={{dd: 'ff'}} id="d" text="ss"/>
|
43
|
+
}
|
47
44
|
<Flex
|
48
45
|
className={classnames(footerCSS, footerSpacing, className)}
|
49
46
|
spacing={spacing}
|
@@ -1,9 +1,7 @@
|
|
1
|
-
/* @flow */
|
2
|
-
|
3
1
|
import React, { useContext } from 'react'
|
4
2
|
import classnames from 'classnames'
|
5
3
|
import { buildAriaProps, buildCss, buildDataProps } from '../../utilities/props'
|
6
|
-
import { globalProps } from '../../utilities/globalProps'
|
4
|
+
import { globalProps, GlobalProps } from '../../utilities/globalProps'
|
7
5
|
|
8
6
|
import { CloseIcon } from '../_close_icon'
|
9
7
|
import { DialogContext } from '../_dialog_context'
|
@@ -11,18 +9,18 @@ import Flex from '../../pb_flex/_flex'
|
|
11
9
|
import SectionSeparator from '../../pb_section_separator/_section_separator'
|
12
10
|
|
13
11
|
type DialogHeaderProps = {
|
14
|
-
aria?:
|
15
|
-
children:
|
12
|
+
aria?: {[key: string]: string},
|
13
|
+
children: React.ReactNode[] | React.ReactNode | string,
|
16
14
|
className?: string,
|
17
|
-
closeable
|
15
|
+
closeable?: boolean,
|
18
16
|
data?: object,
|
19
17
|
id?: string,
|
20
18
|
padding?: string,
|
21
|
-
separator
|
22
|
-
spacing?:
|
19
|
+
separator?: boolean,
|
20
|
+
spacing?: "none" | "between" | "around" | "evenly",
|
23
21
|
text?: string,
|
24
22
|
title?: string,
|
25
|
-
}
|
23
|
+
} & GlobalProps
|
26
24
|
|
27
25
|
const DialogHeader = (props: DialogHeaderProps) => {
|
28
26
|
const {
|
@@ -53,16 +51,15 @@ const DialogHeader = (props: DialogHeaderProps) => {
|
|
53
51
|
spacing={spacing}
|
54
52
|
>
|
55
53
|
{children}
|
56
|
-
|
54
|
+
{closeable &&
|
57
55
|
<CloseIcon
|
58
|
-
|
59
|
-
onClose={api.onClose}
|
56
|
+
onClose={api.onClose}
|
60
57
|
/>
|
61
|
-
|
58
|
+
}
|
62
59
|
</Flex>
|
63
|
-
|
60
|
+
{separator &&
|
64
61
|
<SectionSeparator />
|
65
|
-
|
62
|
+
}
|
66
63
|
</>
|
67
64
|
)
|
68
65
|
}
|
@@ -33,6 +33,7 @@ const FilterDouble = ({
|
|
33
33
|
children,
|
34
34
|
dark,
|
35
35
|
minWidth,
|
36
|
+
placement,
|
36
37
|
...bgProps
|
37
38
|
}: FilterDoubleProps) => (
|
38
39
|
<FilterBackground
|
@@ -46,6 +47,7 @@ const FilterDouble = ({
|
|
46
47
|
<FiltersPopover
|
47
48
|
dark={dark}
|
48
49
|
minWidth={minWidth}
|
50
|
+
placement={placement}
|
49
51
|
>
|
50
52
|
{children}
|
51
53
|
</FiltersPopover>
|
@@ -33,6 +33,7 @@ const FilterSingle = ({
|
|
33
33
|
children,
|
34
34
|
dark,
|
35
35
|
minWidth,
|
36
|
+
placement,
|
36
37
|
...bgProps
|
37
38
|
}: FilterSingleProps) => {
|
38
39
|
return (
|
@@ -49,6 +50,7 @@ const FilterSingle = ({
|
|
49
50
|
<FiltersPopover
|
50
51
|
dark={dark}
|
51
52
|
minWidth={minWidth}
|
53
|
+
placement={placement}
|
52
54
|
>
|
53
55
|
{children}
|
54
56
|
</FiltersPopover>
|
@@ -6,7 +6,7 @@ import CircleIconButton from '../../pb_circle_icon_button/_circle_icon_button'
|
|
6
6
|
import PbReactPopover from '../../pb_popover/_popover'
|
7
7
|
|
8
8
|
const FiltersPopoverProps = { children: Node }
|
9
|
-
const FiltersPopover = ({ children, dark, minWidth }: FiltersPopoverProps) => {
|
9
|
+
const FiltersPopover = ({ children, dark, minWidth, placement = "bottom-start" }: FiltersPopoverProps) => {
|
10
10
|
const [hide, updateHide] = useState(true)
|
11
11
|
const toggle = () => updateHide(!hide)
|
12
12
|
|
@@ -25,7 +25,7 @@ const FiltersPopover = ({ children, dark, minWidth }: FiltersPopoverProps) => {
|
|
25
25
|
<PbReactPopover
|
26
26
|
closeOnClick="outside"
|
27
27
|
minWidth={minWidth}
|
28
|
-
placement=
|
28
|
+
placement={placement}
|
29
29
|
reference={filterButton}
|
30
30
|
shouldClosePopover={updateHide}
|
31
31
|
show={!hide}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<%=
|
2
|
+
pb_rails("filter", props: {
|
3
|
+
id: "pla",
|
4
|
+
filters: [
|
5
|
+
{ name: "name", value: "John Wick" }
|
6
|
+
],
|
7
|
+
placement: "right",
|
8
|
+
template:"filter_only",
|
9
|
+
}) do
|
10
|
+
%>
|
11
|
+
<%
|
12
|
+
example_collection = [
|
13
|
+
OpenStruct.new(name: "Alabama", value: 1),
|
14
|
+
OpenStruct.new(name: "Alaska", value: 2),
|
15
|
+
OpenStruct.new(name: "Arizona", value: 3),
|
16
|
+
OpenStruct.new(name: "Arkansas", value: 4),
|
17
|
+
OpenStruct.new(name: "California", value: 5),
|
18
|
+
OpenStruct.new(name: "Colorado", value: 6),
|
19
|
+
OpenStruct.new(name: "Connecticut", value: 7),
|
20
|
+
OpenStruct.new(name: "Delaware", value: 8),
|
21
|
+
OpenStruct.new(name: "Florida", value: 9),
|
22
|
+
OpenStruct.new(name: "Georgia", value: 10),
|
23
|
+
]
|
24
|
+
%>
|
25
|
+
<%= pb_rails("form", props: { form_system_options: { scope: :example, method: :get } }) do |form| %>
|
26
|
+
<%= form.text_field :example_text_field, props: { label: true } %>
|
27
|
+
<%= form.collection_select :example_collection_select, example_collection, :value, :name, props: { label: true } %>
|
28
|
+
|
29
|
+
<%= form.actions do |action| %>
|
30
|
+
<%= action.submit props: { text: "Apply", data: { disable_with: "<i class='far fa-spinner fa-spin mr-3'></i>Searching...".html_safe },}%>
|
31
|
+
<%= action.button props: { type: "reset", text: "Clear", variant: "secondary" } %>
|
32
|
+
<% end %>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import { Button, Filter, Flex, Select, TextInput } from '../..'
|
3
|
+
|
4
|
+
const SortingChangeCallback = (sortOptions) => {
|
5
|
+
alert(JSON.stringify(sortOptions[0]))
|
6
|
+
}
|
7
|
+
|
8
|
+
const FilterPlacement = (props) => {
|
9
|
+
const options = [
|
10
|
+
{ value: 'USA' },
|
11
|
+
{ value: 'Canada' },
|
12
|
+
{ value: 'Brazil' },
|
13
|
+
{ value: 'Philippines' },
|
14
|
+
{ value: 'A Galaxy Far Far Away Like Really Far Away' },
|
15
|
+
]
|
16
|
+
return (
|
17
|
+
|
18
|
+
<>
|
19
|
+
<Filter
|
20
|
+
double
|
21
|
+
onSortChange={SortingChangeCallback}
|
22
|
+
placement={"right"}
|
23
|
+
results={1}
|
24
|
+
sortOptions={{
|
25
|
+
popularity: 'Popularity',
|
26
|
+
// eslint-disable-next-line
|
27
|
+
manager_title: 'Manager\'s Title',
|
28
|
+
// eslint-disable-next-line
|
29
|
+
manager_name: 'Manager\'s Name',
|
30
|
+
}}
|
31
|
+
sortValue={[{ name: 'popularity', dir: 'desc' }]}
|
32
|
+
{...props}
|
33
|
+
>
|
34
|
+
<TextInput
|
35
|
+
label="Example Text Field"
|
36
|
+
placeholder="Enter Text"
|
37
|
+
{...props}
|
38
|
+
/>
|
39
|
+
|
40
|
+
<Select
|
41
|
+
blankSelection="Select One..."
|
42
|
+
label="Example Collection Select"
|
43
|
+
name="Collection Select"
|
44
|
+
options={options}
|
45
|
+
{...props}
|
46
|
+
/>
|
47
|
+
<Flex
|
48
|
+
spacing="between"
|
49
|
+
{...props}
|
50
|
+
>
|
51
|
+
<Button
|
52
|
+
text="Apply"
|
53
|
+
{...props}
|
54
|
+
/>
|
55
|
+
<Button
|
56
|
+
text="Clear"
|
57
|
+
variant="secondary"
|
58
|
+
{...props}
|
59
|
+
/>
|
60
|
+
</Flex>
|
61
|
+
</Filter>
|
62
|
+
</>
|
63
|
+
)
|
64
|
+
}
|
65
|
+
|
66
|
+
export default FilterPlacement
|
@@ -0,0 +1,4 @@
|
|
1
|
+
Click the filter buttom above to toggle the popover.
|
2
|
+
|
3
|
+
To change the filter's popover position, use the `placement` prop with one of the positions:
|
4
|
+
`"top" | "right" | "bottom" | "left" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "right-start" | "right-end" | "left-start" | "left-end"`
|
@@ -8,6 +8,7 @@ examples:
|
|
8
8
|
- filter_only: Filter Only
|
9
9
|
- sort_only: Sort Only
|
10
10
|
- filter_min_width: Min Width for Popover Inside of Filter
|
11
|
+
- filter_placement: Filter Placement
|
11
12
|
|
12
13
|
react:
|
13
14
|
- filter_default: Default
|
@@ -18,3 +19,4 @@ examples:
|
|
18
19
|
- sort_only: Sort Only
|
19
20
|
- filter_min_width: Min Width for Popover Inside of Filter
|
20
21
|
- filter_close_popover: Close Popover
|
22
|
+
- filter_placement: Filter Placement
|
@@ -6,3 +6,4 @@ export { default as FilterOnly } from './_filter_only.jsx'
|
|
6
6
|
export { default as SortOnly } from './_sort_only.jsx'
|
7
7
|
export { default as FilterMinWidth } from './_filter_min_width.jsx'
|
8
8
|
export { default as FilterClosePopover } from './_filter_close_popover.jsx'
|
9
|
+
export { default as FilterPlacement } from './_filter_placement.jsx'
|
@@ -69,13 +69,13 @@
|
|
69
69
|
<% end %>
|
70
70
|
|
71
71
|
<% if object.template != "sort_only"%>
|
72
|
-
<%= pb_rails("popover", props: {min_width: object.min_width, close_on_click: "outside", trigger_element_id: "filter#{object.id}", tooltip_id: "filter-form#{object.id}", position:
|
72
|
+
<%= pb_rails("popover", props: {min_width: object.min_width, close_on_click: "outside", trigger_element_id: "filter#{object.id}", tooltip_id: "filter-form#{object.id}", position: object.placement }) do %>
|
73
73
|
<%= content %>
|
74
74
|
<% end %>
|
75
75
|
<%end%>
|
76
76
|
|
77
77
|
<% if object.template != "filter_only"%>
|
78
|
-
<%= pb_rails("popover", props: {classname: "pb_filter_sort_menu", close_on_click: "outside", trigger_element_id: "sort-button#{object.id}", tooltip_id: "sort-filter-btn-tooltip#{object.id}", position:
|
78
|
+
<%= pb_rails("popover", props: {classname: "pb_filter_sort_menu", close_on_click: "outside", trigger_element_id: "sort-button#{object.id}", tooltip_id: "sort-filter-btn-tooltip#{object.id}", position: object.placement , padding: 'none'}) do %>
|
79
79
|
<%= pb_rails("list") do %>
|
80
80
|
<% object.sort_menu.each do |item| %>
|
81
81
|
<%= pb_rails("list/item") do%> <%= pb_rails("button", props: {variant: "link" ,classname: "p-0", text: item[:item], link: item[:link]}) %><% end %>
|
@@ -11,6 +11,9 @@ module Playbook
|
|
11
11
|
default: "default"
|
12
12
|
prop :background, type: Playbook::Props::Boolean, default: true
|
13
13
|
prop :min_width, default: "auto"
|
14
|
+
prop :placement, type: Playbook::Props::Enum,
|
15
|
+
values: %w[top bottom left right top-start top-end bottom-start bottom-end right-start right-end left-start left-end],
|
16
|
+
default: "bottom-start"
|
14
17
|
|
15
18
|
def classname
|
16
19
|
generate_classname("pb_filter_kit")
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import {
|
3
|
+
render,
|
4
|
+
screen,
|
5
|
+
fireEvent,
|
6
|
+
} from "../utilities/test-utils";
|
7
|
+
import { Button, Filter, Flex, Select, TextInput } from "..";
|
8
|
+
|
9
|
+
function FilterTest(props) {
|
10
|
+
const SortingChangeCallback = (sortOptions) => {
|
11
|
+
alert(JSON.stringify(sortOptions[0]));
|
12
|
+
};
|
13
|
+
|
14
|
+
const options = [
|
15
|
+
{ value: "USA" },
|
16
|
+
{ value: "Canada" },
|
17
|
+
{ value: "Brazil" },
|
18
|
+
{ value: "Philippines" },
|
19
|
+
{ value: "A Galaxy Far Far Away Like Really Far Away" },
|
20
|
+
];
|
21
|
+
return (
|
22
|
+
<Filter
|
23
|
+
onSortChange={SortingChangeCallback}
|
24
|
+
results={1}
|
25
|
+
sortOptions={{
|
26
|
+
popularity: "Popularity",
|
27
|
+
// eslint-disable-next-line
|
28
|
+
manager_title: "Manager's Title",
|
29
|
+
// eslint-disable-next-line
|
30
|
+
manager_name: "Manager's Name",
|
31
|
+
}}
|
32
|
+
sortValue={[{ name: "popularity", dir: "desc" }]}
|
33
|
+
{...props}
|
34
|
+
>
|
35
|
+
<TextInput
|
36
|
+
label="Example Text Field"
|
37
|
+
placeholder="Enter Text"
|
38
|
+
{...props}
|
39
|
+
/>
|
40
|
+
|
41
|
+
<Select
|
42
|
+
blankSelection="Select One..."
|
43
|
+
label="Example Collection Select"
|
44
|
+
name="Collection Select"
|
45
|
+
options={options}
|
46
|
+
{...props}
|
47
|
+
/>
|
48
|
+
<Flex spacing="between"
|
49
|
+
{...props}>
|
50
|
+
<Button text="Apply"
|
51
|
+
{...props} />
|
52
|
+
<Button text="Clear"
|
53
|
+
variant="secondary"
|
54
|
+
{...props} />
|
55
|
+
</Flex>
|
56
|
+
</Filter>
|
57
|
+
);
|
58
|
+
}
|
59
|
+
|
60
|
+
test("triggers popover on filter button click", () => {
|
61
|
+
render(<FilterTest data={{ testid: "render-test" }}/>);
|
62
|
+
|
63
|
+
const btn = screen.getAllByRole("button")[0];
|
64
|
+
|
65
|
+
// checks if the sort menu rendered
|
66
|
+
expect(screen.getByLabelText("sort-amount-down icon")).toBeInTheDocument()
|
67
|
+
expect(screen.getByText('Popularity')).toBeInTheDocument() // check if filter/sort is rendered
|
68
|
+
|
69
|
+
// hits the filter button and triggers popover
|
70
|
+
fireEvent.click(btn);
|
71
|
+
|
72
|
+
// check if popover displays correctly by checking its tet
|
73
|
+
expect(screen.getByText("Example Text Field")).toBeInTheDocument()
|
74
|
+
|
75
|
+
|
76
|
+
});
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%= pb_rails("flex", props: {wrap: true, padding: "xl", gap: "sm"}) do %>
|
2
|
+
<%= pb_rails("flex/flex_item", props: {flex: 1, grow: true }) do %>
|
3
|
+
<%= pb_rails("card", props: {max_width: "xs", padding: "md", }) do %>
|
4
|
+
<%= pb_rails("title", props: {padding_bottom: "sm", size: 4, text: "Abandoned Calls" })%>
|
5
|
+
<%= pb_rails("flex", props: {align: "stretch"}) do %>
|
6
|
+
<%= pb_rails("flex", props: {margin_right: "sm", orientation: "column"}) do %>
|
7
|
+
<%= pb_rails("body", props: {color: "light", padding_bottom: "sm",text: "Total Abandoned"}) %>
|
8
|
+
<%= pb_rails("flex", props: {align: "baseline", padding_bottom: "sx"}) do %>
|
9
|
+
<%= pb_rails("title", props: {size: 1, text: "39"})%>
|
10
|
+
<%= pb_rails("title", props: {color: "light", size: 3, text: "calls"}) %>
|
11
|
+
<% end %>
|
12
|
+
<%= pb_rails("caption", props: {size: "xs", text: "of 390" }) %>
|
13
|
+
<%end %>
|
14
|
+
<%= pb_rails("section_separator", props: {align_self: "stretch", margin_right: "sm", orientation: "vertical" }) %>
|
15
|
+
<%= pb_rails("flex", props: {orientation: "column", wrap: true}) do %>
|
16
|
+
<%= pb_rails("body", props: {color: "light", text: "% Abandoned"}) %>
|
17
|
+
<%= pb_rails("flex", props: {wrap: true}) do %>
|
18
|
+
<%= pb_rails("flex/flex_item", props: {fixed_size: "150px", overflow: "hidden", shrink: true}) do %>
|
19
|
+
<%= pb_rails("gauge", props: {
|
20
|
+
chart_data: [{ name: "Name", value: 10 }],
|
21
|
+
disable_animation: true,
|
22
|
+
height: '100%',
|
23
|
+
id: "gauge-complex",
|
24
|
+
suffix: "%"
|
25
|
+
}) %>
|
26
|
+
<% end %>
|
27
|
+
<% end %>
|
28
|
+
<% end %>
|
29
|
+
<%end %>
|
30
|
+
<% end %>
|
31
|
+
<% end %>
|
32
|
+
<% end %>
|