playbook_ui 11.19.0 → 11.20.0.pre.alpha.focus1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_body/_body.scss +10 -1
  3. data/app/pb_kits/playbook/pb_body/docs/_body_styled.html.erb +9 -0
  4. data/app/pb_kits/playbook/pb_body/docs/_body_styled.jsx +20 -0
  5. data/app/pb_kits/playbook/pb_body/docs/_body_styled.md +1 -0
  6. data/app/pb_kits/playbook/pb_body/docs/example.yml +2 -0
  7. data/app/pb_kits/playbook/pb_body/docs/index.js +1 -0
  8. data/app/pb_kits/playbook/pb_button/_button.scss +0 -5
  9. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +33 -2
  10. data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.html.erb +2 -2
  11. data/app/pb_kits/playbook/pb_button/docs/_button_icon_options.jsx +2 -0
  12. data/app/pb_kits/playbook/pb_button/docs/_button_link.html.erb +3 -3
  13. data/app/pb_kits/playbook/pb_button/docs/_button_link.jsx +3 -0
  14. data/app/pb_kits/playbook/pb_button/docs/_button_loading.html.erb +3 -3
  15. data/app/pb_kits/playbook/pb_button/docs/_button_loading.jsx +3 -0
  16. data/app/pb_kits/playbook/pb_button/docs/_button_size.html.erb +3 -3
  17. data/app/pb_kits/playbook/pb_button/docs/_button_size.jsx +3 -0
  18. data/app/pb_kits/playbook/pb_checkbox/_checkbox.tsx +7 -7
  19. data/app/pb_kits/playbook/pb_dialog/_dialog.scss +69 -3
  20. data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +1 -1
  21. data/app/pb_kits/playbook/pb_dialog/dialog.rb +1 -1
  22. data/app/pb_kits/playbook/pb_dialog/dialog.test.jsx +12 -0
  23. data/app/pb_kits/playbook/pb_file_upload/_file_upload.tsx +5 -4
  24. data/app/pb_kits/playbook/pb_file_upload/docs/_description.md +2 -3
  25. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_custom_message.jsx +40 -0
  26. data/app/pb_kits/playbook/pb_file_upload/docs/example.yml +2 -2
  27. data/app/pb_kits/playbook/pb_file_upload/docs/index.js +1 -0
  28. data/app/pb_kits/playbook/pb_file_upload/fileupload.test.js +12 -0
  29. data/app/pb_kits/playbook/pb_radio/_radio.tsx +4 -4
  30. data/app/pb_kits/playbook/pb_select/_select.scss +1 -1
  31. data/app/pb_kits/playbook/pb_selectable_card/{_selectable_card.jsx → _selectable_card.tsx} +47 -42
  32. data/app/pb_kits/playbook/pb_selectable_card/docs/_selectable_card_default.jsx +1 -2
  33. data/app/pb_kits/playbook/pb_selectable_card/docs/_selectable_card_single_select.jsx +1 -1
  34. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.test.js +185 -0
  35. data/app/pb_kits/playbook/pb_selectable_icon/{_selectable_icon.jsx → _selectable_icon.tsx} +29 -32
  36. data/app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_default.jsx +1 -5
  37. data/app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_single_select.jsx +1 -4
  38. data/app/pb_kits/playbook/pb_selectable_icon/selectable_icon.test.js +148 -0
  39. data/app/pb_kits/playbook/tokens/_accessibility.scss +6 -0
  40. data/app/pb_kits/playbook/tokens/_colors.scss +3 -1
  41. data/lib/playbook/version.rb +2 -2
  42. metadata +13 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb389dc6dd09b729a058710f9dbaffccf1c70f4994dabad0e8c877fdfb15160a
4
- data.tar.gz: 5f8d2f82abeccdb16d5a8e0896db8c9c701b524f1fdfd86ac0cdb3e296dc5b16
3
+ metadata.gz: dd5b6e17a1e5ff8a0149e8d809b67ebd4c1bd6ade257db72ed9fe4716c7f0488
4
+ data.tar.gz: 4f6b2edf940d88f2113516a34e7288c18e68bde88cb367a49e3407c8e5d506a9
5
5
  SHA512:
