playbook_ui 11.4.0 → 11.5.0.pre.alpha.datepicker1

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.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/data/menu.yml +0 -13
  3. data/app/pb_kits/playbook/pb_badge/badge.test.js +80 -0
  4. data/app/pb_kits/playbook/pb_button/_button.tsx +7 -2
  5. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +7 -0
  6. data/app/pb_kits/playbook/pb_button/button.html.erb +11 -0
  7. data/app/pb_kits/playbook/pb_button/button.rb +3 -0
  8. data/app/pb_kits/playbook/pb_button/button.test.js +6 -8
  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/_date.tsx +1 -1
  18. data/app/pb_kits/playbook/pb_date_picker/_date_picker.jsx +13 -1
  19. data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +24 -19
  20. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +1 -1
  21. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +9 -0
  22. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.js +25 -3
  23. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.html.erb +44 -0
  24. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.jsx +60 -0
  25. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.md +9 -0
  26. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions_element.html.erb +33 -0
  27. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions_element.jsx +67 -0
  28. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +4 -0
  29. data/app/pb_kits/playbook/pb_date_picker/docs/index.js +2 -0
  30. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_flatpickr_styles.scss +0 -3
  31. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_overrides.scss +4 -4
  32. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.tsx +142 -0
  33. data/app/pb_kits/playbook/pb_date_range_inline/date_range_inline.test.js +116 -0
  34. data/app/pb_kits/playbook/pb_date_range_inline/docs/_date_range_inline_default.jsx +1 -1
  35. data/app/pb_kits/playbook/pb_date_time/{_date_time.jsx → _date_time.tsx} +2 -5
  36. data/app/pb_kits/playbook/pb_date_time/dateTime.test.js +110 -0
  37. data/app/pb_kits/playbook/pb_date_time/docs/_date_time_align.jsx +1 -1
  38. data/app/pb_kits/playbook/pb_date_time/docs/_date_time_default.jsx +1 -1
  39. data/app/pb_kits/playbook/pb_date_time/docs/_date_time_size.jsx +1 -1
  40. data/app/pb_kits/playbook/pb_date_year_stacked/{_date_year_stacked.jsx → _date_year_stacked.tsx} +6 -6
  41. data/app/pb_kits/playbook/pb_date_year_stacked/date_year_stacked.test.js +67 -0
  42. data/app/pb_kits/playbook/pb_dialog/_dialog.jsx +32 -14
  43. data/app/pb_kits/playbook/pb_dialog/_dialog.scss +5 -0
  44. data/app/pb_kits/playbook/pb_dialog/child_kits/_dialog_body.jsx +2 -2
  45. data/app/pb_kits/playbook/pb_dialog/child_kits/_dialog_footer.jsx +22 -4
  46. data/app/pb_kits/playbook/pb_dialog/child_kits/_dialog_header.jsx +3 -3
  47. data/app/pb_kits/playbook/pb_dialog/dialog.test.jsx +79 -17
  48. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_stacked_alert.jsx +55 -93
  49. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_status.jsx +79 -42
  50. data/app/pb_kits/playbook/pb_file_upload/{_file_upload.jsx → _file_upload.tsx} +6 -10
  51. data/app/pb_kits/playbook/pb_filter/Filter/FilterDouble.jsx +2 -0
  52. data/app/pb_kits/playbook/pb_filter/Filter/FilterSingle.jsx +2 -0
  53. data/app/pb_kits/playbook/pb_filter/Filter/FiltersPopover.jsx +2 -2
  54. data/app/pb_kits/playbook/pb_filter/docs/_filter_min_width.html.erb +1 -0
  55. data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.html.erb +34 -0
  56. data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.jsx +66 -0
  57. data/app/pb_kits/playbook/pb_filter/docs/_filter_placement.md +4 -0
  58. data/app/pb_kits/playbook/pb_filter/docs/example.yml +2 -0
  59. data/app/pb_kits/playbook/pb_filter/docs/index.js +1 -0
  60. data/app/pb_kits/playbook/pb_filter/filter.html.erb +2 -2
  61. data/app/pb_kits/playbook/pb_filter/filter.rb +3 -0
  62. data/app/pb_kits/playbook/pb_filter/filter.test.js +76 -0
  63. data/app/pb_kits/playbook/pb_form_group/{_form_group.jsx → _form_group.tsx} +1 -4
  64. data/app/pb_kits/playbook/pb_form_group/form_group.test.js +17 -0
  65. data/app/pb_kits/playbook/pb_hashtag/_hashtag.tsx +10 -1
  66. data/app/pb_kits/playbook/pb_hashtag/docs/_hashtag_link.html.erb +5 -0
  67. data/app/pb_kits/playbook/pb_hashtag/docs/_hashtag_link.jsx +26 -0
  68. data/app/pb_kits/playbook/pb_hashtag/docs/_hashtag_link.md +1 -0
  69. data/app/pb_kits/playbook/pb_hashtag/docs/example.yml +2 -0
  70. data/app/pb_kits/playbook/pb_hashtag/docs/index.js +1 -0
  71. data/app/pb_kits/playbook/pb_hashtag/hashtag.html.erb +1 -1
  72. data/app/pb_kits/playbook/pb_hashtag/hashtag.rb +6 -0
  73. data/app/pb_kits/playbook/pb_hashtag/hashtag.test.js +54 -0
  74. data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.tsx +129 -0
  75. data/app/pb_kits/playbook/pb_home_address_street/city_emphasis.html.erb +2 -1
  76. data/app/pb_kits/playbook/pb_home_address_street/city_emphasis.rb +2 -0
  77. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_default.jsx +1 -1
  78. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_emphasis.jsx +2 -2
  79. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_link.html.erb +12 -0
  80. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_link.jsx +23 -0
  81. data/app/pb_kits/playbook/pb_home_address_street/docs/_home_address_street_link.md +1 -0
  82. data/app/pb_kits/playbook/pb_home_address_street/docs/example.yml +3 -0
  83. data/app/pb_kits/playbook/pb_home_address_street/docs/index.js +1 -0
  84. data/app/pb_kits/playbook/pb_home_address_street/home_address_street.rb +4 -0
  85. data/app/pb_kits/playbook/pb_home_address_street/home_adress_street.test.js +60 -0
  86. data/app/pb_kits/playbook/pb_home_address_street/street_emphasis.html.erb +2 -1
  87. data/app/pb_kits/playbook/pb_home_address_street/street_emphasis.rb +4 -1
  88. data/app/pb_kits/playbook/pb_icon_stat_value/{_icon_stat_value.jsx → _icon_stat_value.tsx} +2 -4
  89. data/app/pb_kits/playbook/pb_icon_stat_value/icon_stat_value.test.js +154 -0
  90. data/app/pb_kits/playbook/pb_icon_value/{_icon_value.jsx → _icon_value.tsx} +2 -4
  91. data/app/pb_kits/playbook/pb_icon_value/icon_value.test.js +77 -0
  92. data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +123 -0
  93. data/app/pb_kits/playbook/pb_label_value/label_value.test.js +109 -0
  94. data/app/pb_kits/playbook/pb_layout/{_layout.jsx → _layout.tsx} +13 -19
  95. data/app/pb_kits/playbook/pb_layout/layout.test.js +97 -0
  96. data/app/pb_kits/playbook/pb_lightbox/lightbox.test.jsx +23 -15
  97. data/app/pb_kits/playbook/pb_popover/popover.rb +1 -1
  98. data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +0 -1
  99. data/app/pb_kits/playbook/pb_time/_time.tsx +2 -2
  100. data/app/pb_kits/playbook/pb_timestamp/_timestamp.jsx +5 -2
  101. data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_elapsed.html.erb +9 -0
  102. data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_elapsed.jsx +10 -0
  103. data/app/pb_kits/playbook/pb_timestamp/timestamp.rb +4 -1
  104. data/app/pb_kits/playbook/pb_timestamp/timestamp.test.js +164 -0
  105. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +0 -4
  106. data/app/pb_kits/playbook/pb_tooltip/tooltip.test.jsx +11 -8
  107. data/app/pb_kits/playbook/tokens/_colors.scss +74 -74
  108. data/app/pb_kits/playbook/tokens/_typography.scss +8 -8
  109. data/app/pb_kits/playbook/utilities/_flexbox.scss +11 -11
  110. data/app/pb_kits/playbook/utilities/{_align_content.scss → flexbox_global_props/_align_content.scss} +0 -0
  111. data/app/pb_kits/playbook/utilities/{_align_items.scss → flexbox_global_props/_align_items.scss} +0 -0
  112. data/app/pb_kits/playbook/utilities/{_align_self.scss → flexbox_global_props/_align_self.scss} +0 -0
  113. data/app/pb_kits/playbook/utilities/{_flex.scss → flexbox_global_props/_flex.scss} +0 -0
  114. data/app/pb_kits/playbook/utilities/{_flex_direction.scss → flexbox_global_props/_flex_direction.scss} +0 -0
  115. data/app/pb_kits/playbook/utilities/{_flex_grow.scss → flexbox_global_props/_flex_grow.scss} +0 -0
  116. data/app/pb_kits/playbook/utilities/{_flex_shrink.scss → flexbox_global_props/_flex_shrink.scss} +0 -0
  117. data/app/pb_kits/playbook/utilities/{_flex_wrap.scss → flexbox_global_props/_flex_wrap.scss} +0 -0
  118. data/app/pb_kits/playbook/utilities/{_justify_content.scss → flexbox_global_props/_justify_content.scss} +0 -0
  119. data/app/pb_kits/playbook/utilities/{_justify_self.scss → flexbox_global_props/_justify_self.scss} +0 -0
  120. data/app/pb_kits/playbook/utilities/{_order.scss → flexbox_global_props/_order.scss} +0 -0
  121. data/app/pb_kits/playbook/utilities/props.ts +1 -1
  122. data/app/pb_kits/playbook/utilities/test-utils.js +2 -3
  123. data/app/pb_kits/playbook/utilities/text.ts +1 -1
  124. data/lib/playbook/version.rb +2 -2
  125. metadata +56 -25
  126. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.jsx +0 -155
  127. data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.jsx +0 -124
  128. data/app/pb_kits/playbook/pb_label_value/_label_value.jsx +0 -155
