playbook_ui 11.6.1.pre.alpha.rubocop.pre.performance1 → 11.7.0.pre.alpha.table1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/data/menu.yml +0 -13
  3. data/app/pb_kits/playbook/index.js +1 -1
  4. data/app/pb_kits/playbook/pb_badge/badge.test.js +80 -0
  5. data/app/pb_kits/playbook/pb_button/_button.tsx +7 -2
  6. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +7 -0
  7. data/app/pb_kits/playbook/pb_button/button.html.erb +11 -0
  8. data/app/pb_kits/playbook/pb_button/button.rb +3 -0
  9. data/app/pb_kits/playbook/pb_button/docs/_button_block_content.html.erb +1 -1
  10. data/app/pb_kits/playbook/pb_button/docs/_button_block_content.jsx +12 -9
  11. data/app/pb_kits/playbook/pb_button/docs/_button_block_content.md +1 -0
  12. data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.html.erb +2 -0
  13. data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.jsx +23 -0
  14. data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.md +1 -0
  15. data/app/pb_kits/playbook/pb_button/docs/example.yml +2 -0
  16. data/app/pb_kits/playbook/pb_button/docs/index.js +1 -0
  17. data/app/pb_kits/playbook/pb_date_picker/{_date_picker.jsx → _date_picker.tsx} +58 -66
  18. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +2 -1
  19. data/app/pb_kits/playbook/pb_date_picker/{date_picker_helper.js → date_picker_helper.ts} +37 -16
  20. data/app/pb_kits/playbook/pb_date_picker/plugins/timeSelect.ts +171 -0
  21. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_flatpickr_styles.scss +0 -3
  22. data/app/pb_kits/playbook/pb_date_range_stacked/{_date_range_stacked.jsx → _date_range_stacked.tsx} +5 -6
  23. data/app/pb_kits/playbook/pb_date_range_stacked/date_range_stacked.test.js +127 -0
  24. data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.tsx +90 -0
  25. data/app/pb_kits/playbook/pb_date_stacked/date_stacked.test.js +151 -0
  26. data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_align.jsx +1 -1
  27. data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_bold.jsx +1 -1
  28. data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_default.jsx +1 -1
  29. data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_not_current_year.jsx +1 -1
  30. data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_reverse.jsx +1 -1
  31. data/app/pb_kits/playbook/pb_date_stacked/docs/_date_stacked_sizes.jsx +1 -1
  32. data/app/pb_kits/playbook/pb_dialog/{_close_icon.jsx → _close_icon.tsx} +1 -3
  33. data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +217 -0
  34. data/app/pb_kits/playbook/pb_dialog/_dialog_context.tsx +3 -0
  35. data/app/pb_kits/playbook/pb_dialog/child_kits/{_dialog_body.jsx → _dialog_body.tsx} +6 -2
  36. data/app/pb_kits/playbook/pb_dialog/child_kits/{_dialog_footer.jsx → _dialog_footer.tsx} +8 -11
  37. data/app/pb_kits/playbook/pb_dialog/child_kits/{_dialog_header.jsx → _dialog_header.tsx} +12 -15
  38. data/app/pb_kits/playbook/pb_filter/Filter/FilterDouble.jsx +2 -0
  39. data/app/pb_kits/playbook/pb_filter/Filter/FilterSingle.jsx +2 -0
  40. data/app/pb_kits/playbook/pb_filter/Filter/FiltersPopover.jsx +2 -2
  41. data/app/pb_kits/playbook/pb_filter/docs/_filter_min_width.html.erb +1 -0
  42. data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.html.erb +34 -0
  43. data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.jsx +66 -0
  44. data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.md +4 -0
  45. data/app/pb_kits/playbook/pb_filter/docs/example.yml +2 -0
  46. data/app/pb_kits/playbook/pb_filter/docs/index.js +1 -0
  47. data/app/pb_kits/playbook/pb_filter/filter.html.erb +2 -2
  48. data/app/pb_kits/playbook/pb_filter/filter.rb +3 -0
  49. data/app/pb_kits/playbook/pb_filter/filter.test.js +76 -0
  50. data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.html.erb +32 -0
  51. data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.jsx +101 -0
  52. data/app/pb_kits/playbook/pb_gauge/docs/_gauge_complex.md +1 -0
  53. data/app/pb_kits/playbook/pb_gauge/docs/_gauge_sizing.html.erb +2 -1
  54. data/app/pb_kits/playbook/pb_gauge/docs/_gauge_sizing.jsx +2 -0
  55. data/app/pb_kits/playbook/pb_gauge/docs/example.yml +2 -0
  56. data/app/pb_kits/playbook/pb_gauge/docs/index.js +1 -0
  57. data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.tsx +129 -0
  58. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_default.jsx +1 -1
  59. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_emphasis.jsx +2 -2
  60. data/app/pb_kits/playbook/pb_home_address_street/home_adress_street.test.js +60 -0
  61. data/app/pb_kits/playbook/pb_icon_stat_value/{_icon_stat_value.jsx → _icon_stat_value.tsx} +2 -4
  62. data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.test.js +154 -0
  63. data/app/pb_kits/playbook/pb_icon_value/{_icon_value.jsx → _icon_value.tsx} +2 -4
  64. data/app/pb_kits/playbook/pb_icon_value/icon_value.test.js +77 -0
  65. data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +123 -0
  66. data/app/pb_kits/playbook/pb_label_value/label_value.test.js +109 -0
  67. data/app/pb_kits/playbook/pb_layout/layout.test.js +1 -2
  68. data/app/pb_kits/playbook/pb_lightbox/Carousel/Slides.tsx +33 -0
  69. data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnails.tsx +1 -3
  70. data/app/pb_kits/playbook/pb_lightbox/Carousel/index.tsx +3 -1
  71. data/app/pb_kits/playbook/pb_lightbox/{_lightbox_header.tsx → Header/_lightbox_header.tsx} +8 -8
  72. data/app/pb_kits/playbook/pb_lightbox/{_lightbox_header_icon.tsx → Header/_lightbox_header_icon.tsx} +2 -2
  73. data/app/pb_kits/playbook/pb_lightbox/_lightbox.tsx +2 -1
  74. data/app/pb_kits/playbook/pb_lightbox/lightbox.scss +8 -60
  75. data/app/pb_kits/playbook/pb_popover/popover.rb +1 -1
  76. data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +5 -5
  77. data/app/pb_kits/playbook/pb_table/_table.jsx +5 -3
  78. data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +0 -1
  79. data/app/pb_kits/playbook/pb_title/_title.tsx +1 -1
  80. data/app/pb_kits/playbook/playbook-rails.js +1 -1
  81. data/app/pb_kits/playbook/plugins/pb_chart.js +5 -0
  82. data/app/pb_kits/playbook/tokens/_spacing.scss +2 -0
  83. data/app/pb_kits/playbook/utilities/_spacing.scss +1 -0
  84. data/app/pb_kits/playbook/utilities/text.ts +1 -1
  85. data/lib/playbook/spacing.rb +1 -1
  86. data/lib/playbook/version.rb +2 -2
  87. metadata +37 -19
  88. data/app/pb_kits/playbook/pb_date_picker/plugins/timeSelect.js +0 -137
  89. data/app/pb_kits/playbook/pb_date_stacked/_date_stacked.jsx +0 -103
  90. data/app/pb_kits/playbook/pb_dialog/_dialog.jsx +0 -223
  91. data/app/pb_kits/playbook/pb_dialog/_dialog_context.jsx +0 -3
  92. data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.jsx +0 -127
  93. 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;
