playbook_ui 11.4.0.pre.alpha.rubytheme2 → 11.5.0.pre.alpha.pre.rubocop

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_button/button.test.js +6 -8
  3. data/app/pb_kits/playbook/pb_date_picker/_date_picker.jsx +13 -1
  4. data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +24 -19
  5. data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +1 -1
  6. data/app/pb_kits/playbook/pb_date_picker/date_picker.rb +8 -0
  7. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.js +25 -3
  8. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.html.erb +44 -0
  9. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.jsx +60 -0
  10. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions.md +9 -0
  11. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions_element.html.erb +33 -0
  12. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_positions_element.jsx +67 -0
  13. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +4 -0
  14. data/app/pb_kits/playbook/pb_date_picker/docs/index.js +2 -0
  15. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_overrides.scss +4 -4
  16. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.tsx +142 -0
  17. data/app/pb_kits/playbook/pb_date_range_inline/date_range_inline.test.js +116 -0
  18. data/app/pb_kits/playbook/pb_date_range_inline/docs/_date_range_inline_default.jsx +1 -1
  19. data/app/pb_kits/playbook/pb_date_year_stacked/{_date_year_stacked.jsx → _date_year_stacked.tsx} +6 -6
  20. data/app/pb_kits/playbook/pb_date_year_stacked/date_year_stacked.test.js +67 -0
  21. data/app/pb_kits/playbook/pb_file_upload/{_file_upload.jsx → _file_upload.tsx} +6 -10
  22. data/app/pb_kits/playbook/pb_form_group/{_form_group.jsx → _form_group.tsx} +1 -4
  23. data/app/pb_kits/playbook/pb_form_group/form_group.test.js +17 -0
  24. data/app/pb_kits/playbook/pb_layout/{_layout.jsx → _layout.tsx} +13 -19
  25. data/app/pb_kits/playbook/pb_layout/layout.test.js +98 -0
  26. data/app/pb_kits/playbook/pb_lightbox/lightbox.test.jsx +23 -15
  27. data/app/pb_kits/playbook/pb_timestamp/_timestamp.jsx +5 -2
  28. data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_elapsed.html.erb +9 -0
  29. data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_elapsed.jsx +10 -0
  30. data/app/pb_kits/playbook/pb_timestamp/timestamp.rb +4 -1
  31. data/app/pb_kits/playbook/pb_timestamp/timestamp.test.js +164 -0
  32. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +0 -4
  33. data/app/pb_kits/playbook/pb_tooltip/tooltip.test.jsx +11 -8
  34. data/app/pb_kits/playbook/utilities/_flexbox.scss +11 -11
  35. data/app/pb_kits/playbook/utilities/{_align_content.scss → flexbox_global_props/_align_content.scss} +0 -0
  36. data/app/pb_kits/playbook/utilities/{_align_items.scss → flexbox_global_props/_align_items.scss} +0 -0
  37. data/app/pb_kits/playbook/utilities/{_align_self.scss → flexbox_global_props/_align_self.scss} +0 -0
  38. data/app/pb_kits/playbook/utilities/{_flex.scss → flexbox_global_props/_flex.scss} +0 -0
  39. data/app/pb_kits/playbook/utilities/{_flex_direction.scss → flexbox_global_props/_flex_direction.scss} +0 -0
  40. data/app/pb_kits/playbook/utilities/{_flex_grow.scss → flexbox_global_props/_flex_grow.scss} +0 -0
  41. data/app/pb_kits/playbook/utilities/{_flex_shrink.scss → flexbox_global_props/_flex_shrink.scss} +0 -0
  42. data/app/pb_kits/playbook/utilities/{_flex_wrap.scss → flexbox_global_props/_flex_wrap.scss} +0 -0
  43. data/app/pb_kits/playbook/utilities/{_justify_content.scss → flexbox_global_props/_justify_content.scss} +0 -0
  44. data/app/pb_kits/playbook/utilities/{_justify_self.scss → flexbox_global_props/_justify_self.scss} +0 -0
  45. data/app/pb_kits/playbook/utilities/{_order.scss → flexbox_global_props/_order.scss} +0 -0
  46. data/app/pb_kits/playbook/utilities/props.ts +1 -1
  47. data/app/pb_kits/playbook/utilities/test-utils.js +2 -3
  48. data/lib/playbook/version.rb +2 -2
  49. metadata +29 -19
  50. data/app/pb_kits/playbook/pb_date_range_inline/_date_range_inline.jsx +0 -155