@@ -0,0 +1,77 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import IconValue from './_icon_value'
5
+
6
+ const testId = "iconvalue-kit";
7
+
8
+ describe("IconValue Kit", () => {
9
+ test("renders IconValue classname", () => {
10
+ render(
11
+ <IconValue
12
+ data={{ testid: testId }}
13
+ icon="clipboard"
14
+ text="33-123456"
15
+ />
16
+ )
17
+
18
+ const kit = screen.getByTestId(testId)
19
+ expect(kit).toHaveClass("pb_icon_value_kit_left")
20
+ })
21
+
22
+ test("renders icon", () => {
23
+ render(
24
+ <IconValue
25
+ data={{ testid: testId }}
26
+ icon="clipboard"
27
+ text="33-123456"
28
+ />
29
+ )
30
+
31
+ const kit = screen.getByTestId(testId)
32
+ const icon = kit.querySelector(".fa-clipboard.pb_icon_kit.fa-fw")
33
+ expect(icon).toBeInTheDocument()
34
+ })
35
+
36
+ test("renders value", () => {
37
+ render(
38
+ <IconValue
39
+ data={{ testid: testId }}
40
+ icon="clipboard"
41
+ text="33-123456"
42
+ />
43
+ )
44
+
45
+ const kit = screen.getByTestId(testId)
46
+ const value = kit.querySelector(".pb_body_kit_light")
47
+ expect(value.textContent).toEqual("33-123456")
48
+ })
49
+
50
+ test("aligns content center", () => {
51
+ render(
52
+ <IconValue
53
+ align="center"
54
+ data={{ testid: testId }}
55
+ icon="clipboard"
56
+ text="33-123456"
57
+ />
58
+ )
59
+
60
+ const kit = screen.getByTestId(testId)
61
+ expect(kit).toHaveClass("pb_icon_value_kit_center")
62
+ })
63
+
64
+ test("aligns content right", () => {
65
+ render(
66
+ <IconValue
67
+ align="right"
68
+ data={{ testid: testId }}
69
+ icon="clipboard"
70
+ text="33-123456"
71
+ />
72
+ )
73
+
74
+ const kit = screen.getByTestId(testId)
75
+ expect(kit).toHaveClass("pb_icon_value_kit_right")
76
+ })
77
+ })
@@ -0,0 +1,123 @@
1
+ import React from "react";
2
+ import classnames from "classnames";
3
+ import DateTime from "../pb_kit/dateTime";
4
+ import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
5
+ import { globalProps } from "../utilities/globalProps";
6
+
7
+ import Body from "../pb_body/_body";
8
+ import Caption from "../pb_caption/_caption";
9
+ import Flex from "../pb_flex/_flex";
10
+ import Icon from "../pb_icon/_icon";
11
+ import Title from "../pb_title/_title";
12
+
13
+ type LabelValueProps = {
14
+ active?: boolean;
15
+ aria?: { [key: string]: string };
16
+ className?: string;
17
+ dark?: boolean;
18
+ data?: object;
19
+ date?: Date;
20
+ id?: string;
21
+ label: string;
22
+ value?: string;
23
+ variant?: "default" | "details";
24
+ icon?: string;
25
+ description?: string;
26
+ title?: string;
27
+ };
28
+
29
+ const dateString = (value: DateTime) => {
30
+ const month = value.toMonthNum();
31
+ const day = value.toDay();
32
+
33
+ return ` · ${month}/${day}`;
34
+ };
35
+
36
+ const LabelValue = (props: LabelValueProps) => {
37
+ const {
38
+ active = false,
39
+ aria = {},
40
+ className,
41
+ dark = false,
42
+ data = {},
43
+ date,
44
+ description,
45
+ icon,
46
+ id,
47
+ label,
48
+ title,
49
+ value,
50
+ variant = "default",
51
+ } = props;
52
+
53
+ const ariaProps = buildAriaProps(aria);
54
+ const dataProps = buildDataProps(data);
55
+ const formattedDate = new DateTime({ value: date });
56
+ const variantClass = variant === "details" ? "details" : "";
57
+ const classes = classnames(
58
+ buildCss("pb_label_value_kit", variantClass),
59
+ globalProps(props),
60
+ className
61
+ );
62
+
63
+ return (
64
+ <div
65
+ {...ariaProps}
66
+ {...dataProps}
67
+ className={classes}
68
+ id={id}
69
+ title={title}
70
+ >
71
+ <Caption dark={dark} text={label} />
72
+ {variant === "details" ? (
73
+ <Flex inline vertical="center">
74
+ {icon && (
75
+ <Body color="light" dark={dark} marginRight="xs">
76
+ <Icon dark={dark} fixedWidth icon={icon} />
77
+ </Body>
78
+ )}
79
+ {description && (
80
+ <Body
81
+ color="light"
82
+ dark={dark}
83
+ marginRight="xs"
84
+ text={description}
85
+ />
86
+ )}
87
+ {active === true ? (
88
+ <Flex inline vertical="center">
89
+ {title && (
90
+ <Title dark={dark} size={4} text={title} variant="link" />
91
+ )}
92
+ {date && (
93
+ <Title
94
+ dark={dark}
95
+ marginLeft="xs"
96
+ size={4}
97
+ text={" " + dateString(formattedDate)}
98
+ variant="link"
99
+ />
100
+ )}
101
+ </Flex>
102
+ ) : (
103
+ <>
104
+ {title && <Title dark={dark} size={4} text={title} />}
105
+ {date && (
106
+ <Title
107
+ dark={dark}
108
+ marginLeft="xs"
109
+ size={4}
110
+ text={" " + dateString(formattedDate)}
111
+ />
112
+ )}
113
+ </>
114
+ )}
115
+ </Flex>
116
+ ) : (
117
+ <Body dark={dark} text={value} />
118
+ )}
119
+ </div>
120
+ );
121
+ };
122
+
123
+ export default LabelValue;
@@ -0,0 +1,109 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import LabelValue from './_label_value'
5
+
6
+ const testId = "labelvalue-kit";
7
+ jest.useFakeTimers()
8
+
9
+ describe("LabelValue Kit", () => {
10
+ test("renders LabelValue classname", () => {
11
+ render(
12
+ <LabelValue
13
+ data={{ testid: testId }}
14
+ label="Role"
15
+ value="Administrator, Moderator"
16
+ />
17
+ )
18
+ const kit = screen.getByTestId(testId)
19
+ expect(kit).toHaveClass("pb_label_value_kit")
20
+ })
21
+
22
+ test("renders label correctly", () => {
23
+ render(
24
+ <LabelValue
25
+ data={{ testid: testId }}
26
+ label="Role"
27
+ value="Administrator, Moderator"
28
+ />
29
+ )
30
+ const kit = screen.getByTestId(testId)
31
+ const text = kit.querySelector(".pb_caption_kit_md")
32
+ expect(text.textContent).toEqual("Role")
33
+ })
34
+
35
+ test("renders value correctly", () => {
36
+ render(
37
+ <LabelValue
38
+ data={{ testid: testId }}
39
+ label="Role"
40
+ value="Administrator, Moderator"
41
+ />
42
+ )
43
+ const kit = screen.getByTestId(testId)
44
+ const text = kit.querySelector(".pb_body_kit")
45
+ expect(text.textContent).toEqual("Administrator, Moderator")
46
+ })
47
+
48
+ test("renders icon if included with details variant", () => {
49
+ render(
50
+ <LabelValue
51
+ data={{ testid: testId }}
52
+ icon="truck"
53
+ label="Installer"
54
+ title="JD Installations LLC"
55
+ variant="details"
56
+ />
57
+ )
58
+ const kit = screen.getByTestId(testId)
59
+ const icon = kit.querySelector(".fa-truck.pb_icon_kit.fa-fw")
60
+ expect(icon).toBeInTheDocument()
61
+ })
62
+
63
+ test("renders title if included with details variant", () => {
64
+ render(
65
+ <LabelValue
66
+ data={{ testid: testId }}
67
+ icon="truck"
68
+ label="Installer"
69
+ title="JD Installations LLC"
70
+ variant="details"
71
+ />
72
+ )
73
+ const kit = screen.getByTestId(testId)
74
+ const text = kit.querySelector(".pb_title_kit_size_4")
75
+ expect(text.textContent).toEqual("JD Installations LLC")
76
+ })
77
+
78
+ test("renders date if included with details variant", () => {
79
+ render(
80
+ <LabelValue
81
+ data={{ testid: testId }}
82
+ date={new Date('18 Nov 2019')}
83
+ description="33-12345"
84
+ icon="home"
85
+ label="Project"
86
+ title="Jefferson-Smith"
87
+ variant="details"
88
+ />
89
+ )
90
+ const text = screen.getByText("11/18", {exact: false})
91
+ expect(text).toBeInTheDocument()
92
+ })
93
+
94
+ test("renders title if included with details variant", () => {
95
+ render(
96
+ <LabelValue
97
+ active
98
+ data={{ testid: testId }}
99
+ icon="truck"
100
+ label="Installer"
101
+ title="JD Installations LLC"
102
+ variant="details"
103
+ />
104
+ )
105
+ const kit = screen.getByTestId(testId)
106
+ const activeProp = kit.querySelector(".pb_title_kit_size_4_link")
107
+ expect(activeProp).toBeInTheDocument()
108
+ })
109
+ })
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import classnames from 'classnames'
5
3
  import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
