playbook_ui 8.2.0.pre.alpha1 → 8.2.1.pre.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -0
  3. data/app/pb_kits/playbook/_playbook.scss +2 -0
  4. data/app/pb_kits/playbook/data/menu.yml +3 -1
  5. data/app/pb_kits/playbook/index.js +2 -0
  6. data/app/pb_kits/playbook/pb_avatar/_avatar.jsx +14 -2
  7. data/app/pb_kits/playbook/pb_avatar/avatar.html.erb +1 -1
  8. data/app/pb_kits/playbook/pb_avatar/avatar.rb +5 -2
  9. data/app/pb_kits/playbook/pb_avatar/avatar.test.js +5 -2
  10. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_default.html.erb +5 -0
  11. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_default.jsx +5 -0
  12. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_status.html.erb +4 -0
  13. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_status.jsx +4 -0
  14. data/app/pb_kits/playbook/pb_avatar_action_button/_avatar_action_button.jsx +6 -0
  15. data/app/pb_kits/playbook/pb_avatar_action_button/avatar_action_button.html.erb +2 -1
  16. data/app/pb_kits/playbook/pb_avatar_action_button/avatar_action_button.rb +2 -0
  17. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_actions.html.erb +4 -0
  18. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_actions.jsx +4 -0
  19. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_default.html.erb +2 -0
  20. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_default.jsx +2 -0
  21. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_on_click.jsx +2 -0
  22. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_onclick.html.erb +2 -0
  23. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_placement.html.erb +8 -0
  24. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_placement.jsx +8 -0
  25. data/app/pb_kits/playbook/pb_avatar_action_button/docs/_avatar_action_button_tooltip.html.erb +2 -0
  26. data/app/pb_kits/playbook/pb_avatar_action_button/pb_avatar_action_button.test.js +31 -0
  27. data/app/pb_kits/playbook/pb_badge/_badge.jsx +26 -1
  28. data/app/pb_kits/playbook/pb_button/_button.jsx +6 -0
  29. data/app/pb_kits/playbook/pb_button/button.test.js +91 -0
  30. data/app/pb_kits/playbook/pb_button/docs/_button_default.jsx +0 -1
  31. data/app/pb_kits/playbook/pb_button_toolbar/button_toolbar.test.js +46 -0
  32. data/app/pb_kits/playbook/pb_caption/_caption.jsx +3 -2
  33. data/app/pb_kits/playbook/pb_caption/caption.rb +1 -1
  34. data/app/pb_kits/playbook/pb_card/_card.jsx +18 -3
  35. data/app/pb_kits/playbook/pb_card/card.html.erb +1 -1
  36. data/app/pb_kits/playbook/pb_card/card.rb +3 -0
  37. data/app/pb_kits/playbook/pb_card/docs/_card_tag.html.erb +25 -0
  38. data/app/pb_kits/playbook/pb_card/docs/_card_tag.jsx +59 -0
  39. data/app/pb_kits/playbook/pb_card/docs/example.yml +2 -0
  40. data/app/pb_kits/playbook/pb_card/docs/index.js +1 -0
  41. data/app/pb_kits/playbook/pb_checkbox/_checkbox.jsx +31 -9
  42. data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +28 -19
  43. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +11 -3
  44. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +6 -1
  45. data/app/pb_kits/playbook/pb_checkbox/checkbox.test.js +94 -0
  46. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_custom.jsx +0 -1
  47. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +7 -0
  48. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.jsx +16 -0
  49. data/app/pb_kits/playbook/pb_checkbox/docs/example.yml +2 -0
  50. data/app/pb_kits/playbook/pb_checkbox/docs/index.js +1 -0
  51. data/app/pb_kits/playbook/pb_circle_icon_button/circle_icon_button.test.js +17 -0
  52. data/app/pb_kits/playbook/pb_date_picker/_date_picker.jsx +6 -0
  53. data/app/pb_kits/playbook/pb_dialog/_close_icon.jsx +23 -0
  54. data/app/pb_kits/playbook/pb_dialog/_dialog.html.erb +10 -0
  55. data/app/pb_kits/playbook/pb_dialog/_dialog.jsx +142 -0
  56. data/app/pb_kits/playbook/pb_dialog/_dialog.scss +133 -0
  57. data/app/pb_kits/playbook/pb_dialog/_dialog_context.jsx +3 -0
  58. data/app/pb_kits/playbook/pb_dialog/child_kits/_dialog_body.jsx +21 -0
  59. data/app/pb_kits/playbook/pb_dialog/child_kits/_dialog_footer.jsx +36 -0
  60. data/app/pb_kits/playbook/pb_dialog/child_kits/_dialog_header.jsx +68 -0
  61. data/app/pb_kits/playbook/pb_dialog/dialog.rb +47 -0
  62. data/app/pb_kits/playbook/pb_dialog/dialog.test.jsx +23 -0
  63. data/app/pb_kits/playbook/pb_dialog/dialog_header.rb +31 -0
  64. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.jsx +53 -0
  65. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_compound_components.md +2 -0
  66. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_default.jsx +27 -0
  67. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_scrollable.jsx +27 -0
  68. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_scrollable.md +2 -0
  69. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_separators.jsx +119 -0
  70. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_separators.md +2 -0
  71. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_should_close_on_overlay.jsx +28 -0
  72. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_should_close_on_overlay.md +2 -0
  73. data/app/pb_kits/playbook/pb_dialog/docs/_dialog_sizes.jsx +93 -0
  74. data/app/pb_kits/playbook/pb_dialog/docs/example.yml +10 -0
  75. data/app/pb_kits/playbook/pb_dialog/docs/index.js +6 -0
  76. data/app/pb_kits/playbook/pb_form/_form.scss +5 -1
  77. data/app/pb_kits/playbook/pb_form/form_builder.rb +4 -2
  78. data/app/pb_kits/playbook/pb_form/form_builder/action_area.rb +14 -7
  79. data/app/pb_kits/playbook/pb_form/simple_form.html.erb +2 -4
  80. data/app/pb_kits/playbook/pb_form/simple_form.rb +4 -0
  81. data/app/pb_kits/playbook/pb_inline/_inline.jsx +83 -0
  82. data/app/pb_kits/playbook/pb_inline/_inline.scss +58 -0
  83. data/app/pb_kits/playbook/pb_inline/docs/_inline_default.jsx +36 -0
  84. data/app/pb_kits/playbook/pb_inline/docs/_inline_input_options.jsx +58 -0
  85. data/app/pb_kits/playbook/pb_inline/docs/_inline_text_options.jsx +99 -0
  86. data/app/pb_kits/playbook/pb_inline/docs/example.yml +5 -0
  87. data/app/pb_kits/playbook/pb_inline/docs/index.js +3 -0
  88. data/app/pb_kits/playbook/pb_inline/inline.test.jsx +21 -0
  89. data/app/pb_kits/playbook/pb_online_status/_online_status.jsx +2 -0
  90. data/app/pb_kits/playbook/pb_online_status/online_status.html.erb +1 -1
  91. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.jsx +4 -3
  92. data/app/pb_kits/playbook/pb_text_input/_text_input.jsx +3 -0
  93. data/app/pb_kits/playbook/pb_textarea/_textarea.jsx +3 -0
  94. data/app/pb_kits/playbook/pb_typeahead/_typeahead.jsx +9 -1
  95. data/app/pb_kits/playbook/pb_typeahead/components/Input.jsx +24 -0
  96. data/app/pb_kits/playbook/pb_typeahead/components/MultiValue.jsx +25 -2
  97. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_default.jsx +1 -0
  98. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_pills.jsx +8 -3
  99. data/app/pb_kits/playbook/pb_user_badge/_user_badge.jsx +1 -1
  100. data/app/pb_kits/playbook/react_rails_kits.js +4 -0
  101. data/app/pb_kits/playbook/utilities/test-utils.js +6 -0
  102. data/lib/playbook/version.rb +2 -1
  103. metadata +75 -35
  104. data/app/pb_kits/playbook/pb_form/form_builder/action_area.html.erb +0 -3