6
- metadata.gz: 4ef7df4f5c65d61d144d0b552b11c7205451cb77d50dff97c181af2175de03374ee98d18505c0765b219b217caef55f5714425585a27f7d0d2597efa50a1af21
7
- data.tar.gz: '0068b2d612e89e7932399e089b1478faac10bd3a710e29ef4f555b6e57060236ff0a4f346c15ae61bd08e2a925b136174901803b55a066d1c1d6397b1379f1ee'
6
+ metadata.gz: 7400acc711d9fa10b999850ed8c02282b3e6f9dcee98745dec7df79bdb7e57842d3751cae96b9d248ac08bf807daa035af6b429b3ea93c4d7157f6bf0e156392
7
+ data.tar.gz: f54bc46b74b4f15ad295303b73413b8f2e7e17adc078420b2b21970f470770ee2dcdc9203d58fec00fb28e826f8e7f0a4065c28f8e798efd60d3d582250e7e7e
@@ -1,4 +1,5 @@
1
1
  @import "./body_mixins";
2
+ @import "../tokens/titles";
2
3
 
3
4
  [class^=pb_body_kit]{
4
5
  @include pb_body($text_lt_default);
@@ -12,13 +13,21 @@
12
13
  }
13
14
  }
14
15
  }
15
-
16
16
  @each $dark_color_name, $dark_color_value in $pb_dark_body_colors{
17
17
  &[class*=_#{$dark_color_name}][class*=dark]{
18
18
  @include pb_body($dark_color_value);
19
19
  }
20
20
  }
21
+ b, strong {
22
+ @include pb_title_4
23
+ }
21
24
 
25
+ a {
26
+ color: $primary;
27
+ &:hover {
28
+ color: $text_lt_default;
29
+ }
30
+ }
22
31
  @each $status_name, $status_value in $pb_body_status {
23
32
  &[class*=#{$status_name}] {
24
33
  @include pb_body($status_value);
@@ -0,0 +1,9 @@
1
+ <%= pb_rails("body") do %>
2
+ <b>This text is using the <%="<b>"%> tag</b>
3
+ <br />
4
+ <br />
5
+ <strong>This text is using the <%="<strong>"%> tag</strong>
6
+ <br />
7
+ <br />
8
+ <a href="#">This text is using the <%="<a>"%> tag</a>
9
+ <% end %>
@@ -0,0 +1,20 @@
1
+ import React from 'react'
2
+ import { Body } from '../..'
3
+
4
+ const BodyStyled = (props) => {
5
+ return (
6
+ <div>
7
+ <Body {...props}>
8
+ <b>{"This text is using the <b> tag"}</b>
9
+ <br />
10
+ <br />
11
+ <strong>{"This text is using the <strong> tag"}</strong>
12
+ <br />
13
+ <br />
14
+ <a href="#">{"This text is using the <a> tag"}</a>
15
+ </Body>
16
+ </div>
17
+ )
18
+ }
19
+
20
+ export default BodyStyled
@@ -0,0 +1 @@
1
+ Playbook styles the `b`, `strong` and `a` tags within the body kit to match Playbook's design system.
@@ -2,6 +2,8 @@ examples:
2
2
  rails:
3
3
  - body_light: Default
4
4
  - body_block: Block
5
+ - body_styled: Styled b/strong/a tags
5
6
  react:
6
7
  - body_light: Default
7
8
  - body_block: Block
9
+ - body_styled: Styled b/strong/a tags
@@ -1,2 +1,3 @@
1
1
  export { default as BodyLight } from './_body_light.jsx'
2
2
  export { default as BodyBlock } from './_body_block.jsx'
3
+ export { default as BodyStyled } from './_body_styled.jsx'
@@ -29,11 +29,6 @@ $pb_button_sizes: (
29
29
  }
30
30
  &[class*=_link] {
31
31
  @include pb_button_link;
32
- @media (hover:hover) {
33
- &:hover {
34
- color: $text_lt_default;
35
- }
36
- }
37
32
  }
38
33
 
39
34
  // Disabled =================
@@ -5,6 +5,7 @@
5
5
  @import "../tokens/spacing";
6
6
  @import "../tokens/transition";
7
7
  @import "../tokens/typography";
8
+ @import "../tokens/accessibility";
8
9
 
9
10
  $pb_button_size: 40px;
10
11
  $pb_button_v_padding: 7px;
@@ -62,11 +63,12 @@ $pb_button_border_width: 0px;
62
63
  margin-left: $space_xs;
63
64
  }
64
65
 
65
- &:hover, &:focus {
66
+ &:hover {
66
67
  outline: none;
67
-
68
68
  }
69
69
 
70
+ @include focus;
71
+
70
72
  &:active {
71
73
  outline: none;
72
74
  border-width: $pb_button_border_width;
@@ -86,6 +88,10 @@ $pb_button_border_width: 0px;
86
88
  &:hover {
87
89
  @include pb_button_hover;
88
90
  }
91
+ &:active {
92
+ transition: none;
93
+ @include pb_button_variant($primary_action);
94
+ }
89
95
  }
90
96
  }
91
97
 
@@ -97,6 +103,10 @@ $pb_button_border_width: 0px;
97
103
  &:hover {
98
104
  @include pb_button_hover(rgba($primary_action, $opacity_3));
99
105
  }
106
+ &:active {
107
+ transition: none;
108
+ @include pb_button_variant(rgba($primary_action, 0.05), $primary_action);
109
+ }
100
110
  }