@@ -0,0 +1,116 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import DateRangeInline from './_date_range_inline'
5
+
6
+ jest.useFakeTimers()
7
+ const testId = "daterangeinline-kit";
8
+
9
+ describe("DateRangeInline Kit", () => {
10
+ test("renders DateRangeInline className", () => {
11
+ render(
12
+ <DateRangeInline
13
+ data={{ testid: testId }}
14
+ endDate={new Date('20 Mar 2015')}
15
+ size="xs"
16
+ startDate={new Date('18 Jun 2013')}
17
+ />
18
+ )
19
+
20
+ const kit = screen.getByTestId(testId)
21
+ expect(kit).toHaveClass("pb_date_range_inline_kit_left")
22
+ })
23
+
24
+ test("renders DateRangeInline text left", () => {
25
+ render(
26
+ <DateRangeInline
27
+ data={{ testid: testId }}
28
+ endDate={new Date('20 Mar 2015')}
29
+ size="xs"
30
+ startDate={new Date('18 Jun 2013')}
31
+ />
32
+ )
33
+
34
+ const kit = screen.getByTestId(testId)
35
+ const text = kit.querySelector('.pb_caption_kit_md:first-child')
36
+ expect(text.textContent).toEqual(" Jun 18, 2013 ")
37
+ })
38
+
39
+ test("renders DateRangeInline text right", () => {
40
+ render(
41
+ <DateRangeInline
42
+ data={{ testid: testId }}
43
+ endDate={new Date('20 Mar 2015')}
44
+ size="xs"
45
+ startDate={new Date('18 Jun 2013')}
46
+ />
47
+ )
48
+
49
+ const kit = screen.getByTestId(testId)
50
+ const text = kit.querySelector('.pb_caption_kit_md:last-child')
51
+ expect(text.textContent).toEqual(" Mar 20, 2015 ")
52
+ })
53
+
54
+ test("renders DateRangeInline arrow icon center", () => {
55
+ render(
56
+ <DateRangeInline
57
+ data={{ testid: testId }}
58
+ endDate={new Date('20 Mar 2015')}
59
+ size="xs"
60
+ startDate={new Date('18 Jun 2013')}
61
+ />
62
+ )
63
+
64
+ const kit = screen.getByTestId(testId)
65
+ const arrow = kit.querySelector('.pb_icon_kit.fa-fw.fa-long-arrow-right')
66
+ expect(arrow).toBeInTheDocument()
67
+ })
68
+
69
+ test("renders DateRangeInline className if size sm", () => {
70
+ render(
71
+ <DateRangeInline
72
+ data={{ testid: testId }}
73
+ endDate={new Date('20 Mar 2015')}
74
+ size="sm"
75
+ startDate={new Date('18 Jun 2013')}
76
+ />
77
+ )
78
+
79
+ const kit = screen.getByTestId(testId)
80
+ const innerKit = kit.querySelector('.pb_body_kit')
81
+ expect(innerKit).toBeInTheDocument()
82
+ })
83
+
84
+ test("renders DateRangeInline calender icon left", () => {
85
+ render(
86
+ <DateRangeInline
87
+ data={{ testid: testId }}
88
+ endDate={new Date('20 Mar 2015')}
89
+ icon
90
+ size="xs"
91
+ startDate={new Date('18 Jun 2013')}
92
+ />
93
+ )
94
+
95
+ const kit = screen.getByTestId(testId)
96
+ const calendar = kit.querySelector('.pb_icon_kit.fa-fw.fa-calendar-alt')
97
+ expect(calendar).toBeInTheDocument()
98
+ })
99
+
100
+ test("renders DateRangeInline without year", () => {
101
+ render(
102
+ <DateRangeInline
103
+ data={{ testid: testId }}
104
+ endDate={new Date((`15 Aug ${new Date().getFullYear()}`))}
105
+ size="xs"
106
+ startDate={new Date(`15 Jan ${new Date().getFullYear()}`)}
107
+ />
108
+ )
109
+
110
+ const kit = screen.getByTestId(testId)
111
+ const text = kit.querySelector('.pb_caption_kit_md:first-child')
112
+ expect(text.textContent).toEqual(" Jan 15 ")
113
+ })
114
+
115
+
116
+ })
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import DateRangeInline from '../_date_range_inline.jsx'
2
+ import DateRangeInline from '../_date_range_inline'
3
3
 