@@ -0,0 +1,3 @@
1
+ import React from 'react'
2
+
3
+ export const DialogContext = React.createContext(null)
@@ -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: array<React.ReactNode> | React.ReactNode | string,
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: boolean,
24
- spacing?: string,
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
- <If condition={separator}>
45
- <SectionSeparator />
46
- </If>
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?: object,
15
- children: array<React.ReactNode> | React.ReactNode | string,
12
+ aria?: {[key: string]: string},
13
+ children: React.ReactNode[] | React.ReactNode | string,
16
14
  className?: string,
17
- closeable: boolean,
15
+ closeable?: boolean,
18
16
  data?: object,
19
17
  id?: string,
20
18
  padding?: string,
21
- separator: boolean,
22
- spacing?: string,
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
- <If condition={closeable}>
54
+ {closeable &&
57
55
  <CloseIcon
58
- className="close-icon"
59
- onClose={api.onClose}
56
+ onClose={api.onClose}
60
57
  />
61
- </If>
58
+ }
62
59
  </Flex>
63
- <If condition={separator}>
60
+ {separator &&
64
61
  <SectionSeparator />
65
- </If>
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="bottom"
28
+ placement={placement}
29
29
  reference={filterButton}
30
30
  shouldClosePopover={updateHide}
31
31
  show={!hide}
@@ -2,6 +2,7 @@
2
2
  pb_rails("filter", props: {
3
3
  min_width: "600px",
4
4
  id: "25",
5
+ position: "top",
5
6
  filters: [
6
7
  { name: "name", value: "John Wick" },
7
8
  { name: "city", value: "San Francisco"}
@@ -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: 'bottom'}) do %>
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: 'bottom', padding: 'none'}) do %>
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 %>