101
111
  }
102
112
 
@@ -107,6 +117,11 @@ $pb_button_border_width: 0px;
107
117
  @media (hover:hover) {
108
118
  &:hover {
109
119
  @include pb_button_hover($transparent);
120
+ color: $text_lt_default;
121
+ }
122
+ &:active {
123
+ transition: none;
124
+ @include pb_button_variant($transparent, $primary_action);
110
125
  }
111
126
  }
112
127
  }
@@ -116,6 +131,9 @@ $pb_button_border_width: 0px;
116
131
  $disabled_color: rgba($charcoal, $opacity_5);
117
132
  @include pb_button_variant(rgba($slate, $opacity_4), $disabled_color);
118
133
  pointer-events: none;
134
+ &:focus {
135
+ outline: none;
136
+ }
119
137
  }
120
138
 
121
139
  // Block =======================
@@ -145,6 +163,10 @@ $pb_button_border_width: 0px;
145
163
  &:hover {
146
164
  @include pb_button_hover($bg: darken($primary_action, $pb_button_hover_darken));
147
165
  }
166
+ &:active {
167
+ transition: none;
168
+ @include pb_button_variant($primary_action);
169
+ }
148
170
  }
149
171
  }
150
172
 
@@ -156,6 +178,10 @@ $pb_button_border_width: 0px;
156
178
  &:hover {
157
179
  @include pb_button_hover(rgba($primary_action, $opacity_2));
158
180
  }
181
+ &:active {
182
+ transition: none;
183
+ @include pb_button_variant(rgba($white, 0.2), $white);
184
+ }
159
185
  }
160
186
  }
161
187
 
@@ -166,6 +192,11 @@ $pb_button_border_width: 0px;
166
192
  @media (hover:hover) {
167
193
  &:hover {
168
194
  @include pb_button_hover($transparent);
195
+ color: rgba($white, $opacity_6)
196
+ }
197
+ &:active {
198
+ transition: none;
199
+ @include pb_button_variant($transparent, $white);
169
200
  }
170
201
  }
171
202
  }
