playbook_ui 12.10.0 → 12.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_avatar/_avatar.tsx +1 -1
  3. data/app/pb_kits/playbook/pb_button/_button.tsx +15 -3
  4. data/app/pb_kits/playbook/pb_button/button.rb +10 -1
  5. data/app/pb_kits/playbook/pb_button/button.test.js +92 -61
  6. data/app/pb_kits/playbook/pb_button/docs/_button_link.html.erb +3 -2
  7. data/app/pb_kits/playbook/pb_button/docs/_button_link.jsx +12 -2
  8. data/app/pb_kits/playbook/pb_button/docs/_button_link.md +1 -0
  9. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_day_styles.scss +1 -1
  10. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.tsx +13 -1
  11. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_auto_close.jsx +68 -0
  12. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_auto_close.md +1 -0
  13. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/example.yml +1 -0
  14. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/index.js +1 -0
  15. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.rb +6 -1
  16. data/app/pb_kits/playbook/pb_fixed_confirmation_toast/index.js +17 -0
  17. data/app/pb_kits/playbook/pb_rich_text_editor/{_rich_text_editor.jsx → _rich_text_editor.tsx} +40 -32
  18. data/app/pb_kits/playbook/pb_rich_text_editor/{inlineFocus.js → inlineFocus.ts} +1 -1
  19. data/app/pb_kits/playbook/pb_rich_text_editor/{useFocus.js → useFocus.ts} +1 -1
  20. data/app/pb_kits/playbook/pb_selectable_card/_selectable_card.tsx +1 -0
  21. data/app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.test.js +67 -0
  22. data/app/pb_kits/playbook/pb_selectable_card_icon/{_selectable_card_icon.jsx → _selectable_card_icon.tsx} +26 -28
  23. data/app/pb_kits/playbook/pb_source/{_source.jsx → _source.tsx} +33 -29
  24. data/app/pb_kits/playbook/pb_source/source.test.js +82 -0
  25. data/app/pb_kits/playbook/pb_tooltip/_tooltip.tsx +4 -1
  26. data/lib/playbook/version.rb +2 -2
  27. metadata +12 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9e1489462a3801b52dfe684f47a206bd828e7acef14d05c33d0f82fc2338cee
4
- data.tar.gz: 01d894ce63d37e36d7ba7cac5e6469c51f280b06d43a736046899300b3c6b230
3
+ metadata.gz: 53d5eae6427aba5ae9de4053e2069de8cf8a669c0f082c8a00066da74180be1d
4
+ data.tar.gz: 5d16ee2b64c60cbede34f42ad67e25a397f908c98f5a3fc1a3d3fa9edd1234a7
5
5
  SHA512:
6
- metadata.gz: 4ce7e5fa512dfe372904d822f263888f05557305935ff171c48582aa1d80a67ddbfb772a92598ecffce4d39a6399a6b34e27b754b4f11f46da116cb5db358030
7
- data.tar.gz: 47eccdf4be23394775ab3ebd74e0797d0b49290906dd0ae7da66d289b04702f374152cbc1180963ee5a0c9d8c31988d61a7421d00adeb34aa55ca1c150a81671
6
+ metadata.gz: 304866b64d95656b79835f2f7264f409b71a583ac6ac2e54870b6a19c3413815b162b39215eb849e92d9e045b4fc6f203b30ba065e82f4a60fd73befd7676244
7
+ data.tar.gz: 931c9aeeb4f9a0e317b3fe226ddcf3d1ec1b5ff52de4dcad9fb456e7a4c237f45f66b9b695adfdad63706f71519c40b14b4362fea2e83197f6c0737788375ee9
@@ -7,7 +7,7 @@ import { globalProps, GlobalProps } from '../utilities/globalProps'
7
7
  import Image from '../pb_image/_image'
8
8
  import OnlineStatus from '../pb_online_status/_online_status'
9
9
 