@@ -4,7 +4,9 @@ import { AvatarActionButton } from '../../'
4
4
  const AvatarActionButtonOnClick = (props) => (
5
5
  <div className="pb--doc-demo-row">
6
6
  <AvatarActionButton
7
+ imageAlt="Sophia Carden"
7
8
  imageUrl="https://randomuser.me/api/portraits/women/8.jpg"
9
+ linkAriaLabel="Alert Sophia Carden"
8
10
  linkUrl="https://www.google.com"
9
11
  name="Sophia Carden"
10
12
  onClick={() => alert('clicked!')}
@@ -1,9 +1,11 @@
1
1
  <div class="pb--doc-demo-row">
2
2
 
3
3
  <%= pb_rails("avatar_action_button", props: {
4
+ link_aria_label: "Alert Sophia Carden",
4
5
  name: "Sophia Carden",
5
6
  id: "clickable",
6
7
  link_url: "http://www.google.com",
8
+ image_alt: "Sophia Carden",
7
9
  image_url: "https://randomuser.me/api/portraits/women/8.jpg",
8
10
  }) %>
9
11
 
@@ -1,25 +1,33 @@
1
1
  <div class="pb--doc-demo-row">
2
2
 
3
3
  <%= pb_rails("avatar_action_button", props: {
4
+ link_aria_label: "Sophia Carden",
4
5
  name: "Sophia Carden",
6
+ image_alt: "Sophia Carden",
5
7
  image_url: "https://randomuser.me/api/portraits/women/8.jpg",
6
8
  placement: "bottom_left"
7
9
  }) %>
8
10
 
9
11
  <%= pb_rails("avatar_action_button", props: {
12
+ link_aria_label: "Sophia Carden",
10
13
  name: "Sophia Carden",
14
+ image_alt: "Sophia Carden",
11
15
  image_url: "https://randomuser.me/api/portraits/women/8.jpg",
12
16
  placement: "bottom_right"
13
17
  }) %>
14
18
 
15
19
  <%= pb_rails("avatar_action_button", props: {
20
+ link_aria_label: "Sophia Carden",
16
21
  name: "Sophia Carden",
22
+ image_alt: "Sophia Carden",
17
23
  image_url: "https://randomuser.me/api/portraits/women/8.jpg",
18
24
  placement: "top_left"
19
25
  }) %>
20
26
 
21
27
  <%= pb_rails("avatar_action_button", props: {
28
+ link_aria_label: "Sophia Carden",
22
29
  name: "Sophia Carden",
30
+ image_alt: "Sophia Carden",
23
31
  image_url: "https://randomuser.me/api/portraits/women/8.jpg",
24
32
  placement: "top_right"
25
33
  }) %>
@@ -4,25 +4,33 @@ import { AvatarActionButton } from '../../'
4
4
  const AvatarActionButtonPlacement = (props) => (
5
5
  <div className="pb--doc-demo-row">
6
6
  <AvatarActionButton
7
+ imageAlt="Sophia Carden"
7
8
  imageUrl="https://randomuser.me/api/portraits/women/8.jpg"
9
+ linkAriaLabel="Sophia Carden"
8
10
  name="Sophia Carden"
9
11
  placement="bottom_left"
10
12
  {...props}
11
13
  />
12
14
  <AvatarActionButton
15
+ imageAlt="Sophia Carden"
13
16
  imageUrl="https://randomuser.me/api/portraits/women/8.jpg"
17
+ linkAriaLabel="Sophia Carden"
14
18
  name="Sophia Carden"
15
19
  placement="bottom_right"
16
20
  {...props}
17
21
  />
18
22
  <AvatarActionButton
23
+ imageAlt="Sophia Carden"
19
24
  imageUrl="https://randomuser.me/api/portraits/women/8.jpg"
25
+ linkAriaLabel="Sophia Carden"
20
26
  name="Sophia Carden"
21
27
  placement="top_left"
22
28
  {...props}
23
29
  />
24
30
  <AvatarActionButton
31
+ imageAlt="Sophia Carden"
25
32
  imageUrl="https://randomuser.me/api/portraits/women/8.jpg"
33
+ linkAriaLabel="Sophia Carden"
26
34
  name="Sophia Carden"
27
35
  placement="top_right"
28
36
  {...props}
@@ -1,8 +1,10 @@
1
1
  <div class="pb--doc-demo-row">
2
2
 
3
3
  <%= pb_rails("avatar_action_button", props: {
4
+ link_aria_label: "Sophia Carden",
4
5
  name: "Sophia Carden",
5
6
  link_url: "http://www.google.com",
7
+ image_alt: "Sophia Carden",
6
8
  image_url: "https://randomuser.me/api/portraits/women/8.jpg",
7
9
  tooltip_text: "Tooltip Text",
8
10
  tooltip_id: "avatar_1",
@@ -0,0 +1,31 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import AvatarActionButton from './_avatar_action_button'
5
+
6
+ const imageUrl = 'https://randomuser.me/api/portraits/women/8.jpg',
7
+ testId = 'scarden',
8
+ name = 'Sophia Carden',
9
+ imageAlt = 'Sophia Carden Profile'
10
+
11
+ test('loads the given image url and name', () => {
12
+ render(
13
+ <AvatarActionButton
14
+ data={{ testid: testId }}
15
+ imageAlt={imageAlt}
16
+ imageUrl={imageUrl}
17
+ linkAriaLabel={name}
18
+ name={name}
19
+ />
20
+ )
21
+
22
+ const kit = screen.getByTestId(testId)
23
+ const image = screen.getByAltText(imageAlt)
24
+ const link = kit.children[0]
25
+
26
+ expect(kit).toHaveClass('pb_avatar_action_button_kit_add_bottom_left_md')
27
+ expect(image).toHaveAttribute('data-src', imageUrl)
28
+ expect(image).toHaveAttribute('src', imageUrl)
29
+ expect(image).toHaveAttribute('alt', imageAlt)
30
+ expect(link).toHaveAttribute('aria-label', name)
31
+ })
@@ -3,6 +3,7 @@
3
3
  import React from 'react'
4
4
  import classnames from 'classnames'
5
5
  import { globalProps } from '../utilities/globalProps.js'
6
+ import { Icon } from '../'
6
7
 
7
8
  import {
8
9
  buildAriaProps,
@@ -13,8 +14,15 @@ import {
13
14
  type BadgeProps = {
14
15
  aria?: object,
15
16
  className?: string,
17
+ closeProps?: {
18
+ onClick?: EventHandler,
19
+ onMouseDown?: EventHandler,
20
+ onTouchEnd?: EventHandler,
21
+ },
16
22
  data?: object,
17
23
  id?: string,
24
+ removeIcon?: Boolean,
25
+ removeOnClick?: EventHandler,
18
26
  rounded?: boolean,
19
27
  text?: string,
20
28
  variant?: "error" | "info" | "neutral" | "primary" | "success" | "warning",
@@ -23,8 +31,11 @@ const Badge = (props: BadgeProps) => {
23
31
  const {
24
32
  aria = {},
25
33
  className,
34
+ closeProps = {},
26
35
  data = {},
27
36
  id,
37
+ removeIcon = false,
38
+ removeOnClick = () => {},
28
39
  rounded = false,
29
40
  text,
30
41
  variant = 'neutral',
@@ -44,7 +55,21 @@ const Badge = (props: BadgeProps) => {
44
55
  className={css}
45
56
  id={id}
46
57
  >
47
- <span>{text}</span>
58
+ <span>
59
+ <If condition={removeIcon}>
60
+ <span
61
+ onClick={removeOnClick}
62
+ style={{ cursor: 'pointer' }}
63
+ {...closeProps}
64
+ >
65
+ <Icon
66
+ fixedWidth
67
+ icon="times"
68
+ />
69
+ </span>
70
+ </If>
71
+ {text}
72
+ </span>
48
73
  </div>
49
74
  )
50
75
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import React from 'react'
4
4
  import classnames from 'classnames'
5
+ import { buildDataProps } from '../utilities/props'
5
6
  import { globalProps } from '../utilities/globalProps.js'
6
7
 
7
8
  import Icon from '../pb_icon/_icon.jsx'
@@ -13,6 +14,7 @@ type ButtonPropTypes = {
13
14
  },
14
15
  children?: array<React.ReactChild>,
15
16
  className?: string | array<string>,
17
+ data?: object,
16
18
  disabled?: boolean,
17
19
  fixedWidth?: boolean,
18
20
  fullWidth?: boolean,
@@ -69,6 +71,7 @@ const Button = (props: ButtonPropTypes) => {
69
71
  const {
70
72
  children,
71
73
  className,
74
+ data = {},
72
75
  disabled,
73
76
  icon = null,
74
77
  id,
@@ -82,6 +85,7 @@ const Button = (props: ButtonPropTypes) => {
82
85
  } = props
83
86
 
84
87
  const buttonAria = buttonAriaProps(props)
88
+ const dataProps = buildDataProps(data)
85
89
  const css = classnames(
86
90
  buttonClassName(props),
87
91
  globalProps(props),
@@ -111,6 +115,7 @@ const Button = (props: ButtonPropTypes) => {
111
115
  <If condition={link !== null}>
112
116
  <a
113
117
  {...buttonAria}
118
+ {...dataProps}
114
119
  className={css}
115
120
  href={link}
116
121
  id={id}
@@ -122,6 +127,7 @@ const Button = (props: ButtonPropTypes) => {
122
127
  <Else />
123
128
  <button
124
129
  {...buttonAria}
130
+ {...dataProps}
125
131
  className={css}
126
132
  disabled={disabled}
127
133
  id={id}
@@ -0,0 +1,91 @@
1
+
2
+ import React from 'react'
3
+ import { appendAlert, fireEvent, render, screen, waitFor } from '../utilities/test-utils'
4
+
5
+ import Button from './_button'
6
+
7
+ // Primary Test Variables
8
+ const htmlType = 'submit',
9
+ text = 'Button Text',
10
+ value = '1234'
11
+
12
+ test('passes type, text, and value props to button', () => {
13
+ render(
14
+ <>
15
+ <Button
16
+ data={{ testid: 'primary-test' }}
17
+ htmlType={htmlType}
18
+ text={text}
19
+ value={value}
20
+ />
21
+ </>
22
+ )
23
+
24
+ const kit = screen.getByTestId('primary-test')
25
+ const content = screen.getByText(text)
26
+
27
+ expect(kit).toHaveClass('pb_button_kit_primary_inline_enabled')
28
+ expect(kit).toHaveAttribute('type', htmlType)
29
+ expect(kit).toHaveAttribute('value', value)
30
+ expect(content).toHaveTextContent(text)
31
+ })
32
+
33
+ // Link Test Variables
34
+ const link = 'https://www.google.com'
35
+
36
+ test('adds link to button', () => {
37
+ render(
38
+ <Button
39
+ data={{ testid: 'link-test' }}
40
+ link={link}
41
+ />
42
+ )
43
+
44
+ const kit = screen.getByTestId('link-test')
45
+
46
+ expect(kit).toHaveAttribute('href', link)
47
+ })
48
+
49
+ test('button with secondary variant', () => {
50
+ render(
51
+ <Button
52
+ data={{ testid: 'variant-test' }}
53
+ variant="secondary"
54
+ />
55
+ )
56
+
57
+ const kit = screen.getByTestId('variant-test')
58
+
59
+ expect(kit).toHaveClass('pb_button_kit_secondary_inline_enabled')
60
+ expect(kit).toHaveAttribute('type', 'button')
61
+ })
62
+
63
+ test('disable prop', () => {
64
+ render(
65
+ <Button
66
+ data={{ testid: 'disable-test' }}
67
+ disabled
68
+ />
69
+ )
70
+
71
+ const kit = screen.getByTestId('disable-test')
72
+
73
+ expect(kit).toBeDisabled()
74
+ })
75
+
76
+ test('click event', async () => {
77
+ render(
78
+ <Button
79
+ data={{ testid: 'click-test' }}
80
+ onClick={() => appendAlert('clicked button!')}
81
+ />
82
+ )
83
+
84
+ const kit = screen.getByTestId('click-test')
85
+
86
+ fireEvent.click(kit)
87
+
88
+ await waitFor(() => screen.getByText('clicked button!'))
89
+
90
+ expect(screen.getByText('clicked button!')).toBeInTheDocument()
91
+ })
@@ -30,7 +30,6 @@ const ButtonDefault = (props) => (
30
30
  {...props}
31
31
  />
32
32
  </div>
33
-
34
33
  )
35
34
 
36
35
  export default ButtonDefault
@@ -0,0 +1,46 @@
1
+ import React from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+
4
+ import { Button, ButtonToolbar } from '../'
5
+
6
+ test('default test', () => {
7
+ render(
8
+ <ButtonToolbar
9
+ data={{ testid: 'default-test' }}
10
+ >
11
+ <Button
12
+ data={{ testid: 'child-button' }}
13
+ text="Test"
14
+ />
15
+ </ButtonToolbar>
16
+ )
17
+
18
+ const kit = screen.getByTestId('default-test')
19
+ const child = screen.getByTestId('child-button')
20
+
21
+ expect(kit).toHaveClass('pb_button_toolbar_kit_horizontal_primary')
22
+ expect(kit).toContainElement(child)
23
+ expect(child).toHaveClass('pb_button_kit_primary_inline_enabled')
24
+ })
25
+
26
+ test('variant and orientation props', () => {
27
+ render(
28
+ <ButtonToolbar
29
+ data={{ testid: 'second-test' }}
30
+ orientation="vertical"
31
+ variant="secondary"
32
+ >
33
+ <Button
34
+ data={{ testid: 'child-button' }}
35
+ text="Create"
36
+ variant="secondary"
37
+ />
38
+ </ButtonToolbar>
39
+ )
40
+
41
+ const kit = screen.getByTestId('second-test')
42
+ const child = screen.getByTestId('child-button')
43
+
44
+ expect(kit).toHaveClass('pb_button_toolbar_kit_vertical_secondary')
45
+ expect(child).toHaveClass('pb_button_kit_secondary_inline_enabled')
46
+ })
@@ -12,7 +12,7 @@ type CaptionProps = {
12
12
  data?: object,
13
13
  id?: string,
14
14
  size?: "xs" | "sm" | "md" | "lg" | "xl",
15
- tag?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div",
15
+ tag?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div" | "caption",
16
16
  text?: string,
17
17
  variant?: null | "link",
18
18
  }
@@ -29,7 +29,8 @@ const Caption = (props: CaptionProps) => {
29
29
  text,
30
30
  variant = null,
31
31
  } = props
32
- const Tag = `${tag}`
32
+ const tagOptions = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span', 'div', 'caption']
33
+ const Tag = tagOptions.includes(tag) ? tag : 'div'
33
34
 
34
35
  const ariaProps = buildAriaProps(aria)
35
36
  const dataProps = buildDataProps(data)
@@ -7,7 +7,7 @@ module Playbook
7
7
  values: %w[xs sm md base lg xl],
8
8
  default: "md"
9
9
  prop :tag, type: Playbook::Props::Enum,
10
- values: %w[h1 h2 h3 h4 h5 h6 p span div],
10
+ values: %w[h1 h2 h3 h4 h5 h6 p span div caption],
11
11
  default: "div"
12
12
  prop :text
13
13
  prop :variant, type: Playbook::Props::Enum,
@@ -3,14 +3,16 @@
3
3
  import React from 'react'
4
4
  import { get } from 'lodash'
5
5
  import classnames from 'classnames'
6
- import { buildCss } from '../utilities/props'
6
+ import { buildAriaProps, buildCss, buildDataProps } from '../utilities/props'
7
7
  import { globalProps } from '../utilities/globalProps.js'
8
8
 
9
9
  type CardPropTypes = {
10
+ aria?: object,
10
11
  borderNone?: boolean,
11
12
  borderRadius?: "xs" | "sm" | "md" | "lg" | "xl" | "none" | "rounded",
12
13
  children: array<React.ReactNode> | React.ReactNode,
13
14
  className?: string,
15
+ data?: object,
14
16
  highlight?: {
15
17
  position?: "side" | "top",
16
18
  color?: string,
@@ -18,6 +20,7 @@ type CardPropTypes = {
18
20
  padding?: string,
19
21
  selected?: boolean,
20
22
  shadow?: "none" | "deep" | "deeper" | "deepest",
23
+ tag?: "div" | "section" | "footer" | "header" | "article" | "aside" | "main" | "nav",
21
24
  }
22
25
 
23
26
  type CardHeaderProps = {
@@ -62,13 +65,16 @@ const Body = (props: CardBodyProps) => {
62
65
 
63
66
  const Card = (props: CardPropTypes) => {
64
67
  const {
68
+ aria = {},
65
69
  borderNone = false,
66
70
  borderRadius = 'md',
67
71
  children,
68
72
  className,
73
+ data = {},
69
74
  highlight = {},
70
75
  selected = false,
71
76
  shadow = 'none',
77
+ tag = 'div',
72
78
  padding = 'md',
73
79
  } = props
74
80
  const borderCSS = borderNone == true ? 'border_none' : ''
@@ -78,6 +84,8 @@ const Card = (props: CardPropTypes) => {
78
84
  [`highlight_${highlight.position}`]: highlight.position,
79
85
  [`highlight_${highlight.color}`]: highlight.color,
80
86
  })
87
+ const ariaProps = buildAriaProps(aria)
88
+ const dataProps = buildDataProps(data)
81
89
 
82
90
  // coerce to array
83
91
  const cardChildren =
@@ -93,11 +101,18 @@ const Card = (props: CardPropTypes) => {
93
101
 
94
102
  const nonHeaderChildren = cardChildren.filter((child) => (get(child, 'type.displayName') !== 'Header'))
95
103
 
104
+ const tagOptions = ['div', 'section', 'footer', 'header', 'article', 'aside', 'main', 'nav']
105
+ const Tag = tagOptions.includes(tag) ? tag : 'div'
106
+
96
107
  return (
97
- <div className={classnames(cardCss, globalProps(props, { padding }), className)}>
108
+ <Tag
109
+ {...ariaProps}
110
+ {...dataProps}
111
+ className={classnames(cardCss, globalProps(props, { padding }), className)}
112
+ >
98
113
  {subComponentTags('Header')}
99
114
  {nonHeaderChildren}
100
- </div>
115
+ </Tag>
101
116
  )
102
117
  }
103
118