@@ -7,8 +5,8 @@ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
7
5
  import { globalProps } from '../utilities/globalProps'
8
6
 
9
7
  type LayoutPropTypes = {
10
- aria?: object,
11
- children?: array<React.ReactNode> | React.ReactNode,
8
+ aria?: {[key: string]: string},
9
+ children?: React.ReactChild[] | React.ReactChild,
12
10
  className?: string,
13
11
  collapse?: "xs" | "sm" | "md" | "lg" | "xl",
14
12
  dark?: boolean,
@@ -23,28 +21,28 @@ type LayoutPropTypes = {
23
21
  }
24
22
 
25
23
  type LayoutSideProps = {
26
- children: array<React.ReactNode> | React.ReactNode,
24
+ children: React.ReactNode[] | React.ReactNode,
27
25
  className?: string,
28
26
  }
29
27
 
30
28
  type LayoutBodyProps = {
31
- children: array<React.ReactNode> | React.ReactNode,
29
+ children: React.ReactNode[] | React.ReactNode,
32
30
  className?: string,
33
31
  }
34
32
 
35
33
  type LayoutItemProps = {
36
- children: array<React.ReactNode> | React.ReactNode,
34
+ children: React.ReactNode[] | React.ReactNode,
37
35
  className?: string,
38
36
  size?: "sm" | "md" | "lg"
39
37
  }
40
38
 
41
39
  type LayoutHeaderProps = {
42
- children: array<React.ReactNode> | React.ReactNode,
40
+ children: React.ReactNode[] | React.ReactNode,
43
41
  className?: string,
44
42
  }
45
43
 
46
44
  type LayoutFooterProps = {
47
- children: array<React.ReactNode> | React.ReactNode,
45
+ children: React.ReactNode[] | React.ReactNode,
48
46
  className?: string,
49
47
  }
50
48
 
@@ -99,8 +97,6 @@ const Footer = (props: LayoutFooterProps) => {
99
97
  )
100
98
  }