4
4
  const DateRangeInlineDefault = (props) => {
5
5
  return (
@@ -1,10 +1,8 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import classnames from 'classnames'
5
3
 
6
4
  import DateTime from '../pb_kit/dateTime'
7
- import { buildCss } from '../utilities/props'
5
+ import { buildCss, buildDataProps } from '../utilities/props'
8
6
  import { globalProps } from '../utilities/globalProps'
9
7
 
10
8
  import Body from '../pb_body/_body'
@@ -12,7 +10,7 @@ import Title from '../pb_title/_title'
12
10
 
13
11
  type DateYearStackedProps = {
14
12
  align?: "left" | "center" | "right",
15
- className?: string | array<string>,
13
+ className?: string | string[],
16
14
  dark?: boolean,
17
15
  data?: string,
18
16
  date: string,
@@ -20,16 +18,18 @@ type DateYearStackedProps = {
20
18
  }
21
19
 
22
20
  const DateYearStacked = (props: DateYearStackedProps) => {
23
- const { align = 'left', className, dark = false, date } = props
21
+ const { align = 'left', className, dark = false, date, data={} } = props
24
22
  const dateTimestamp = new DateTime({ value: date })
25
23
  const css = classnames(
26
24
  buildCss('pb_date_year_stacked', align),
27
25
  globalProps(props),
28
26
  className
29
27
  )
28
+ const dataProps = buildDataProps(data)
30
29
 
31
30
  return (
32
- <div className={css}>
31
+ <div {...dataProps}
32
+ className={css}>
33
33
  <Title
34
34
  dark={dark}
35
35
  size={4}
@@ -0,0 +1,67 @@
1
+ import React from "react";
2
+ import { render, screen } from "../utilities/test-utils";
3
+
4
+ import DateYearStacked from "./_date_year_stacked";
5
+
6
+ const TEST_DATE = "01/01/2020 00:00:000 GMT-0500";
7
+ jest.setSystemTime(new Date(TEST_DATE));
8
+ const testId = "dateyearstacked-kit";
9
+ const realDate = Date;
10
+
11
+ beforeEach(() => {
12
+ global.Date.now = jest.fn(() => new Date(TEST_DATE));
13
+ });
14
+
15
+ afterEach(() => {
16
+ global.Date = realDate;
17
+ });
18
+
19
+ describe("DateYearStacked Kit", () => {
20
+ test("renders DateYearStacked className", () => {
21
+ render(
22
+ <DateYearStacked
23
+ data={{ testid: testId }}
24
+ date={new Date(Date.now())} />
25
+ );
26
+
27
+ const kit = screen.getByTestId(testId);
28
+ expect(kit).toHaveClass("pb_date_year_stacked_left");
29
+ });
30
+
31
+ test("renders DateYearStacked text top", () => {
32
+ render(
33
+ <DateYearStacked
34
+ data={{ testid: testId }}
35
+ date={new Date(Date.now())} />
36
+ );
37
+
38
+ const kit = screen.getByTestId(testId);
39
+ const text = kit.querySelector(".pb_title_kit_size_4");
40
+ expect(text.textContent).toEqual("1 JAN");
41
+ });
42
+
43
+ test("renders DateYearStacked text bottom", () => {
44
+ render(
45
+ <DateYearStacked
46
+ data={{ testid: testId }}
47
+ date={new Date(Date.now())} />
48
+ );
49
+
50
+ const kit = screen.getByTestId(testId);
51
+ const text = kit.querySelector(".pb_body_kit_light");
52
+ expect(text.textContent).toEqual("2020");
53
+ });
54
+
55
+ test("renders align prop", () => {
56
+ render(
57
+ <DateYearStacked
58
+ align="center"
59
+ data={{ testid: testId }}
60
+ date={new Date(Date.now())}
61
+ />
62
+ );
63
+
64
+ const kit = screen.getByTestId(testId);
65
+ expect(kit).toHaveClass("pb_date_year_stacked_center");
66
+ });
67
+ });
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React, { useCallback } from 'react'
4
2
  import { useDropzone } from 'react-dropzone'
5
3
  import classnames from 'classnames'
@@ -12,11 +10,11 @@ import Body from '../pb_body/_body'
12
10
  import Card from '../pb_card/_card'
13
11
 
14
12
  type FileUploadProps = {
15
- accept?: array<string>,
13
+ accept?: string[],
16
14
  className?: string,
17
15
  data?: object,
18
16
  acceptedFilesDescription?: string,
19
- onFilesAccepted: Callback,
17
+ onFilesAccepted: Callback<File, File>,
20
18
  }
21
19
 
22
20
  const FileUpload = (props: FileUploadProps) => {
@@ -27,10 +25,8 @@ const FileUpload = (props: FileUploadProps) => {
27
25
  data = {},
28
26
  onFilesAccepted = noop,
29
27
  } = props
30
- const onDrop = useCallback((files) => {
31
- onFilesAccepted(files)
32
- })
33
28
 
29
+ const onDrop = useCallback((files) => onFilesAccepted(files), []);
34
30
  const { getRootProps, getInputProps, isDragActive } = useDropzone({
35
31
  accept,
36
32
  onDrop,
@@ -57,11 +53,11 @@ const FileUpload = (props: FileUploadProps) => {
57
53
  <Card>
58
54
  <input {...getInputProps()} />
59
55
  <Body color="light">
60
- <If condition={isDragActive}>
56
+ {isDragActive ?
61
57
  <p>{'Drop the files here ...'}</p>
62
- <Else />
58
+ :
63
59
  <p>{accept === null ? 'Choose a file or drag it here' : `Choose a file or drag it here. The accepted file types are: ${acceptedFilesDescription || acceptedFileTypes()}`}</p>
64
- </If>
60
+ }
65
61
  </Body>
66
62
  </Card>
67
63
  </div>
@@ -1,12 +1,10 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import classnames from 'classnames'
5
3
  import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
6
4
  import { globalProps } from '../utilities/globalProps'
7
5
 
8
6
  type FormGroupProps = {
9
- aria?: object,
7
+ aria?: {[key: string]: string},
10
8
  children?: Node,
11
9
  className?: string,
12
10
  data?: object,
@@ -27,7 +25,6 @@ const FormGroup = (props: FormGroupProps) => {
27
25
  const ariaProps = buildAriaProps(aria)
28
26
  const dataProps = buildDataProps(data)
29
27
  const classes = classnames(buildCss('pb_form_group_kit', { full: fullWidth }), globalProps(props), className)
30
-
31
28
  return (
32
29
  <div
33
30
  {...ariaProps}
@@ -0,0 +1,17 @@
1
+ import React from 'react'
2
+ import { render } from "../utilities/test-utils";
3
+
4
+ import { Button, FormGroup } from "..";
5
+
6
+ test("should render a div with a button child", () => {
7
+ const testId = "primary-test"
8
+ const { queryByTestId } = render(
9
+ <FormGroup>
10
+ <Button
11
+ data={{ testid: testId }}
12
+ text={"some text"} />
13
+ </FormGroup>
14
+ )
15
+
16
+ expect(queryByTestId("primary-test")).not.toBeNull;
17
+ })
@@ -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,98 @@
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, container } = 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
+ console.log(container)
94
+
95
+ expect(getByTestId(`test-${layout}`)).toHaveClass(expected)
96
+ cleanup()
97
+ })
98
+ })
@@ -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
  })
@@ -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
  }
@@ -12,6 +12,8 @@ module Playbook
12
12
  prop :align, type: Playbook::Props::Enum,
13
13
  values: %w[left center right],
14
14
  default: "left"
15
+ prop :hide_updated, type: Playbook::Props::Boolean,
16
+ default: false
15
17
  prop :show_date, type: Playbook::Props::Boolean,
16
18
  default: true
17
19
  prop :show_timezone, type: Playbook::Props::Boolean,
@@ -70,8 +72,9 @@ module Playbook
70
72
  def format_elapsed_string
71
73
  user_string = show_user ? " by #{text}" : ""
72
74
  datetime_string = " #{time_ago_in_words(pb_date_time.convert_to_timestamp)} ago"
75
+ updated_string = hide_updated ? "" : "Last updated"
73
76
 
74
- "Last updated#{user_string}#{datetime_string}"
77
+ "#{updated_string}#{user_string}#{datetime_string}"
75
78
  end
76
79
 
77
80
  def datetime_or_text