@@ -1,2 +1,2 @@
1
- <%= pb_rails("button", props: { icon: "plus", text: "Icon on Left" }) %>
2
- <%= pb_rails("button", props: { icon: "chevron-right", icon_right: true, text: "Icon on Right" }) %>
1
+ <%= pb_rails("button", props: { icon: "plus", text: "Icon on Left", margin_right: "lg" }) %>
2
+ <%= pb_rails("button", props: { icon: "chevron-right", icon_right: true, text: "Icon on Right", margin_right: "lg" }) %>
@@ -6,6 +6,7 @@ const ButtonIconOptions = (props) => (
6
6
  <Button
7
7
  fixedWidth
8
8
  icon='plus'
9
+ marginRight='lg'
9
10
  text="Icon on Left"
10
11
  {...props}
11
12
  />
@@ -14,6 +15,7 @@ const ButtonIconOptions = (props) => (
14
15
  fixedWidth
15
16
  icon='chevron-right'
16
17
  iconRight
18
+ marginRight='lg'
17
19
  text="Icon on Right"
18
20
  {...props}
19
21
  />
@@ -1,3 +1,3 @@
1
- <%= pb_rails("button", props: { text: "A Tag Button", aria: { label: "Link to Google" }, tag: "a", link: "http://google.com" }) %>
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" }) %>
3
- <%= pb_rails("button", props: { text: "A Tag Button Disabled", aria: { label: "Disabled link to Google" }, disabled: true, link: "http://google.com" }) %>
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" }) %>
@@ -6,6 +6,7 @@ const ButtonLink = (props) => (
6
6
  <Button
7
7
  aria={{ label: 'Link to Google' }}
8
8
  link="https://google.com"
9
+ marginRight='lg'
9
10
  text="A Tag Button"
10
11
  {...props}
11
12
  />
@@ -13,6 +14,7 @@ const ButtonLink = (props) => (
13
14
  <Button
14
15
  aria={{ label: 'Link to Google in new window' }}
15
16
  link="https://google.com"
17
+ marginRight='lg'
16
18
  newWindow
17
19
  text="Open in New Window"
18
20
  {...props}
@@ -22,6 +24,7 @@ const ButtonLink = (props) => (
22
24
  aria={{ label: 'Disabled link to Google' }}
23
25
  disabled
24
26
  link="https://google.com"
27
+ marginRight='lg'
25
28
  text="A Tag Button Disabled"
26
29
  {...props}
27
30
  />
@@ -1,3 +1,3 @@
1
- <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", loading: true }) %>
2
- <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", variant: "secondary", loading: true }) %>
3
- <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", variant: "link", loading: true }) %>
1
+ <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", loading: true, margin_right: "lg" }) %>
2
+ <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", variant: "secondary", loading: true, margin_right: "lg" }) %>
3
+ <%= pb_rails("button", props: { aria: { label: "Loading" }, text: "Button Primary", variant: "link", loading: true, margin_right: "lg" }) %>
@@ -6,6 +6,7 @@ const ButtonLoading = (props) => (
6
6
  <Button
7
7
  aria={{ label: 'Loading' }}
8
8
  loading
9
+ marginRight='lg'
9
10
  text="Button Primary"
10
11
  {...props}
11
12
  />
@@ -13,6 +14,7 @@ const ButtonLoading = (props) => (
13
14
  <Button
14
15
  aria={{ label: 'Loading' }}
15
16
  loading
17
+ marginRight='lg'
16
18
  text="Button Secondary"
17
19
  variant="secondary"
18
20
  {...props}
@@ -21,6 +23,7 @@ const ButtonLoading = (props) => (
21
23
  <Button
22
24
  aria={{ label: 'Loading' }}
23
25
  loading
26
+ marginRight='lg'
24
27
  text="A Tag Button Disabled"
25
28
  variant="link"
26
29
  {...props}
@@ -1,3 +1,3 @@
1
- <%= pb_rails("button", props: { text: "Button sm size", size: "sm" }) %>
2
- <%= pb_rails("button", props: { text: "Button md size", size: "md" }) %>
3
- <%= pb_rails("button", props: { text: "Button lg size", size: "lg" }) %>
1
+ <%= pb_rails("button", props: { text: "Button sm size", size: "sm", margin_right: "lg" }) %>
2
+ <%= pb_rails("button", props: { text: "Button md size", size: "md", margin_right: "lg" }) %>
3
+ <%= pb_rails("button", props: { text: "Button lg size", size: "lg", margin_right: "lg" }) %>
@@ -4,18 +4,21 @@ import { Button } from '../../'
4
4
  const ButtonSize = (props) => (
5
5
  <div>
6
6
  <Button
7
+ marginRight='lg'
7
8
  size="sm"
8
9
  text="Button sm size"
9
10
  {...props}
10
11
  />
11
12
  {' '}
12
13
  <Button
14
+ marginRight='lg'
13
15
  size="md"
14
16
  text="Button md size"
15
17
  {...props}
16
18
  />
17
19
  {' '}
18
20
  <Button
21
+ marginRight='lg'
19
22
  size="lg"
20
23
  text="Button lg size"
21
24
  {...props}
@@ -8,18 +8,18 @@ import { globalProps, GlobalProps } from '../utilities/globalProps'
8
8
  type CheckboxProps = {
9
9
  aria?: {[key: string]: string},
10
10
  checked?: boolean,
11
- children: Node,
11
+ children?: React.ReactChild[] | React.ReactChild,
12
12
  className?: string,
13
13
  dark?: boolean,
14
14
  data?: {[key: string]: string},
15
15
  error?: boolean,
16
16
  id?: string,
17
17
  indeterminate?: boolean,
18
- name: string,
19
- onChange: (event: React.FormEvent<HTMLInputElement>) => void,
20
- tabIndex: number,
21
- text: string,
22
- value: string,
18
+ name?: string,
19
+ onChange?: (event: React.FormEvent<HTMLInputElement>) => void,
20
+ tabIndex?: number,
21
+ text?: string,
22
+ value?: string,
23
23
  } & GlobalProps
24
24
 
25
25
  const Checkbox = (props: CheckboxProps): JSX.Element => {
@@ -34,7 +34,7 @@ const Checkbox = (props: CheckboxProps): JSX.Element => {
34
34
  id,
35
35
  indeterminate = false,
36
36
  name = '',
37
- onChange = () => {},
37
+ onChange = () => { void 0 },
38
38
  tabIndex,
39
39
  text = '',
40
40
  value = '',
@@ -9,7 +9,7 @@
9
9
 
10
10
 
11
11
  // Dialog Animations
12
-
12
+ // Dialog Animations for fading in and out from the center
13
13
  @keyframes modalFadeIn {
14
14
  from {
15
15
  transform: translate3d(0, -100%, 0);
@@ -32,6 +32,53 @@
32
32
  }
33
33
  }
34
34
 
35
+ // Dialog Animations for fading in and out from the left side
36
+ @keyframes modalFadeInLeft {
37
+ from {
38
+ transform: translate3d(-100%, 0, 0);
39
+ opacity: 0;
40
+ }
41
+ to {
42
+ transform: translate3d(0, 0, 0);
43
+ opacity: 1;
44
+ }
45
+ }
46
+
47
+ @keyframes modalFadeOutLeft {
48
+ from {
49
+ transform: translate3d(0, 0, 0);
50
+ opacity: 1;
51
+ }
52
+ to {
53
+ transform: translate3d(-50%, 0, 0);
54
+ opacity: 0;
55
+ }
56
+ }
57
+
58
+
59
+ // Dialog Animations for fading in and out from the right side
60
+ @keyframes modalFadeInRight {
61
+ from {
62
+ transform: translate3d(100%, 0, 0);
63
+ opacity: 0;
64
+ }
65
+ to {
66
+ transform: translate3d(0, 0, 0);
67
+ opacity: 1;
68
+ }
69
+ }
70
+
71
+ @keyframes modalFadeOutRight {
72
+ from {
73
+ transform: translate3d(0, 0, 0);
74
+ opacity: 1;
75
+ }
76
+ to {
77
+ transform: translate3d(50%, 0, 0);
78
+ opacity: 0;
79
+ }
80
+ }
81
+
35
82
  @keyframes overlayFade {
36
83
  from {
37
84
  opacity: 0;
@@ -63,7 +110,7 @@
63
110
  $medium: 500px;
64
111
  $large: 800px;
65
112
  $xlarge: 1150px;
66
- $animation-duration: 0.2s;
113
+ $animation-duration: .2s;
67
114
  $z-index: 100;
68
115
  $opacity_visible: 1;
69
116
  $opacity_hidden: 0;
@@ -87,6 +134,24 @@
87
134
  outline: none;
88
135
  animation-timing-function: $easeInOutQuint;
89
136
 
137
+ &[class*="_left"] {
138
+ animation-name: modalFadeInLeft;
139
+ &[class*="_before_close"] {
140
+ animation-name: modalFadeOutLeft;
141
+ animation-duration: $animation-duration;
142
+ opacity: $opacity_hidden;
143
+ }
144
+ }
145
+
146
+ &[class*="_right"] {
147
+ animation-name: modalFadeInRight;
148
+ &[class*="_before_close"] {
149
+ animation-name: modalFadeOutRight;
150
+ animation-duration: $animation-duration;
151
+ opacity: $opacity_hidden;
152
+ }
153
+ }
154
+
90
155
  &[class*="_status_size"] {
91
156
  width: $status_size;
92
157
  }
@@ -98,6 +163,7 @@
98
163
  &[class*="_md"] {
99
164
  width: $medium;
100
165
  }
166
+
101
167
 
102
168
  &[class*="_lg"] {
103
169
  width: $large;
@@ -111,7 +177,7 @@
111
177
  opacity: $opacity_visible;
112
178
  }
113
179
 
114
- &_before_close {
180
+ &[class*="_before_close"] {
115
181
  animation-name: modalFadeOut;
116
182
  animation-duration: $animation-duration;
117
183
  opacity: $opacity_hidden;
@@ -71,7 +71,7 @@ const Dialog = (props: DialogProps) => {
71
71
  const ariaProps = buildAriaProps(aria);
72
72
  const dataProps = buildDataProps(data);
73
73
  const dialogClassNames = {
74
- base: classnames("pb_dialog", buildCss("pb_dialog", size)),
74
+ base: classnames("pb_dialog", buildCss("pb_dialog", size, placement)),
75
75
  afterOpen: "pb_dialog_after_open",
76
76
  beforeClose: "pb_dialog_before_close",
77
77
  };
@@ -20,7 +20,7 @@ module Playbook
20
20
  default: ""
21
21
 
22
22
  def classname
23
- generate_classname("pb_dialog pb_dialog_rails pb_dialog_#{size}")
23
+ generate_classname("pb_dialog pb_dialog_rails pb_dialog_#{size}_#{placement}")
24
24
  end
25
25
 
26
26
  def full_height_style
@@ -25,6 +25,7 @@ function DialogTest({ props }) {
25
25
  onClose={close}
26
26
  onConfirm={() => setIsLoading(!isLoading)}
27
27
  opened={isOpen}
28
+ placement="right"
28
29
  portalClassName="portal"
29
30
  size={size}
30
31
  text={text}
@@ -98,3 +99,14 @@ test("renders the buttons", async () => {
98
99
  cleanup()
99
100
  });
100
101
 
102
+ test("renders the right placement dialog", async () => {
103
+
104
+ const { queryByText } = render(<DialogTest />);
105
+
106
+ fireEvent.click(queryByText('Open Dialog'));
107
+
108
+ await waitFor(() => expect(queryByText("Header Title is the Title Prop")));
109
+
110
+ cleanup()
111
+ });
112
+
@@ -12,6 +12,7 @@ import Card from '../pb_card/_card'
12
12
  type FileUploadProps = {
13
13
  accept?: string[],
14
14
  className?: string,
15
+ customMessage?: string,
15
16
  data?: {[key: string]: string | number},
16
17
  acceptedFilesDescription?: string,
17
18
  maxSize?: number,
@@ -28,6 +29,7 @@ const FileUpload = (props: FileUploadProps): React.ReactElement => {
28
29
  accept = null,
29
30
  acceptedFilesDescription = '',
30
31
  className,
32
+ customMessage,
31
33
  data = {},
32
34
  maxSize,
33
35
  onFilesAccepted = noop,
@@ -77,10 +79,9 @@ const FileUpload = (props: FileUploadProps): React.ReactElement => {
77
79
  const dataProps = buildDataProps(data)
78
80
 
79
81
  const getDescription = () => {
80
- let msg = ""
81
- accept === null ? msg += 'Choose a file or drag it here.' : msg += `Choose a file or drag it here. The accepted file types are: ${acceptedFilesDescription || acceptedFileTypes()}.`
82
- if (maxSize) msg += ` ${maxFileSizeText}`
83
- return msg
82
+ return customMessage
83
+ ? customMessage
84
+ : `Choose a file or drag it here.${accept === null ? '' : ` The accepted file types are: ${acceptedFilesDescription || acceptedFileTypes()}.`}${maxSize ? ` ${maxFileSizeText}` : ''}`;
84
85
  }
85
86
 
86
87
  return (
@@ -1,8 +1,7 @@
1
- This kit provides a drag and drop interface for file uploads. Currently, the kit leverages [react-dropzone](https://github.com/react-dropzone/react-dropzone).
1
+ This kit provides a drag and drop interface for file uploads. Currently, the kit leverages [react-dropzone](https://github.com/react-dropzone/react-dropzone).
2
2
 
3
3
  ### Props
4
4
 
5
5
  `accept: [String]` Use this prop to set the list of valid file types
6
+ `customMessage: [String]` Use this prop to set a custom message, replacing the default text
6
7
  `onFilesAccepted: Function` The callback function, providing the list of dropped files
7
-
8
-
@@ -0,0 +1,40 @@
1
+ /* @flow */
2
+
3
+ import React, { useState } from 'react'
4
+ import {
5
+ FileUpload,
6
+ List,
7
+ ListItem,
8
+ } from '../..'
9
+
10
+ const AcceptedFilesList = ({ files }: FileList) => (
11
+ <List>
12
+ {files.map((file) => (
13
+ <ListItem key={file.name}>{file.name}</ListItem>
14
+ ))}
15
+ </List>
16
+ )
17
+
18
+ const FileUploadCustomMessage = (props) => {
19
+ const [filesToUpload, setFilesToUpload] = useState([])
20
+
21
+ const handleOnFilesAccepted = (files) => {
22
+ setFilesToUpload([...filesToUpload, ...files])
23
+ }
24
+
25
+ return (
26
+ <div>
27
+ <AcceptedFilesList
28
+ files={filesToUpload}
29
+ {...props}
30
+ />
31
+ <FileUpload
32
+ customMessage="Playbook is awesome!"
33
+ onFilesAccepted={handleOnFilesAccepted}
34
+ {...props}
35
+ />
36
+ </div>
37
+ )
38
+ }
39
+
40
+ export default FileUploadCustomMessage
@@ -1,10 +1,10 @@
1
1
  examples:
2
2
 
3
3
  rails:
4
-
4
+
5
5
  react:
6
6
  - file_upload_default: Default List of files to upload
7
7
  - file_upload_accept: Accept only certain types of files
8
+ - file_upload_custom_message: Add a custom message
8
9
  - file_upload_custom_description: Add your one accepted files description
9
10
  - file_upload_max_size: Set a file size limit
10
-
@@ -1,4 +1,5 @@
1
1
  export { default as FileUploadDefault } from './_file_upload_default.jsx'
2
2
  export { default as FileUploadAccept } from './_file_upload_accept.jsx'
3
+ export { default as FileUploadCustomMessage } from './_file_upload_custom_message.jsx'
3
4
  export { default as FileUploadCustomDescription } from './_file_upload_custom_description.jsx'
4
5
  export { default as FileUploadMaxSize } from './_file_upload_max_size.jsx'
@@ -38,3 +38,15 @@ test('displays max file size text', () => {
38
38
  const kit = screen.getByTestId(testid)
39
39
  expect(kit).toHaveTextContent('Choose a file or drag it here. Max file size is 1 MB.')
40
40
  })
41
+
42
+ test('displays custom message', () => {
43
+ render(
44
+ <FileUpload
45
+ customMessage={'Hello world!'}
46
+ data={{ testid: testid }}
47
+ />
48
+ )
49
+
50
+ const kit = screen.getByTestId(testid)
51
+ expect(kit).toHaveTextContent('Hello world!')
52
+ })
@@ -10,16 +10,16 @@ type RadioProps = {
10
10
  aria?: {[key: string]: string},
11
11
  alignment?: string,
12
12
  checked?: boolean,
13
- children?: Node,
13
+ children?: React.ReactChild[] | React.ReactChild,
14
14
  className?: string,
15
15
  dark?: boolean,
16
16
  data?: {[key: string]: string},
17
17
  error?: boolean,
18
18
  id?: string,
19
19
  label: string,
20
- name: string,
21
- value: string,
22
- text: string,
20
+ name?: string,
21
+ value?: string,
22
+ text?: string,
23
23
  onChange: (event: React.FormEvent<HTMLInputElement> | null)=>void,
24
24
  } & GlobalProps
25
25
 
@@ -50,7 +50,7 @@
50
50
  border-color: $error;
51
51
  }
52
52
  .pb_select_kit_caret {
53
- top: 35%;
53
+ top: 25px;
54
54
  }
55
55
  }
56
56
  }