101
99
 
102
- // Main componenet
103
-
104
100
  const Layout = (props: LayoutPropTypes) => {
105
101
  const {
106
102
  aria = {},
@@ -138,25 +134,23 @@ const Layout = (props: LayoutPropTypes) => {
138
134
  ? ''
139
135
  : buildCss('layout', position, 'collapse', collapse)
140
136
 
141
- const layoutChildren =
142
- typeof children === 'object' && children.length ? children : [children]
137
+ const layoutChildren = React.Children.toArray(children)
143
138
 
144
- const subComponentTags = (tagName) => {
139
+ const subComponentTags = (tagName: string) => {
145
140
  return layoutChildren
146
- .filter((c) => {
147
- return c.type && c.type.displayName === tagName
141
+ .filter((c: React.ReactElement & {type: {displayName: string}}) => {
142
+ return c.type?.displayName === tagName
148
143
  })
149
144
  .map((child, i) => {
150
- return React.cloneElement(child, {
145
+ return React.cloneElement(child as React.ReactElement, {
151
146
  key: `${tagName.toLowerCase()}-${i}`,
152
147
  })
153
148
  })
154
149
  }
155
150
 
156
151
  const nonSideChildren = layoutChildren.filter(
157
- (child) => !child.type || child.type.displayName !== 'Side'
152
+ (child: React.ReactElement & {type: {displayName: string}}) => child.type?.displayName !== 'Side'
158
153
  )
159
-
160
154
  return (
161
155
  <div
162
156
  {...ariaProps}
@@ -0,0 +1,97 @@
1
+ import React from "react"
2
+ import { render, cleanup } from "../utilities/test-utils"
3
+ import { Layout, Card } from ".."
4
+
5
+ function LayoutTest(props) {
6
+ return (
7
+ <Layout {...props}>
8
+ <Layout.Side>{"Light"}</Layout.Side>
9
+ <Layout.Body>{"Body"}</Layout.Body>
10
+ </Layout>
11
+ )
12
+ }
13
+
14
+ test("render all color variants", () => {
15
+ const testValues = [undefined, "light", "dark", "gradient"]
16
+ testValues.forEach((variant) => {
17
+ const { getByTestId } = render(
18
+ <LayoutTest data={{ testid: `test-${variant}` }}
19
+ variant={variant} />
20
+ )
21
+ expect(getByTestId(`test-${variant}`)).toHaveClass(
22
+ `pb_layout_kit_sidebar_size_md_left_${
23
+ variant == undefined ? "light" : variant
24
+ }`
25
+ )
26
+
27
+ cleanup()
28
+ })
29
+ })
30
+
31
+ test("render transparent class", () => {
32
+ const id = "transparent"
33
+
34
+ const { getByTestId } = render(
35
+ <LayoutTest data={{ testid: `test-${id}` }}
36
+ variant={id} />
37
+ )
38
+ expect(getByTestId(`test-${id}`)).toHaveClass(
39
+ `pb_layout_kit_sidebar_size_md_left_${id}`
40
+ )
41
+
42
+ cleanup()
43
+ })
44
+
45
+ test("render all sizes variants", () => {
46
+ const testValues = ["xs", "sm", "md", "lg", "xl"]
47
+ testValues.forEach((size) => {
48
+ const { getByTestId } = render(
49
+ <LayoutTest data={{ testid: `test-${size}` }}
50
+ size={size} />
51
+ )
52
+ expect(getByTestId(`test-${size}`)).toHaveClass(
53
+ `pb_layout_kit_sidebar_size_${size}_left_light`
54
+ )
55
+
56
+ cleanup()
57
+ })
58
+ })
59
+
60
+ test("render all layout variants", () => {
61
+ const testValues = [
62
+ {
63
+ layout: "collection",
64
+ expected: "pb_layout_kit_collection",
65
+ },
66
+ {
67
+ layout: "collection_detail",
68
+ expected: "pb_layout_kit_collection_detail_size_md_left_light",
69
+ },
70
+ {
71
+ layout: "content",
72
+ expected: "pb_layout_kit_content_size_md_left_light",
73
+ },
74
+ {
75
+ layout: "kanban",
76
+ expected: "pb_layout_kit_kanban",
77
+ },
78
+ {
79
+ layout: "masonry",
80
+ expected: "pb_layout_kit_masonry_size_md_left_light",
81
+ },
82
+ ]
83
+
84
+ testValues.forEach(({ layout, expected }) => {
85
+ const { getByTestId } = render(
86
+ <Layout data={{ testid: `test-${layout}` }}
87
+ layout={layout}>
88
+ <Layout.Body>
89
+ <Card>{"Card content"}</Card>
90
+ </Layout.Body>
91
+ </Layout>
92
+ )
93
+
94
+ expect(getByTestId(`test-${layout}`)).toHaveClass(expected)
95
+ cleanup()
96
+ })
97
+ })
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import { fireEvent, render, screen, waitForElementToBeRemoved } from '../utilities/test-utils'
2
+ import { cleanup, fireEvent, render, screen } from '../utilities/test-utils'
3
3
 
4
4
  import { Lightbox } from '../'
5
5
 
@@ -27,6 +27,7 @@ test('Kit renders', () => {
27
27
  const kit = screen.getByTestId(testId)
28
28
  expect(kit).toHaveClass(`${kitClass} customClass`)
29
29
  expect(kit).toBeInTheDocument()
30
+ cleanup()
30
31
  })
31
32
 
32
33
  test('Shows selected images', () => {
@@ -67,9 +68,12 @@ test('Shows selected images', () => {
67
68
  )
68
69
 
69
70
  expect(image).toHaveAttribute('src', TEST_PHOTOS[0])
71
+ cleanup()
70
72
  })
71
73
 
72
74
  test('Closes on escape key', async () => {
75
+ const mockClose = jest.fn()
76
+
73
77
  render(
74
78
  <Lightbox
75
79
  data={{ testid: testId }}
@@ -77,25 +81,29 @@ test('Closes on escape key', async () => {
77
81
  iconSize="3x"
78
82
  id="test1"
79
83
  initialPhoto={0}
80
- onClose={() => {}}
84
+ onClose={mockClose}
81
85
  photos={TEST_PHOTOS}
82
86
  />
83
87
  )
84
88
 
85
- const kit = screen.getByTestId(testId)
86
-
87
- fireEvent(
88
- document.body,
89
- new KeyboardEvent('keydown', {
90
- keyCode: 27, //escape
91
- })
89
+ fireEvent.keyDown(
90
+ global.window,
91
+ {
92
+ bubbles: true,
93
+ key: "Escape",
94
+ code: "Escape",
95
+ keyCode: 27,
96
+ charCode: 27
97
+ }
92
98
  )
93
99
 
94
- waitForElementToBeRemoved(kit)
95
- .then(() => expect(kit).not.toBeInTheDocument())
100
+ expect(mockClose).toHaveBeenCalled()
101
+ cleanup()
96
102
  })
97
103
 
98
- test('Closes on close button', () => {
104
+ test('Closes on close button', async () => {
105
+ const mockClose = jest.fn()
106
+
99
107
  render(
100
108
  <Lightbox
101
109
  data={{ testid: testId }}
@@ -103,7 +111,7 @@ test('Closes on close button', () => {
103
111
  iconSize="3x"
104
112
  id="test1"
105
113
  initialPhoto={0}
106
- onClose={() => {}}
114
+ onClose={mockClose}
107
115
  photos={TEST_PHOTOS}
108
116
  />
109
117
  )
@@ -119,6 +127,6 @@ test('Closes on close button', () => {
119
127
  }),
120
128
  )
121
129
 
122
- waitForElementToBeRemoved(kit)
123
- .then(() => expect(kit).not.toBeInTheDocument())
130
+ expect(mockClose).toHaveBeenCalled()
131
+ cleanup()
124
132
  })
@@ -4,7 +4,7 @@ module Playbook
4
4
  module PbPopover
5
5
  class Popover < Playbook::KitBase
6
6
  prop :position, type: Playbook::Props::Enum,
7
- values: %w[top bottom left right],
7
+ values: %w[top bottom left right top-start top-end bottom-start bottom-end right-start right-end left-start left-end],
8
8
  default: "left"
9
9
  prop :trigger_element_id
10
10
  prop :tooltip_id
@@ -103,7 +103,6 @@ const TextInput = (props: TextInputProps, ref: React.LegacyRef<HTMLInputElement>
103
103
  <React.Fragment>
104
104
  <Flex
105
105
  className={`add-on-${addOnAlignment} ${borderCss}`}
106
- inline
107
106
  vertical="center"
108
107
  >
109
108
  {addOnAlignment == 'left' && <>
@@ -3,7 +3,7 @@ import classnames from "classnames";
3
3
 
4
4
  import DateTime from "../pb_kit/dateTime";
5
5
  import { buildCss } from "../utilities/props";
6
- import { globalProps } from "../utilities/globalProps";
6
+ import { globalProps, GlobalProps } from "../utilities/globalProps";
7
7
 
8
8
  import Body from "../pb_body/_body";
9
9
  import Caption from "../pb_caption/_caption";
@@ -20,7 +20,7 @@ type TimeProps = {
20
20
  size?: "md" | "sm";
21
21
  showTimezone?: boolean;
22
22
  timeZone?: string;
23
- };
23
+ } & GlobalProps
24
24
 
25
25
  const Time = (props: TimeProps) => {
26
26
  const {
@@ -21,6 +21,7 @@ type TimestampProps = {
21
21
  id?: string,
22
22
  showDate?: boolean,
23
23
  showUser?: boolean,
24
+ hideUpdated?: boolean,
24
25
  showTimezone?: boolean,
25
26
  variant?: "default" | "elapsed" | "updated"
26
27
  }
@@ -37,6 +38,7 @@ const Timestamp = (props: TimestampProps) => {
37
38
  timezone,
38
39
  showDate = true,
39
40
  showUser = false,
41
+ hideUpdated = false,
40
42
  showTimezone = false,
41
43
  variant = 'default',
42
44
  } = props
@@ -57,6 +59,7 @@ const Timestamp = (props: TimestampProps) => {
57
59
  const dateDisplay = `${dateTimestamp.toMonth()} ${dateTimestamp.toDay()}`
58
60
  const shouldShowUser = showUser == true && text.length > 0
59
61
  const shouldShowTimezone = showTimezone == true && timezone.length > 0
62
+ const updatedText = hideUpdated ? "" : "Last updated"
60
63
  const userDisplay = shouldShowUser ? ` by ${text}` : ''
61
64
 
62
65
  let timeDisplay = `${dateTimestamp.toHour()}:${dateTimestamp.toMinute()}${dateTimestamp.toMeridian()}`
@@ -81,7 +84,7 @@ const Timestamp = (props: TimestampProps) => {
81
84
  }
82
85
 
83
86
  const formatElapsedString = () => {
84
- return `Last updated ${userDisplay} ${dateTimestamp.value.fromNow()}`
87
+ return `${updatedText} ${userDisplay} ${dateTimestamp.value.fromNow()}`
85
88
  }
86
89
 
87
90
  const captionText = () => {
@@ -89,7 +92,7 @@ const Timestamp = (props: TimestampProps) => {
89
92
  case 'updated':
90
93
  return formatUpdatedString(userDisplay, dateTimestamp)
91
94
  case 'elapsed':
92
- return formatElapsedString(userDisplay, timeDisplay)
95
+ return formatElapsedString(userDisplay, timeDisplay, updatedText)
93
96
  default:
94
97
  return showDate ? timestamp ? fullDateDisplay() : text : fullTimeDisplay()
95
98
  }
@@ -12,3 +12,12 @@
12
12
  variant: "elapsed",
13
13
  show_user: false
14
14
  }) %>
15
+
16
+ <br>
17
+
18
+ <%= pb_rails("timestamp", props: {
19
+ timestamp: DateTime.now,
20
+ variant: "elapsed",
21
+ show_user: false,
22
+ hide_updated: true
23
+ }) %>
@@ -28,6 +28,16 @@ const TimestampElapsed = (props) => {
28
28
  variant="elapsed"
29
29
  {...props}
30
30
  />
31
+
32
+ <br />
33
+
34
+ <Timestamp
35
+ hideUpdated
36
+ showUser={false}
37
+ timestamp={customDate}
38
+ variant="elapsed"
39
+ {...props}
40
+ />
31
41
  </div>
32
42
  )
33
43
  }