10
- type AvatarProps = {
10
+ export type AvatarProps = {
11
11
  aria?: {[key: string]: string},
12
12
  className?: string,
13
13
  data?: {[key: string]: string},
@@ -25,6 +25,7 @@ type ButtonPropTypes = {
25
25
  onClick?: EventHandler,
26
26
  tabIndex?: number,
27
27
  size?: 'sm' | 'md' | 'lg',
28
+ target?: string,
28
29
  text?: string,
29
30
  type?: 'inline' | null,
30
31
  htmlType?: 'submit' | 'reset' | 'button' | undefined,
@@ -70,6 +71,7 @@ const Button = (props: ButtonPropTypes) => {
70
71
  tabIndex,
71
72
  link = null,
72
73
  newWindow = false,
74
+ target = '',
73
75
  text,
74
76
  htmlType = 'button',
75
77
  value,
@@ -119,7 +121,17 @@ const Button = (props: ButtonPropTypes) => {
119
121
  }
120
122
  }
121
123
 
122
- const displayButton = () => {
124
+ const getTargetAttribute = () => {
125
+ if (target && link) {
126
+ return target
127
+ } else if (newWindow) {
128
+ return '_blank'
129
+ }
130
+
131
+ return null
132
+ }
133
+
134
+ const displayButton = () => {
123
135
  if (link)
124
136
  return (
125
137
  <a
@@ -128,10 +140,10 @@ const Button = (props: ButtonPropTypes) => {
128
140
  className={css}
129
141
  href={link}
130
142
  id={id}
131
- rel="noreferrer"
143
+ rel={target !== 'child' ? 'noreferrer' : null}
132
144
  role="link"
133
145
  tabIndex={tabIndex}
134
- target={newWindow ? '_blank' : null}
146
+ target={getTargetAttribute()}
135
147
  >
136
148
  {ifLoading()}
137
149
  </a>
@@ -18,6 +18,7 @@ module Playbook
18
18
  prop :variant, type: Playbook::Props::Enum,
19
19
  values: %w[primary secondary link],
20
20
  default: "primary"
21
+ prop :target
21
22
  prop :text
22
23
  prop :type
23
24
  prop :value
@@ -41,11 +42,19 @@ module Playbook
41
42
  }.compact
42
43
  end
43
44
 
45
+ def target_attribute
46
+ if target && link
47
+ target
48
+ elsif new_window
49
+ "_blank"
50
+ end
51
+ end
52
+
44
53
  def link_options
45
54
  options.tap do |option|
46
55
  option[:href] = link
47
56
  option[:role] = "link"
48
- option[:target] = "_blank" if new_window
57
+ option[:target] = target_attribute if target_attribute.present?
49
58
  option[:tabindex] = 0
50
59
  end
51
60
  end
@@ -6,97 +6,128 @@ import Button from './_button'
6
6
 
7
7
  // Primary Test Variables
8
8
  const htmlType = 'submit',
9
- text = 'Button Text',
10
- value = '1234'
9
+ text = 'Button Text',
10
+ value = '1234'
11
11
 
12
12
  test('passes type, text, and value props to button', () => {
13
- render(
14
- <Button
15
- data={{ testid: 'primary-test' }}
16
- htmlType={htmlType}
17
- text={text}
18
- value={value}
19
- />
20
- )
21
-
22
- const kit = screen.getByTestId('primary-test')
23
- const content = screen.getByText(text)
24
-
25
- expect(kit).toHaveClass('pb_button_kit_primary_inline_enabled')
26
- expect(kit).toHaveAttribute('type', htmlType)
27
- expect(kit).toHaveAttribute('value', value)
28
- expect(content).toHaveTextContent(text)
13
+ render(
14
+ <Button
15
+ data={{ testid: 'primary-test' }}
16
+ htmlType={htmlType}
17
+ text={text}
18
+ value={value}
19
+ />
20
+ )
21
+
22
+ const kit = screen.getByTestId('primary-test')
23
+ const content = screen.getByText(text)
24
+
25
+ expect(kit).toHaveClass('pb_button_kit_primary_inline_enabled')
26
+ expect(kit).toHaveAttribute('type', htmlType)
27
+ expect(kit).toHaveAttribute('value', value)
28
+ expect(content).toHaveTextContent(text)
29
29
  })
30
30
 
31
31
  // Link Test Variables
32
32
  const link = 'https://www.google.com'
33
33
 
34
34
  test('adds link to button', () => {
35
- render(
36
- <Button
37
- data={{ testid: 'link-test' }}
38
- link={link}
39
- />
40
- )
35
+ render(
36
+ <Button
37
+ data={{ testid: 'link-test' }}
38
+ link={link}
39
+ />
40
+ )
41
41
 
42
- const kit = screen.getByTestId('link-test')
42
+ const kit = screen.getByTestId('link-test')
43
43
 
44
- expect(kit).toHaveAttribute('href', link)
44
+ expect(kit).toHaveAttribute('href', link)
45
45
  })
46
46
 
47
47
  test('button with secondary variant', () => {
48
- render(
49
- <Button
50
- data={{ testid: 'variant-test' }}
51
- variant="secondary"
52
- />
53
- )
48
+ render(
49
+ <Button
50
+ data={{ testid: 'variant-test' }}
51
+ variant="secondary"
52
+ />
53
+ )
54
54
 
55
- const kit = screen.getByTestId('variant-test')
55
+ const kit = screen.getByTestId('variant-test')
56
56
 
57
- expect(kit).toHaveClass('pb_button_kit_secondary_inline_enabled')
58
- expect(kit).toHaveAttribute('type', 'button')
57
+ expect(kit).toHaveClass('pb_button_kit_secondary_inline_enabled')
58
+ expect(kit).toHaveAttribute('type', 'button')
59
59
  })
60
60
 
61
61
  test('disable prop', () => {
62
- render(
63
- <Button
64
- data={{ testid: 'disable-test' }}
65
- disabled
66
- />
67
- )
62
+ render(
63
+ <Button
64
+ data={{ testid: 'disable-test' }}
65
+ disabled
66
+ />
67
+ )
68
68
 
69
- const kit = screen.getByTestId('disable-test')
69
+ const kit = screen.getByTestId('disable-test')
70
70
 
71
- expect(kit).toBeDisabled()
71
+ expect(kit).toBeDisabled()
72
72
  })
73
73
 
74
74
  test('click event', async () => {
75
- render(
76
- <Button
77
- data={{ testid: 'click-test' }}
78
- onClick={() => appendAlert('clicked button!')}
79
- />
80
- )
75
+ render(
76
+ <Button
77
+ data={{ testid: 'click-test' }}
78
+ onClick={() => appendAlert('clicked button!')}
79
+ />
80
+ )
81
81
 
82
- const kit = screen.getByTestId('click-test')
82
+ const kit = screen.getByTestId('click-test')
83
83
 
84
- fireEvent.click(kit)
84
+ fireEvent.click(kit)
85
85
 
86
- await waitFor(() => screen.getByText('clicked button!'))
86
+ await waitFor(() => screen.getByText('clicked button!'))
87
87
 
88
- expect(screen.getByText('clicked button!')).toBeInTheDocument()
88
+ expect(screen.getByText('clicked button!')).toBeInTheDocument()
89
89
  })
90
90
 
91
91
  test('size prop', () => {
92
- render(
93
- <Button
94
- data={{ testid: 'size-test' }}
95
- size="sm"
96
- />
97
- )
92
+ render(
93
+ <Button
94
+ data={{ testid: 'size-test' }}
95
+ size="sm"
96
+ />
97
+ )
98
98
 
99
- const kit = screen.getByTestId('size-test')
99
+ const kit = screen.getByTestId('size-test')
100
100
 
101
- expect(kit).toHaveClass('pb_button_kit_primary_inline_enabled size_sm')
101
+ expect(kit).toHaveClass('pb_button_kit_primary_inline_enabled size_sm')
102
+ })
103
+
104
+ test('should render target prop', () => {
105
+ render(
106
+ <Button
107
+ data={{ testid: 'variant-test' }}
108
+ link="https://google.com"
109
+ target="_parent"
110
+ variant="secondary"
111
+ />
112
+ )
113
+
114
+ const kit = screen.getByTestId('variant-test')
115
+ expect(kit).toHaveAttribute('target', '_parent')
116
+ expect(kit).toHaveAttribute('rel', 'noreferrer')
117
+ })
118
+
119
+ test('should render child target prop', () => {
120
+ render(
121
+ <Button
122
+ data={{ testid: 'variant-test' }}
123
+ link="https://google.com"
124
+ newWindow
125
+ target="child"
126
+ variant="secondary"
127
+ />
128
+ )
129
+
130
+ const kit = screen.getByTestId('variant-test')
131
+ expect(kit).toHaveAttribute('target', 'child')
132
+ expect(kit).not.toHaveAttribute('rel')
102
133
  })
@@ -1,3 +1,4 @@
1
1
  <%= pb_rails("button", props: { text: "A Tag Button", aria: { label: "Link to Google" }, tag: "a", link: "http://google.com", margin_right: "lg" }) %>
2
- <%= pb_rails("button", props: { text: "Open in new Window", aria: { label: "Link to Google in new window" }, new_window: true, link: "http://google.com",margin_right: "lg" }) %>
3
- <%= pb_rails("button", props: { text: "A Tag Button Disabled", aria: { label: "Disabled link to Google" }, disabled: true, link: "http://google.com",margin_right: "lg" }) %>
2
+ <%= pb_rails("button", props: { text: "Open in new Window", aria: { label: "Link to Google in new window" }, new_window: true, link: "http://google.com", margin_right: "lg" }) %>
3
+ <%= pb_rails("button", props: { text: "Open in a Child Tab", aria: { label: "Link to Playbook in new window" }, link: "https://playbook.powerapp.cloud/", margin_right: "lg", target: "child"}) %>
4
+ <%= pb_rails("button", props: { text: "A Tag Button Disabled", aria: { label: "Disabled link to Google" }, disabled: true, link: "http://google.com", margin_right: "lg" }) %>
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import { Button } from '../../'
3
3
 
4
4
  const ButtonLink = (props) => (
5
- <div>
5
+ <>
6
6
  <Button
7
7
  aria={{ label: 'Link to Google' }}
8
8
  link="https://google.com"
@@ -22,6 +22,16 @@ const ButtonLink = (props) => (
22
22
  {...props}
23
23
  />
24
24
  {' '}
25
+ <Button
26
+ aria={{ label: 'Link to Playbook in new window' }}
27
+ link="https://playbook.powerapp.cloud/"
28
+ marginRight='lg'
29
+ tabIndex={0}
30
+ target='child'
31
+ text="Open in a Child Tab"
32
+ {...props}
33
+ />
34
+ {' '}
25
35
  <Button
26
36
  aria={{ label: 'Disabled link to Google' }}
27
37
  disabled
@@ -31,7 +41,7 @@ const ButtonLink = (props) => (
31
41
  text="A Tag Button Disabled"
32
42
  {...props}
33
43
  />
34
- </div>
44
+ </>
35
45
  )
36
46
 
37
47
  export default ButtonLink
@@ -0,0 +1 @@
1
+ The `link` prop accepts a string that is used as an href value and causes the button to act as a link. The default behavior of a link is to open in the current window. You can optionally alter the link behavior by adding the `newWindow` prop (boolean), which will open the link in a new window, or by calling the `target` prop, which accepts `_self`, `_blank`, `_parent`, `_top`, `child`, or any string, allowing you to specify any link target.
@@ -34,7 +34,7 @@
34
34
  }
35
35
  .flatpickr-day.inRange {
36
36
  background-color: #F7FBFF;
37
- border: 2px;
37
+ border-color: transparent;
38
38
  box-shadow: -$space_xs + 4 0 0 #F7FBFF, $space_xs - 3 0 0 #F7FBFF;
39
39
  }
40
40
  /*
@@ -14,6 +14,7 @@ const iconMap = {
14
14
  };
15
15
 
16
16
  type FixedConfirmationToastProps = {
17
+ autoClose?: number;
17
18
  className?: string;
18
19
  closeable?: boolean;
19
20
  data?: string;
@@ -30,11 +31,12 @@ type FixedConfirmationToastProps = {
30
31
  const FixedConfirmationToast = (props: FixedConfirmationToastProps) => {
31
32
  const [showToast, toggleToast] = useState(true);
32
33
  const {
34
+ autoClose = 0,
33
35
  className,
34
36
  closeable = false,
35
37
  horizontal,
36
38
  multiLine = false,
37
- onClose = () => {},
39
+ onClose = () => { },
38
40
  open = true,
39
41
  status = "neutral",
40
42
  text,
@@ -49,8 +51,18 @@ const FixedConfirmationToast = (props: FixedConfirmationToastProps) => {
49
51
  );
50
52
  const icon = iconMap[status];
51
53
 
54
+ const autoCloseToast = () => {
55
+ if (autoClose && open) {
56
+ setTimeout(() => {
57
+ toggleToast(false);
58
+ onClose();
59
+ }, autoClose);
60
+ }
61
+ }
62
+
52
63
  useEffect(() => {
53
64
  toggleToast(open);
65
+ autoCloseToast();
54
66
  }, [open]);
55
67
 
56
68
  const handleClick = () => {
@@ -0,0 +1,68 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import Button from '../../pb_button/_button'
4
+ import FixedConfirmationToast from '../_fixed_confirmation_toast'
5
+
6
+ const FixedConfirmationToastAutoClose = (props) => {
7
+
8
+ const [open, setOpen] = useState(false)
9
+ const [openCloseable, setOpenCloseable] = useState(false)
10
+
11
+ const handleClick = () => {
12
+ setOpen(true)
13
+ }
14
+ const handleClickCloseable = () => {
15
+ setOpenCloseable(true)
16
+ }
17
+
18
+ const handleClose = () => {
19
+ setOpen(false)
20
+ }
21
+
22
+ const handleCloseCloseable = () => {
23
+ setOpenCloseable(false)
24
+ }
25
+
26
+ return (
27
+ <>
28
+ <Button
29
+ onClick={handleClick}
30
+ text="Show Auto Close Toast"
31
+ variant="secondary"
32
+ {...props}
33
+ />
34
+ {' '}
35
+ <Button
36
+ onClick={handleClickCloseable}
37
+ text="Show Closeable Auto Close Toast"
38
+ variant="secondary"
39
+ {...props}
40
+ />
41
+
42
+ <FixedConfirmationToast
43
+ autoClose={3000}
44
+ horizontal='center'
45
+ onClose={handleClose}
46
+ open={open}
47
+ status='tip'
48
+ text='I will disappear in 3 seconds.'
49
+ vertical='top'
50
+ {...props}
51
+ />
52
+
53
+ <FixedConfirmationToast
54
+ autoClose={10000}
55
+ closeable
56
+ horizontal='center'
57
+ onClose={handleCloseCloseable}
58
+ open={openCloseable}
59
+ status='tip'
60
+ text='I will disappear in 10 seconds.'
61
+ vertical='top'
62
+ {...props}
63
+ />
64
+ </>
65
+ )
66
+ }
67
+
68
+ export default FixedConfirmationToastAutoClose
@@ -0,0 +1 @@
1
+ Auto close is used when you want the confirmation toast to close automatically after a certain time. `autoClose` property will be a delay number in ms.
@@ -11,3 +11,4 @@ examples:
11
11
  - fixed_confirmation_toast_multi_line: Multi Line
12
12
  - fixed_confirmation_toast_close: Click to Close
13
13
  - fixed_confirmation_toast_positions: Click to Show Positions
14
+ - fixed_confirmation_toast_auto_close: Click to Show Auto Close
@@ -2,3 +2,4 @@ export { default as FixedConfirmationToastDefault } from './_fixed_confirmation_
2
2
  export { default as FixedConfirmationToastMultiLine } from './_fixed_confirmation_toast_multi_line.jsx'
3
3
  export { default as FixedConfirmationToastClose } from './_fixed_confirmation_toast_close.jsx'
4
4
  export { default as FixedConfirmationToastPositions } from './_fixed_confirmation_toast_positions.jsx'
5
+ export { default as FixedConfirmationToastAutoClose } from './_fixed_confirmation_toast_auto_close.jsx'
@@ -19,6 +19,7 @@ module Playbook
19
19
  prop :vertical, type: Playbook::Props::Enum,
20
20
  values: [nil, "top", "bottom"],
21
21
  default: nil
22
+ prop :auto_close, type: Playbook::Props::Number
22
23
 
23
24
  def show_text?
24
25
  text.present?
@@ -28,6 +29,10 @@ module Playbook
28
29
  closeable.present? ? " remove_toast" : ""
29
30
  end
30
31
 
32
+ def auto_close_class
33
+ auto_close.present? ? " auto_close_#{auto_close}" : ""
34
+ end
35
+
31
36
  def position_class
32
37
  horizontal && vertical ? " positioned_toast #{vertical} #{horizontal}" : ""
33
38
  end
@@ -50,7 +55,7 @@ module Playbook
50
55
  end
51
56
 
52
57
  def classname
53
- generate_classname("pb_fixed_confirmation_toast_kit", status, multi_line_class) + close_class + position_class
58
+ generate_classname("pb_fixed_confirmation_toast_kit", status, multi_line_class) + close_class + position_class + auto_close_class
54
59
  end
55
60
  end
56
61
  end
@@ -7,6 +7,8 @@ export default class PbFixedConfirmationToast extends PbEnhancedElement {
7
7
 
8
8
  connect() {
9
9
  this.self = this.element
10
+ this.autoCloseToast(this.self)
11
+
10
12
  this.self.addEventListener('click', () => {
11
13
  this.removeToast(this.self)
12
14
  })
@@ -15,4 +17,19 @@ export default class PbFixedConfirmationToast extends PbEnhancedElement {
15
17
  removeToast(elem) {
16
18
  elem.parentNode.removeChild(elem)
17
19
  }
20
+
21
+ autoCloseToast(element) {
22
+ const classListValues = element.classList.value
23
+ const hasAutoCloseClass = classListValues.includes('auto_close')
24
+
25
+ if (hasAutoCloseClass) {
26
+ const classList = classListValues.split(' ')
27
+ const autoCloseValue = classList[classList.length - 1].split('_')[2]
28
+ const autoCloseIntValue = parseInt(autoCloseValue)
29
+
30
+ setTimeout(() => {
31
+ this.removeToast(element)
32
+ }, autoCloseIntValue)
33
+ }
34
+ }
18
35
  }
@@ -1,6 +1,3 @@
1
- /* @flow */
2
- /* eslint-disable react-hooks/rules-of-hooks */
3
-
4
1
  import React, { useEffect, useState } from 'react'
5
2
  import classnames from 'classnames'
6
3
  import inlineFocus from './inlineFocus'
@@ -18,11 +15,21 @@ try {
18
15
 
19
16
  import { TrixEditor } from "react-trix"
20
17
 
18
+ type Editor = {
19
+ attributeIsActive?: Function,
20
+ element?: HTMLElement,
21
+ getSelectedDocument?: Function,
22
+ getSelectedRange?: () => Array<number>,
23
+ insertHTML?: Function,
24
+ loadHTML?: Function,
25
+ setSelectedRange?: (range: Array<number>) => void,
26
+ }
27
+
21
28
  type RichTextEditorProps = {
22
- aria?: object,
29
+ aria?: { [key: string]: string },
23
30
  toolbarBottom?: Boolean,
24
31
  className?: string,
25
- data?: object,
32
+ data?: { [key: string]: string },
26
33
  focus?: boolean,
27
34
  id?: string,
28
35
  inline?: boolean,
@@ -53,19 +60,19 @@ const RichTextEditor = (props: RichTextEditorProps) => {
53
60
  } = props
54
61
 
55
62
  const ariaProps = buildAriaProps(aria),
56
- dataProps = buildDataProps(data),
57
- [editor, setEditor] = useState()
63
+ dataProps = buildDataProps(data),
64
+ [editor, setEditor] = useState<Editor>()
58
65
 
59
- const handleOnEditorReady = (editorInstance) => setEditor(editorInstance),
60
- element = editor?.element
66
+ const handleOnEditorReady = (editorInstance: Editor) => setEditor(editorInstance),
67
+ element = editor?.element
61
68
 
62
69
  // DOM manipulation must wait for editor to be ready
63
70
  if (editor) {
64
- const toolbarElement = element.parentElement.querySelector('trix-toolbar'),
65
- blockCodeButton = toolbarElement.querySelector('[data-trix-attribute=code]')
71
+ const toolbarElement = element.parentElement.querySelector('trix-toolbar') as HTMLElement,
72
+ blockCodeButton = toolbarElement.querySelector('[data-trix-attribute=code]') as HTMLElement
66
73
 
67
- let inlineCodeButton = toolbarElement.querySelector('[data-trix-attribute=inlineCode]')
68
- if (!inlineCodeButton) inlineCodeButton = blockCodeButton.cloneNode(true)
74
+ let inlineCodeButton = toolbarElement.querySelector('[data-trix-attribute=inlineCode]') as HTMLElement
75
+ if (!inlineCodeButton) inlineCodeButton = blockCodeButton.cloneNode(true) as HTMLElement
69
76
 
70
77
  // set button attributes
71
78
  inlineCodeButton.dataset.trixAttribute = 'inlineCode'
@@ -93,8 +100,8 @@ const RichTextEditor = (props: RichTextEditorProps) => {
93
100
 
94
101
  focus
95
102
  ? (document.addEventListener('trix-focus', useFocus),
96
- document.addEventListener('trix-blur', useFocus),
97
- useFocus())
103
+ document.addEventListener('trix-blur', useFocus),
104
+ useFocus())
98
105
  : null
99
106
 
100
107
  document.addEventListener('trix-focus', inlineFocus)
@@ -110,11 +117,11 @@ const RichTextEditor = (props: RichTextEditorProps) => {
110
117
 
111
118
  useEffect(() => {
112
119
  if (!element) return
113
- element.addEventListener('click', ({target}) => {
114
- const trixEditorContainer = target.closest('.pb_rich_text_editor_kit')
120
+ element.addEventListener('click', ({ target }: Event) => {
121
+ const trixEditorContainer = (target as Element).closest('.pb_rich_text_editor_kit')
115
122
  if (!trixEditorContainer) return
116
123
 
117
- const anchorElement = target.closest('a')
124
+ const anchorElement = (target as Element).closest('a')
118
125
  if (!anchorElement) return
119
126
 
120
127
  if (anchorElement.hasAttribute('href')) window.open(anchorElement.href)
@@ -122,11 +129,11 @@ const RichTextEditor = (props: RichTextEditorProps) => {
122
129
  }, [element])
123
130
 
124
131
  const richTextEditorClass = 'pb_rich_text_editor_kit',
125
- simpleClass = simple ? 'simple' : '',
126
- focusClass = focus ? 'focus-editor-targets' : '',
127
- stickyClass = sticky ? 'sticky' : '',
128
- inlineClass = inline ? 'inline' : '',
129
- toolbarBottomClass = toolbarBottom ? 'toolbar-bottom' : ''
132
+ simpleClass = simple ? 'simple' : '',
133
+ focusClass = focus ? 'focus-editor-targets' : '',
134
+ stickyClass = sticky ? 'sticky' : '',
135
+ inlineClass = inline ? 'inline' : '',
136
+ toolbarBottomClass = toolbarBottom ? 'toolbar-bottom' : ''
130
137
 
131
138
  let css = classnames(globalProps(props), className)
132
139
  css = classnames(
@@ -141,17 +148,18 @@ const RichTextEditor = (props: RichTextEditorProps) => {
141
148
 
142
149
  return (
143
150
  <div
144
- {...ariaProps}
145
- {...dataProps}
146
- className={css}
151
+ {...ariaProps}
152
+ {...dataProps}
153
+ className={css}
147
154
  >
148
155
  <TrixEditor
149
- className=""
150
- fileParamName={name}
151
- onChange={onChange}
152
- onEditorReady={handleOnEditorReady}
153
- placeholder={placeholder}
154
- value={value}
156
+ className=""
157
+ fileParamName={name}
158
+ mergeTags={[]}
159
+ onChange={onChange}
160
+ onEditorReady={handleOnEditorReady}
161
+ placeholder={placeholder}
162
+ value={value}
155
163
  />
156
164
  </div>
157
165
  )
@@ -1,5 +1,5 @@
1
1
  const inlineFocus = () => {
2
- const trixEditorElement = event.target
2
+ const trixEditorElement = event.target as Element
3
3
  const trixEditorContainer = trixEditorElement.closest('.pb_rich_text_editor_kit')
4
4
 
5
5
  if (!trixEditorContainer.classList.contains('inline')) return
@@ -2,7 +2,7 @@ const useFocus = () => {
2
2
  const allTrixEditors = document.querySelectorAll(
3
3
  '.focus-editor-targets trix-editor'
4
4
  )
5
- allTrixEditors.forEach((editorElement) => {
5
+ allTrixEditors.forEach((editorElement: any) => {
6
6
  const toolbarElement = editorElement.toolbarElement
7
7
  if (editorElement == document.activeElement) {
8
8
  editorElement.classList.add('focused-editor')
@@ -102,6 +102,7 @@ const SelectableCard = (props: SelectableCardProps) => {
102
102
  delete filteredProps?.error
103
103
  delete filteredProps?.dark
104
104
  delete filteredProps?.multi
105
+ delete filteredProps?.customIcon
105
106
  const labelProps: GlobalProps = variant === 'displayInput' ? { ...filteredProps, padding: 'none' } : { ...filteredProps }
106
107
 
107
108
  return (
@@ -0,0 +1,67 @@
1
+ import React, { useState } from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import SelectableCardIcon from './_selectable_card_icon'
5
+
6
+ const testId = 'selectableCardIcon'
7
+ const className = 'custom-class-name'
8
+
9
+ const SelectableCardIconDefault = () => {
10
+ const [selected, setSelected] = useState(true)
11
+
12
+ return (
13
+ <SelectableCardIcon
14
+ aria={{ label: testId }}
15
+ bodyText="Export"
16
+ checked={selected}
17
+ className={className}
18
+ data={{ testid: testId }}
19
+ icon="chart-line"
20
+ inputId={1}
21
+ onChange={() => setSelected(!selected)}
22
+ titleText="Quarterly Report"
23
+ />
24
+ )
25
+ }
26
+
27
+ test('should pass data prop', () => {
28
+ render(<SelectableCardIconDefault />)
29
+ const kit = screen.getByTestId(testId)
30
+ expect(kit).toBeInTheDocument()
31
+ })
32
+
33
+ test('should pass className prop', () => {
34
+ render(<SelectableCardIconDefault />)
35
+ const kit = screen.getByTestId(testId)
36
+ expect(kit).toHaveClass(className)
37
+ })
38
+
39
+ test('should pass aria prop', () => {
40
+ render(<SelectableCardIconDefault />)
41
+ const kit = screen.getByTestId(testId)
42
+ expect(kit).toHaveAttribute('aria-label', testId)
43
+ })
44
+
45
+ test('should be checked', () => {
46
+ render(<SelectableCardIconDefault />)
47
+ const kit = screen.getByTestId(testId)
48
+ expect(kit).toHaveClass('pb_selectable_card_icon_kit_checked_enabled')
49
+ })
50
+
51
+ test('should not be disabled', () => {
52
+ render(<SelectableCardIconDefault />)
53
+ const kit = screen.getByTestId(testId)
54
+ expect(kit).toHaveClass('pb_selectable_card_icon_kit_checked_enabled')
55
+ })
56
+
57
+ test('should render body text prop', () => {
58
+ render(<SelectableCardIconDefault />)
59
+ const kit = screen.getByText("Export")
60
+ expect(kit).toBeInTheDocument()
61
+ })
62
+
63
+ test('should render title text prop', () => {
64
+ render(<SelectableCardIconDefault />)
65
+ const kit = screen.getByText("Quarterly Report")
66
+ expect(kit).toBeInTheDocument()
67
+ })
@@ -1,5 +1,3 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import classnames from 'classnames'
5
3
 
@@ -15,13 +13,13 @@ import SelectableCard from '../pb_selectable_card/_selectable_card'
15
13
  import SelectableIcon from '../pb_selectable_icon/_selectable_icon'
16
14
 
17
15
  type SelectableCardIconProps = {
18
- aria?: Object,
16
+ aria?: { [key: string]: string },
19
17
  checked?: boolean,
20
18
  checkmark: boolean,
21
19
  className?: string,
22
- customIcon?: SVGElement,
20
+ customIcon?: { [key: string]: SVGElement },
23
21
  dark?: boolean,
24
- data?: Object,
22
+ data?: { [key: string]: string },
25
23
  disabled?: boolean,
26
24
  icon?: string,
27
25
  inputId?: string,
@@ -30,7 +28,7 @@ type SelectableCardIconProps = {
30
28
  titleText?: string,
31
29
  bodyText?: string,
32
30
  value?: string,
33
- onChange?: (e) => void,
31
+ onChange?: (event: React.FormEvent<HTMLInputElement>) => void,
34
32
  }
35
33
 
36
34
  const SelectableCardIcon = (props: SelectableCardIconProps) => {
@@ -68,35 +66,35 @@ const SelectableCardIcon = (props: SelectableCardIconProps) => {
68
66
 
69
67
  return (
70
68
  <div
71
- {...ariaProps}
72
- {...dataProps}
73
- className={classes}
69
+ {...ariaProps}
70
+ {...dataProps}
71
+ className={classes}
74
72
  >
75
73
  <SelectableCard
76
- checked={checked}
77
- customIcon={customIcon}
78
- dark={dark}
79
- disabled={disabled}
80
- icon={checkmark}
81
- inputId={inputId}
82
- multi={multi}
83
- name={name}
84
- onChange={onChange}
85
- value={value}
74
+ checked={checked}
75
+ customIcon={customIcon}
76
+ dark={dark}
77
+ disabled={disabled}
78
+ icon={checkmark}
79
+ inputId={inputId}
80
+ multi={multi}
81
+ name={name}
82
+ onChange={onChange}
83
+ value={value}
86
84
  >
87
85
  {
88
86
  <>
89
87
  <SelectableIcon
90
- customIcon={customIcon}
91
- icon={icon}
92
- inputs="disabled"
93
- size="2x"
94
- text={titleText}
95
- />
88
+ customIcon={customIcon}
89
+ icon={icon}
90
+ inputId={''}
91
+ inputs="disabled"
92
+ name={''}
93
+ text={titleText} />
96
94
  <Body
97
- color="light"
98
- dark={dark}
99
- text={bodyText}
95
+ color="light"
96
+ dark={dark}
97
+ text={bodyText}
100
98
  />
101
99
  </>
102
100
  }
@@ -1,28 +1,28 @@
1
- /* @flow */
2
-
3
1
  import React from 'react'
4
2
  import classnames from 'classnames'
5
3
 
6
- import { buildDataProps } from '../utilities/props'
4
+ import { buildDataProps, buildAriaProps } from '../utilities/props'
7
5
  import { titleize } from '../utilities/text'
8
6
 
9
- import Avatar from '../pb_avatar/_avatar'
7
+ import Avatar, { AvatarProps } from '../pb_avatar/_avatar'
10
8
  import Body from '../pb_body/_body'
11
9
  import Caption from '../pb_caption/_caption'
12
10
  import IconCircle from '../pb_icon_circle/_icon_circle'
13
11
  import Title from '../pb_title/_title'
14
12
 
15
13
  type SourceProps = {
14
+ aria?: {[key: string]: string},
16
15
  className?: string,
17
- data?: object,
16
+ data?: { [key: string]: string },
18
17
  hideIcon: boolean,
19
18
  id?: string,
20
19
  source?: string,
21
20
  type: "events" | "inbound" | "outbound" | "prospecting" | "referral" | "retail" | "user",
22
- user: object,
21
+ user: AvatarProps,
23
22
  }
24
23
 
25
24
  const Source = ({
25
+ aria = {},
26
26
  className,
27
27
  data = {},
28
28
  hideIcon = false,
@@ -32,6 +32,7 @@ const Source = ({
32
32
  user = {},
33
33
  }: SourceProps) => {
34
34
  const dataProps = buildDataProps(data)
35
+ const ariaProps = buildAriaProps(aria)
35
36
 
36
37
  const css = classnames([
37
38
  'pb_source_kit',
@@ -40,7 +41,7 @@ const Source = ({
40
41
 
41
42
  const avatar = () => {
42
43
  if ((type === 'user' || type === 'referral') && user.name !== undefined) {
43
- const avatarProps = { ...user }
44
+ const avatarProps: AvatarProps = { ...user }
44
45
  avatarProps.size = 'sm'
45
46
  delete avatarProps.userId
46
47
  return avatarProps
@@ -55,7 +56,7 @@ const Source = ({
55
56
  }
56
57
  }
57
58
 
58
- const typeIconNames = {
59
+ const typeIconNames: { [key: string]: string } = {
59
60
  events: 'calendar-alt',
60
61
  outbound: 'sign-out',
61
62
  prospecting: 'binoculars',
@@ -68,47 +69,50 @@ const Source = ({
68
69
 
69
70
  return (
70
71
  <div
71
- {...dataProps}
72
- className={css}
73
- id={id}
72
+ {...ariaProps}
73
+ {...dataProps}
74
+ className={css}
75
+ id={id}
74
76
  >
75
77
 
76
78
  <div className="pb__source_layout">
77
- <If condition={hideIcon === false}>
78
- <If condition={showIcon()}>
79
- <IconCircle
79
+ {hideIcon === false &&
80
+ <>
81
+ {showIcon() &&
82
+ <IconCircle
80
83
  icon={typeIconNames[type]}
81
84
  size="sm"
82
- />
83
- <Else />
84
- <Avatar
85
+ />
86
+ }
87
+ {!showIcon() &&
88
+ <Avatar
85
89
  {...avatar()}
86
- />
87
- </If>
88
- </If>
90
+ />
91
+ }
92
+ </>
93
+ }
89
94
 
90
95
  <div className="pb__source_content">
91
96
  <Title
92
- size={4}
93
- tag="h4"
94
- text={source}
97
+ size={4}
98
+ tag="h4"
99
+ text={source}
95
100
  />
96
101
 
97
102
  <div className="pb__source_value">
98
103
  <Body
99
- color="light"
100
- text={typeText()}
104
+ color="light"
105
+ text={typeText()}
101
106
  />
102
107
 
103
- <If condition={user.userId}>
108
+ {user.userId &&
104
109
  <Caption
105
- text={user.userId}
110
+ text={user.userId}
106
111
  />
107
- </If>
112
+ }
108
113
  </div>
109
114
  </div>
110
115
  </div>
111
-
112
116
  </div>
113
117
  )
114
118
  }
@@ -0,0 +1,82 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import Source from './_source'
5
+
6
+ const testId = 'source'
7
+ const className = 'custom-class-name'
8
+
9
+ const SourceDefault = (props) => (
10
+ <>
11
+ <Source
12
+ aria={{ label: testId }}
13
+ className={className}
14
+ data={{ testid: testId }}
15
+ source="BJ's Johnston-208"
16
+ type='retail'
17
+ {...props}
18
+ />
19
+ </>
20
+ )
21
+
22
+ test('should pass data prop', () => {
23
+ render(<SourceDefault />)
24
+ const kit = screen.getByTestId(testId)
25
+ expect(kit).toBeInTheDocument()
26
+ })
27
+
28
+ test('should pass className prop', () => {
29
+ render(<SourceDefault />)
30
+ const kit = screen.getByTestId(testId)
31
+ expect(kit).toHaveClass(className)
32
+ })
33
+
34
+ test('should pass aria prop', () => {
35
+ render(<SourceDefault />)
36
+ const kit = screen.getByTestId(testId)
37
+ expect(kit).toHaveAttribute('aria-label', testId)
38
+ })
39
+
40
+ test('should pass type prop', () => {
41
+ render(<SourceDefault />)
42
+ const kit = screen.getByText('Retail')
43
+ expect(kit).toBeInTheDocument()
44
+ })
45
+
46
+ test('should pass source prop', () => {
47
+ render(<SourceDefault />)
48
+ const kit = screen.getByText("BJ's Johnston-208")
49
+ expect(kit).toBeInTheDocument()
50
+ })
51
+
52
+ test('should not hide icon by default', () => {
53
+ render(<SourceDefault />)
54
+ const kit = screen.getByTestId(testId)
55
+ expect(kit.querySelector('.pb_icon_circle_kit_sm_default')).toBeTruthy()
56
+ })
57
+
58
+ test('should hide icon', () => {
59
+ render(<SourceDefault hideIcon />)
60
+ const kit = screen.getByTestId(testId)
61
+ expect(kit.querySelector('.pb_icon_circle_kit_sm_default')).toBeFalsy()
62
+ })
63
+
64
+ test('should pass user prop', () => {
65
+ const user = {
66
+ name: 'Anna Black',
67
+ userId: '48582',
68
+ }
69
+
70
+ render(
71
+ <SourceDefault
72
+ type='user'
73
+ user={user}
74
+ />
75
+ )
76
+
77
+ let kit = screen.getByText(user.name)
78
+ expect(kit).toBeInTheDocument()
79
+
80
+ kit = screen.getByText(user.userId)
81
+ expect(kit).toBeInTheDocument()
82
+ })
@@ -10,13 +10,16 @@ import {
10
10
  useFloating,
11
11
  useHover,
12
12
  useInteractions,
13
- } from "@floating-ui/react-dom-interactions"
13
+ } from "@floating-ui/react"
14
14
 
15
15
  import classnames from "classnames"
16
16
  import { GlobalProps, globalProps } from "../utilities/globalProps"
17
17
  import { buildAriaProps, buildDataProps } from "../utilities/props"
18
18
  import Flex from "../pb_flex/_flex"
19
19
 
20
+
21
+
22
+
20
23
  type TooltipProps = {
21
24
  aria?: { [key: string]: string },
22
25
  className?: string | string[],
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playbook
4
- PREVIOUS_VERSION = "12.9.1"
5
- VERSION = "12.10.0"
4
+ PREVIOUS_VERSION = "12.10.0"
5
+ VERSION = "12.11.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: playbook_ui
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.10.0
4
+ version: 12.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Power UX
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-03-22 00:00:00.000000000 Z
12
+ date: 2023-03-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -457,6 +457,7 @@ files:
457
457
  - app/pb_kits/playbook/pb_button/docs/_button_icon_options.md
458
458
  - app/pb_kits/playbook/pb_button/docs/_button_link.html.erb
459
459
  - app/pb_kits/playbook/pb_button/docs/_button_link.jsx
460
+ - app/pb_kits/playbook/pb_button/docs/_button_link.md
460
461
  - app/pb_kits/playbook/pb_button/docs/_button_loading.html.erb
461
462
  - app/pb_kits/playbook/pb_button/docs/_button_loading.jsx
462
463
  - app/pb_kits/playbook/pb_button/docs/_button_loading.md
@@ -955,6 +956,8 @@ files:
955
956
  - app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.scss
956
957
  - app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.tsx
957
958
  - app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_description.md
959
+ - app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_auto_close.jsx
960
+ - app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_auto_close.md
958
961
  - app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_close.html.erb
959
962
  - app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_close.jsx
960
963
  - app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_default.html.erb
@@ -1710,8 +1713,8 @@ files:
1710
1713
  - app/pb_kits/playbook/pb_radio/radio.html.erb
1711
1714
  - app/pb_kits/playbook/pb_radio/radio.rb
1712
1715
  - app/pb_kits/playbook/pb_radio/radio.test.js
1713
- - app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.jsx
1714
1716
  - app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.scss
1717
+ - app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx
1715
1718
  - app/pb_kits/playbook/pb_rich_text_editor/_trix_styles.scss
1716
1719
  - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_attributes.html.erb
1717
1720
  - app/pb_kits/playbook/pb_rich_text_editor/docs/_rich_text_editor_attributes.jsx
@@ -1734,11 +1737,11 @@ files:
1734
1737
  - app/pb_kits/playbook/pb_rich_text_editor/docs/example.yml
1735
1738
  - app/pb_kits/playbook/pb_rich_text_editor/docs/index.js
1736
1739
  - app/pb_kits/playbook/pb_rich_text_editor/docs/templates.js
1737
- - app/pb_kits/playbook/pb_rich_text_editor/inlineFocus.js
1740
+ - app/pb_kits/playbook/pb_rich_text_editor/inlineFocus.ts
1738
1741
  - app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb
1739
1742
  - app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.rb
1740
1743
  - app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.test.js
1741
- - app/pb_kits/playbook/pb_rich_text_editor/useFocus.js
1744
+ - app/pb_kits/playbook/pb_rich_text_editor/useFocus.ts
1742
1745
  - app/pb_kits/playbook/pb_section_separator/_section_separator.scss
1743
1746
  - app/pb_kits/playbook/pb_section_separator/_section_separator.tsx
1744
1747
  - app/pb_kits/playbook/pb_section_separator/_section_separator_mixin.scss
@@ -1811,8 +1814,9 @@ files:
1811
1814
  - app/pb_kits/playbook/pb_selectable_card/selectable_card.html.erb
1812
1815
  - app/pb_kits/playbook/pb_selectable_card/selectable_card.rb
1813
1816
  - app/pb_kits/playbook/pb_selectable_card/selectable_card.test.js
1814
- - app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.jsx
1815
1817
  - app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.scss
1818
+ - app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.test.js
1819
+ - app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.tsx
1816
1820
  - app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_checkmark.html.erb
1817
1821
  - app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_checkmark.jsx
1818
1822
  - app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_default.html.erb
@@ -1849,8 +1853,8 @@ files:
1849
1853
  - app/pb_kits/playbook/pb_selectable_list/selectable_list.rb
1850
1854
  - app/pb_kits/playbook/pb_selectable_list/selectable_list_item.html.erb
1851
1855
  - app/pb_kits/playbook/pb_selectable_list/selectable_list_item.rb
1852
- - app/pb_kits/playbook/pb_source/_source.jsx
1853
1856
  - app/pb_kits/playbook/pb_source/_source.scss
1857
+ - app/pb_kits/playbook/pb_source/_source.tsx
1854
1858
  - app/pb_kits/playbook/pb_source/docs/_description.md
1855
1859
  - app/pb_kits/playbook/pb_source/docs/_source_default.html.erb
1856
1860
  - app/pb_kits/playbook/pb_source/docs/_source_default.jsx
@@ -1862,6 +1866,7 @@ files:
1862
1866
  - app/pb_kits/playbook/pb_source/docs/index.js
1863
1867
  - app/pb_kits/playbook/pb_source/source.html.erb
1864
1868
  - app/pb_kits/playbook/pb_source/source.rb
1869
+ - app/pb_kits/playbook/pb_source/source.test.js
1865
1870
  - app/pb_kits/playbook/pb_star_rating/_star_rating.jsx
1866
1871
  - app/pb_kits/playbook/pb_star_rating/_star_rating.scss
1867
1872
  - app/pb_kits/playbook/pb_star_rating/docs/_description.md