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

Sign up to get free protection for your applications and to get access to all the features.
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