playbook_ui 11.19.0 → 11.20.0.pre.alpha.railsdialog1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) 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_checkbox/_checkbox.tsx +7 -7
  9. data/app/pb_kits/playbook/pb_dialog/_dialog.scss +70 -3
  10. data/app/pb_kits/playbook/pb_dialog/_dialog.tsx +1 -1
  11. data/app/pb_kits/playbook/pb_dialog/dialog.rb +1 -1
  12. data/app/pb_kits/playbook/pb_dialog/dialog.test.jsx +12 -0
  13. data/app/pb_kits/playbook/pb_file_upload/_file_upload.tsx +5 -4
  14. data/app/pb_kits/playbook/pb_file_upload/docs/_description.md +2 -3
  15. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_custom_message.jsx +40 -0
  16. data/app/pb_kits/playbook/pb_file_upload/docs/example.yml +2 -2
  17. data/app/pb_kits/playbook/pb_file_upload/docs/index.js +1 -0
  18. data/app/pb_kits/playbook/pb_file_upload/fileupload.test.js +12 -0
  19. data/app/pb_kits/playbook/pb_radio/_radio.tsx +4 -4
  20. data/app/pb_kits/playbook/pb_select/_select.scss +1 -1
  21. data/app/pb_kits/playbook/pb_selectable_card/{_selectable_card.jsx → _selectable_card.tsx} +47 -42
  22. data/app/pb_kits/playbook/pb_selectable_card/docs/_selectable_card_default.jsx +1 -2
  23. data/app/pb_kits/playbook/pb_selectable_card/docs/_selectable_card_single_select.jsx +1 -1
  24. data/app/pb_kits/playbook/pb_selectable_card/selectable_card.test.js +185 -0
  25. data/app/pb_kits/playbook/pb_selectable_icon/{_selectable_icon.jsx → _selectable_icon.tsx} +29 -32
  26. data/app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_default.jsx +1 -5
  27. data/app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_single_select.jsx +1 -4
  28. data/app/pb_kits/playbook/pb_selectable_icon/selectable_icon.test.js +148 -0
  29. data/lib/playbook/version.rb +2 -2
  30. metadata +12 -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: 270f21bddaa2e5f8a2e2bfb4426ce26083f89c21fd219c068fc4e3f643589748
4
+ data.tar.gz: b8cc815cc03a09ef95173a42b1f7c52bb2f000d010923c3930be1fc45b1c767e
5
5
  SHA512:
6
- metadata.gz: 4ef7df4f5c65d61d144d0b552b11c7205451cb77d50dff97c181af2175de03374ee98d18505c0765b219b217caef55f5714425585a27f7d0d2597efa50a1af21
7
- data.tar.gz: '0068b2d612e89e7932399e089b1478faac10bd3a710e29ef4f555b6e57060236ff0a4f346c15ae61bd08e2a925b136174901803b55a066d1c1d6397b1379f1ee'
6
+ metadata.gz: 5e6487ff9f39df73b1a3cf95cd6be02b82978be031a21f8b4c022daecee81e08ac01105facd9d92293be13de4fdd65f4c2fe3d7688736ee5de6dafca4be1e41c
7
+ data.tar.gz: 428c54f40b19703257dabe224279a0229769f89832985864d95411b6b8c0d9dee7806f5bfd19615285abf5f0598eada9af239bbf501fb8888ac5c56a80eeb00f
@@ -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'
@@ -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;
@@ -250,6 +316,7 @@
250
316
  // fixes for stylesheets in nitro that were conflicting with our kit. DO NOT REMOVE.
251
317
  //conflicts were only apparent in nitro, not in playbook local env
252
318
  .pb_dialog_rails {
319
+ position: fixed !important;
253
320
  top: 0 !important;
254
321
  padding: unset !important;
255
322
  margin: auto;
@@ -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
  }
@@ -1,10 +1,9 @@
1
1
  /* @flow */
2
2
 
3
- import React from 'react'
3
+ import React, {useRef} from 'react'
4
4
  import classnames from 'classnames'
5
5
 
6
- import type { InputCallback } from '../types'
7
- import { globalProps } from '../utilities/globalProps'
6
+ import { globalProps, GlobalProps } from '../utilities/globalProps'
8
7
  import {
9
8
  buildAriaProps,
10
9
  buildCss,
@@ -19,13 +18,13 @@ import Flex from '../pb_flex/_flex'
19
18
  import Radio from '../pb_radio/_radio'
20
19
 
21
20
  type SelectableCardProps = {
22
- aria?: object,
23
- checked: boolean,
24
- children?: array<React.ReactChild>,
21
+ aria?: { [key: string]: string },
22
+ checked?: boolean,
23
+ children?: React.ReactChild[] | React.ReactChild,
25
24
  className?: string,
26
- customIcon?: SVGElement,
25
+ customIcon?: {[key: string] :SVGElement},
27
26
  dark?: boolean,
28
- data: object,
27
+ data?: { [key: string]: string },
29
28
  disabled?: boolean,
30
29
  error?: boolean,
31
30
  icon?: boolean,
@@ -33,32 +32,31 @@ type SelectableCardProps = {
33
32
  inputId?: string,
34
33
  multi?: boolean,
35
34
  name?: string,
36
- onChange: InputCallback<HTMLInputElement>,
35
+ onChange: (event: React.FormEvent<HTMLInputElement>) => void,
37
36
  text?: string,
38
37
  value?: string,
39
38
  variant?: string,
40
- }
39
+ } & GlobalProps
41
40
 
42
- const SelectableCard = ({
43
- aria = {},
44
- checked = false,
45
- children,
46
- className,
47
- customIcon,
48
- dark = false,
49
- data = {},
50
- disabled = false,
51
- error = false,
52
- icon = false,
53
- inputId = null,
54
- multi = true,
55
- name,
56
- onChange = noop,
57
- text,
58
- value,
59
- variant = 'default',
60
- ...props
61
- }: SelectableCardProps) => {
41
+ const SelectableCard = (props: SelectableCardProps) => {
42
+ const {
43
+ aria = {},
44
+ checked = false,
45
+ className,
46
+ customIcon,
47
+ dark = false,
48
+ data = {},
49
+ disabled = false,
50
+ error = false,
51
+ icon = false,
52
+ inputId = null,
53
+ multi = true,
54
+ name,
55
+ onChange = noop,
56
+ text,
57
+ value,
58
+ variant = 'default',
59
+ } = props
62
60
  const ariaProps = buildAriaProps(aria)
63
61
  const dataProps = buildDataProps(data)
64
62
 
@@ -87,7 +85,7 @@ const SelectableCard = ({
87
85
  }
88
86
  }
89
87
 
90
- const inputRef = React.createRef()
88
+ const inputRef = useRef(null)
91
89
  // Delegate clicks to hidden input from visible one
92
90
  const handleClick = () => {
93
91
  inputRef.current.click()
@@ -96,7 +94,15 @@ const SelectableCard = ({
96
94
  const inputType = multi ? 'checkbox' : 'radio'
97
95
  const inputIdPresent = inputId !== null ? inputId : name
98
96
  const Input = multi ? Checkbox : Radio
99
- const labelProps = variant === 'displayInput' ? Object.assign(props, { padding: 'none' }) : props
97
+
98
+ const filteredProps = {...props}
99
+ delete filteredProps?.inputId
100
+ delete filteredProps?.children
101
+ delete filteredProps?.icon
102
+ delete filteredProps?.error
103
+ delete filteredProps?.dark
104
+ delete filteredProps?.multi
105
+ const labelProps: GlobalProps = variant === 'displayInput' ? { ...filteredProps, padding: 'none' } : { ...filteredProps }
100
106
 
101
107
  return (
102
108
  <div
@@ -105,7 +111,6 @@ const SelectableCard = ({
105
111
  className={classes}
106
112
  >
107
113
  <input
108
- {...props}
109
114
  checked={checked}
110
115
  disabled={disabled}
111
116
  id={inputIdPresent}
@@ -114,6 +119,7 @@ const SelectableCard = ({
114
119
  ref={inputRef}
115
120
  type={inputType}
116
121
  value={value}
122
+ {...filteredProps}
117
123
  />
118
124
 
119
125
  <label
@@ -121,8 +127,7 @@ const SelectableCard = ({
121
127
  htmlFor={inputIdPresent}
122
128
  >
123
129
  <div className="buffer">
124
- <Choose>
125
- <When condition={variant === 'displayInput'}>
130
+ {variant === 'displayInput' ?
126
131
  <Flex vertical="center">
127
132
  <Flex
128
133
  orientation="column"
@@ -130,7 +135,9 @@ const SelectableCard = ({
130
135
  paddingRight="xs"
131
136
  vertical="center"
132
137
  >
133
- <Input dark={dark}>
138
+ <Input
139
+ dark={dark}
140
+ >
134
141
  <input
135
142
  checked={checked}
136
143
  disabled={disabled}
@@ -146,14 +153,12 @@ const SelectableCard = ({
146
153
  padding="sm"
147
154
  status={error ? 'negative' : null}
148
155
  >
149
- {text || children}
156
+ {text ||props.children}
150
157
  </Card.Body>
151
158
  </Flex>
152
- </When>
153
- <Otherwise>
154
- {text || children}
155
- </Otherwise>
156
- </Choose>
159
+ :
160
+ text || props.children
161
+ }
157
162
  {displayIcon()}
158
163
  </div>
159
164
  </label>
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react'
2
- import SelectableCard from '../_selectable_card.jsx'
2
+ import SelectableCard from '../_selectable_card.tsx'
3
3
 
4
4
  const SelectableCardDefault = (props) => {
5
5
  const [selectedWithIcon, setSelectedWithIcon] = useState(true)
@@ -24,7 +24,6 @@ const SelectableCardDefault = (props) => {
24
24
 
25
25
  <SelectableCard
26
26
  checked={selectedNoIcon}
27
- icon={false}
28
27
  inputId="selectedWithoutIcon"
29
28
  name="selectedWithoutIcon"
30
29
  onChange={() => setSelectedNoIcon(!selectedNoIcon)}
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react'
2
- import SelectableCard from '../_selectable_card.jsx'
2
+ import SelectableCard from '../_selectable_card.tsx'
3
3
 
4
4
  const SelectableCardSingleSelect = (props) => {
5
5
  const [selected, setSelected] = useState(null)
@@ -0,0 +1,185 @@
1
+ import React, { useState } from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+ import SelectableCard from './_selectable_card'
4
+ import { Body, Title, Image } from '../'
5
+
6
+ const SelectableCardMultiSelect = () => {
7
+ const [selected, setSelected] = useState(true)
8
+ const [unselected, setUnselected] = useState(false)
9
+ const [disabled, setDisabled] = useState(false)
10
+
11
+ return (
12
+ <>
13
+ <SelectableCard
14
+ checked={selected}
15
+ inputId="selected"
16
+ name="selected"
17
+ onChange={() => setSelected(!selected)}
18
+ value="selected"
19
+ >
20
+ {'Selected'}
21
+ </SelectableCard>
22
+
23
+ <SelectableCard
24
+ checked={unselected}
25
+ inputId="unselected"
26
+ name="unselected"
27
+ onChange={() => setUnselected(!unselected)}
28
+ value="unselected"
29
+ >
30
+ {'Unselected'}
31
+ </SelectableCard>
32
+
33
+ <SelectableCard
34
+ checked={disabled}
35
+ disabled
36
+ inputId="disabled"
37
+ name="disabled"
38
+ onChange={() => setDisabled(!disabled)}
39
+ value="disabled"
40
+ >
41
+ {'Disabled'}
42
+ </SelectableCard>
43
+
44
+ </>
45
+ )
46
+ }
47
+
48
+ const SelectableCardSingleSelect = () => {
49
+ const [selected, setSelected] = useState(null)
50
+ const handleSelect = (event) => {
51
+ setSelected(event.target.value)
52
+ }
53
+
54
+ return (
55
+ <>
56
+ <SelectableCard
57
+ checked={selected === 'male'}
58
+ inputId="male1"
59
+ multi={false}
60
+ name="gender"
61
+ onChange={handleSelect}
62
+ value="male"
63
+ >
64
+ {'Male'}
65
+ </SelectableCard>
66
+
67
+ <SelectableCard
68
+ checked={selected === 'female'}
69
+ inputId="female1"
70
+ multi={false}
71
+ name="gender"
72
+ onChange={handleSelect}
73
+ value="female"
74
+ >
75
+ {'Female'}
76
+ </SelectableCard>
77
+
78
+ <SelectableCard
79
+ checked={selected === 'other'}
80
+ inputId="other1"
81
+ multi={false}
82
+ name="gender"
83
+ onChange={handleSelect}
84
+ value="other"
85
+ >
86
+ {'Other'}
87
+ </SelectableCard>
88
+ </>
89
+ )
90
+ }
91
+
92
+
93
+ test('should start with a checked item', () => {
94
+ render(<SelectableCardMultiSelect />)
95
+
96
+ const kit = screen.getByLabelText('Selected')
97
+ expect(kit).toBeChecked()
98
+ })
99
+
100
+ test('should start with a disabled item', () => {
101
+ render(<SelectableCardMultiSelect />)
102
+
103
+ const kit = screen.getByLabelText('Disabled')
104
+ expect(kit).toBeDisabled()
105
+ })
106
+
107
+ test('should click and check an item', () => {
108
+ render(<SelectableCardMultiSelect />)
109
+
110
+ const kit = screen.getByLabelText('Unselected')
111
+ expect(kit).not.toBeChecked()
112
+ kit.click()
113
+ expect(kit).toBeChecked()
114
+ })
115
+
116
+ test('should check multiple items', () => {
117
+ render(<SelectableCardMultiSelect />)
118
+
119
+ const checkedItem = screen.getByLabelText('Selected')
120
+ expect(checkedItem).toBeChecked()
121
+
122
+ const uncheckedItem = screen.getByLabelText('Unselected')
123
+ expect(uncheckedItem).not.toBeChecked()
124
+
125
+ uncheckedItem.click()
126
+
127
+ expect(checkedItem).toBeChecked
128
+ expect(uncheckedItem).toBeChecked
129
+ })
130
+
131
+ test('should check only single item', () => {
132
+ render(<SelectableCardSingleSelect/>)
133
+
134
+ const male = screen.getByLabelText('Male')
135
+ expect(male).not.toBeChecked
136
+
137
+ const female = screen.getByLabelText('Female')
138
+ expect(female).not.toBeChecked
139
+
140
+ const other = screen.getByLabelText('Other')
141
+ expect(other).not.toBeChecked
142
+
143
+ male.click()
144
+ other.click()
145
+
146
+ expect(male).not.toBeChecked
147
+ expect(female).not.toBeChecked
148
+ expect(other).toBeChecked
149
+ })
150
+
151
+ test('should have text passed through the text prop', () => {
152
+ render (<SelectableCard text="This passes text through the tag"/>)
153
+
154
+ expect(screen.getByText("This passes text through the tag")).toBeInTheDocument()
155
+ })
156
+
157
+ test('should pass block content', () => {
158
+ render (<SelectableCard>
159
+ <Title
160
+ size={4}
161
+ text="Block"
162
+ />
163
+ <Body
164
+ tag="span"
165
+ >
166
+ {'This uses block'}
167
+ </Body>
168
+ </SelectableCard>
169
+ )
170
+ expect(screen.getByText("This uses block")).toBeInTheDocument()
171
+ })
172
+
173
+ test('should pass image inside card content', () => {
174
+ render (<SelectableCard>
175
+ <Image
176
+ rounded
177
+ size="xl"
178
+ url="https://unsplash.it/500/400/?image=634"
179
+ />
180
+ </SelectableCard>
181
+ )
182
+ const dispalyedImg = document.querySelector("img")
183
+
184
+ expect(dispalyedImg.src).toContain("image=634")
185
+ })
@@ -1,23 +1,20 @@
1
1
  /* @flow */
2
-
3
2
  import React from 'react'
4
3
  import classnames from 'classnames'
5
-
6
4
  import { globalProps } from '../utilities/globalProps'
7
5
  import {
8
6
  buildAriaProps,
9
7
  buildCss,
10
8
  buildDataProps,
11
9
  } from '../utilities/props'
12
-
13
10
  import Icon from '../pb_icon/_icon'
14
11
  import Title from '../pb_title/_title'
15
12
 
16
13
  type SelectableIconProps = {
17
- aria?: Object,
14
+ aria?: {[key: string]: string},
18
15
  checked?: boolean,
19
16
  className?: string,
20
- customIcon?: SVGElement,
17
+ customIcon?: {[key: string] :SVGElement},
21
18
  disabled?: boolean,
22
19
  data?: Object,
23
20
  icon: string,
@@ -59,54 +56,54 @@ const SelectableIcon = ({
59
56
  )
60
57
 
61
58
  const inputType = multi === false ? 'radio' : 'checkbox'
62
-
63
59
  const inputIdPresent = inputId !== null ? inputId : name
64
60
 
65
61
  return (
66
62
  <div
67
- {...ariaProps}
68
- {...dataProps}
69
- className={classes}
63
+ {...ariaProps}
64
+ {...dataProps}
65
+ className={classes}
70
66
  >
71
- <If condition={inputs === 'disabled'}>
67
+ {inputs === 'disabled' && (
72
68
  <>
73
69
  <Icon
74
- customIcon={customIcon}
75
- icon={icon}
76
- size="2x"
70
+ customIcon={customIcon}
71
+ icon={icon}
72
+ size="2x"
77
73
  />
78
74
  <Title
79
- size={4}
80
- tag="h4"
81
- text={text}
75
+ size={4}
76
+ tag="h4"
77
+ text={text}
82
78
  />
83
79
  </>
84
- </If>
85
- <If condition={inputs === 'enabled'}>
80
+ )}
81
+
82
+ {inputs === 'enabled' && (
86
83
  <>
87
84
  <input
88
- {...props}
89
- checked={checked}
90
- disabled={disabled}
91
- id={inputIdPresent}
92
- name={name}
93
- type={inputType}
94
- value={value}
85
+ {...props}
86
+ checked={checked}
87
+ disabled={disabled}
88
+ id={inputIdPresent}
89
+ name={name}
90
+ type={inputType}
91
+ value={value}
95
92
  />
96
93
  <label htmlFor={inputIdPresent}>
97
94
  <Icon
98
- customIcon={customIcon}
99
- icon={icon}
100
- size="2x"
95
+ customIcon={customIcon}
96
+ icon={icon}
97
+ size="2x"
101
98
  />
102
99
  <Title
103
- size={4}
104
- tag="h4"
105
- text={text}
100
+ size={4}
101
+ tag="h4"
102
+ text={text}
106
103
  />
107
104
  </label>
108
105
  </>
109
- </If>
106
+ )}
110
107
  </div>
111
108
  )
112
109
  }
@@ -1,8 +1,7 @@
1
1
  import React, { useState } from 'react'
2
-
3
2
  import SelectableIcon from '../_selectable_icon'
4
3
 
5
- const SelectableIconDefault = (props) => {
4
+ const SelectableIconDefault = () => {
6
5
  const [ checkSelected, toggleSelected ] = useState(true)
7
6
  const [ checkUnselected, toggleUnselected ] = useState(false)
8
7
  const [ checkDisabled, toggleDisabled ] = useState(false)
@@ -16,7 +15,6 @@ const SelectableIconDefault = (props) => {
16
15
  inputId={10}
17
16
  onChange={() => toggleSelected(!checkSelected)}
18
17
  text="US Dollar"
19
- {...props}
20
18
  />
21
19
 
22
20
  <SelectableIcon
@@ -25,7 +23,6 @@ const SelectableIconDefault = (props) => {
25
23
  inputId={11}
26
24
  onChange={() => toggleUnselected(!checkUnselected)}
27
25
  text="Euro"
28
- {...props}
29
26
  />
30
27
 
31
28
  <SelectableIcon
@@ -35,7 +32,6 @@ const SelectableIconDefault = (props) => {
35
32
  inputId={12}
36
33
  onChange={() => toggleDisabled(!checkDisabled)}
37
34
  text="Yen"
38
- {...props}
39
35
  />
40
36
  </div>
41
37
  )
@@ -2,7 +2,7 @@ import React, { useState } from 'react'
2
2
 
3
3
  import SelectableIcon from '../_selectable_icon'
4
4
 
5
- const SelectableIconSingleSelect = (props) => {
5
+ const SelectableIconSingleSelect = () => {
6
6
  const [ selectedFormat, toggleFormat ] = useState(null)
7
7
 
8
8
  return (
@@ -17,7 +17,6 @@ const SelectableIconSingleSelect = (props) => {
17
17
  onChange={() => toggleFormat('Cassette')}
18
18
  text="Cassette"
19
19
  value="Cassette"
20
- {...props}
21
20
  />
22
21
 
23
22
  <SelectableIcon
@@ -29,7 +28,6 @@ const SelectableIconSingleSelect = (props) => {
29
28
  onChange={() => toggleFormat('CD')}
30
29
  text="CD"
31
30
  value="CD"
32
- {...props}
33
31
  />
34
32
 
35
33
  <SelectableIcon
@@ -41,7 +39,6 @@ const SelectableIconSingleSelect = (props) => {
41
39
  onChange={() => toggleFormat('Vinyl')}
42
40
  text="Vinyl"
43
41
  value="Vinyl"
44
- {...props}
45
42
  />
46
43
  </div>
47
44
  )
@@ -0,0 +1,148 @@
1
+ import React, { useState } from 'react'
2
+ import { render, screen } from '../utilities/test-utils'
3
+ import SelectableIcon from './_selectable_icon'
4
+
5
+ const testId = "selectableIcon"
6
+
7
+ const SelectableIconMultiSelect = () => {
8
+ const [checkSelected, toggleSelected] = useState(true)
9
+ const [checkUnselected, toggleUnselected] = useState(false)
10
+ const [checkDisabled, toggleDisabled] = useState(false)
11
+
12
+ return (
13
+ <>
14
+ <SelectableIcon
15
+ checked={checkSelected}
16
+ className="custom-class"
17
+ data={{ testid: testId }}
18
+ icon="dollar-sign"
19
+ inputId={10}
20
+ onChange={() => toggleSelected(!checkSelected)}
21
+ text="US Dollar"
22
+ />
23
+
24
+ <SelectableIcon
25
+ checked={checkUnselected}
26
+ icon="euro-sign"
27
+ inputId={11}
28
+ onChange={() => toggleUnselected(!checkUnselected)}
29
+ text="Euro"
30
+ />
31
+
32
+ <SelectableIcon
33
+ checked={checkDisabled}
34
+ disabled
35
+ icon="yen-sign"
36
+ inputId={12}
37
+ onChange={() => toggleDisabled(!checkDisabled)}
38
+ text="Yen"
39
+ />
40
+ </>
41
+ )
42
+ }
43
+
44
+ const SelectableIconSingleSelect = () => {
45
+ const [selectedFormat, toggleFormat] = useState('')
46
+
47
+ return (
48
+ <>
49
+ <SelectableIcon
50
+ checked={selectedFormat === 'Cassette'}
51
+ icon="cassette-tape"
52
+ inputId={13}
53
+ multi={false}
54
+ name="music-format"
55
+ onChange={() => toggleFormat('Cassette')}
56
+ text="Cassette"
57
+ value="Cassette"
58
+ />
59
+
60
+ <SelectableIcon
61
+ checked={selectedFormat === 'CD'}
62
+ icon="compact-disc"
63
+ inputId={14}
64
+ multi={false}
65
+ name="music-format"
66
+ onChange={() => toggleFormat('CD')}
67
+ text="CD"
68
+ value="CD"
69
+ />
70
+
71
+ <SelectableIcon
72
+ checked={selectedFormat === 'Vinyl'}
73
+ icon="album-collection"
74
+ inputId={15}
75
+ multi={false}
76
+ name="music-format"
77
+ onChange={() => toggleFormat('Vinyl')}
78
+ text="Vinyl"
79
+ value="Vinyl"
80
+ />
81
+ </>
82
+ )
83
+ }
84
+
85
+ test('should start with a checked item', () => {
86
+ render(<SelectableIconMultiSelect />)
87
+
88
+ const kit = screen.getByLabelText('US Dollar')
89
+ expect(kit).toBeChecked()
90
+ })
91
+
92
+ test('should start with a disabled item', () => {
93
+ render(<SelectableIconMultiSelect />)
94
+
95
+ const kit = screen.getByLabelText('Yen')
96
+ expect(kit).toBeDisabled()
97
+ })
98
+
99
+ test('should click and check an item', () => {
100
+ render(<SelectableIconMultiSelect />)
101
+
102
+ const kit = screen.getByLabelText('Euro')
103
+ expect(kit).not.toBeChecked()
104
+ kit.click()
105
+ expect(kit).toBeChecked()
106
+ })
107
+
108
+ test('should check multiple items', () => {
109
+ render(<SelectableIconMultiSelect />)
110
+
111
+ const usDollarItem = screen.getByLabelText('US Dollar')
112
+ expect(usDollarItem).toBeChecked()
113
+
114
+ const euroItem = screen.getByLabelText('Euro')
115
+ expect(euroItem).not.toBeChecked()
116
+
117
+ euroItem.click()
118
+
119
+ expect(usDollarItem).toBeChecked()
120
+ expect(euroItem).toBeChecked()
121
+ })
122
+
123
+ test('should check single item', () => {
124
+ render(<SelectableIconSingleSelect />)
125
+
126
+ const cassetteItem = screen.getByLabelText('Cassette')
127
+ expect(cassetteItem).not.toBeChecked()
128
+
129
+ const cdItem = screen.getByLabelText('CD')
130
+ expect(cdItem).not.toBeChecked()
131
+
132
+ const vinylItem = screen.getByLabelText('Vinyl')
133
+ expect(vinylItem).not.toBeChecked()
134
+
135
+ cassetteItem.click()
136
+ cdItem.click()
137
+
138
+ expect(cassetteItem).not.toBeChecked()
139
+ expect(cdItem).toBeChecked()
140
+ expect(vinylItem).not.toBeChecked()
141
+ })
142
+
143
+ test('should render custom class and data', () => {
144
+ render(<SelectableIconMultiSelect />)
145
+
146
+ const kit = screen.getByTestId(testId)
147
+ expect(kit).toHaveClass('custom-class')
148
+ })
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playbook
4
- PREVIOUS_VERSION = "11.18.0"
5
- VERSION = "11.19.0"
4
+ PREVIOUS_VERSION = "11.20.0"
5
+ VERSION = "11.20.0.pre.alpha.railsdialog1"
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: 11.19.0
4
+ version: 11.20.0.pre.alpha.railsdialog1
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-01-16 00:00:00.000000000 Z
12
+ date: 2023-01-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -397,6 +397,9 @@ files:
397
397
  - app/pb_kits/playbook/pb_body/docs/_body_light.html.erb
398
398
  - app/pb_kits/playbook/pb_body/docs/_body_light.jsx
399
399
  - app/pb_kits/playbook/pb_body/docs/_body_light.md
400
+ - app/pb_kits/playbook/pb_body/docs/_body_styled.html.erb
401
+ - app/pb_kits/playbook/pb_body/docs/_body_styled.jsx
402
+ - app/pb_kits/playbook/pb_body/docs/_body_styled.md
400
403
  - app/pb_kits/playbook/pb_body/docs/_description.md
401
404
  - app/pb_kits/playbook/pb_body/docs/_footer.md
402
405
  - app/pb_kits/playbook/pb_body/docs/example.yml
@@ -887,6 +890,7 @@ files:
887
890
  - app/pb_kits/playbook/pb_file_upload/docs/_file_upload_accept.jsx
888
891
  - app/pb_kits/playbook/pb_file_upload/docs/_file_upload_custom_description.jsx
889
892
  - app/pb_kits/playbook/pb_file_upload/docs/_file_upload_custom_description.md
893
+ - app/pb_kits/playbook/pb_file_upload/docs/_file_upload_custom_message.jsx
890
894
  - app/pb_kits/playbook/pb_file_upload/docs/_file_upload_default.jsx
891
895
  - app/pb_kits/playbook/pb_file_upload/docs/_file_upload_max_size.jsx
892
896
  - app/pb_kits/playbook/pb_file_upload/docs/example.yml
@@ -1699,8 +1703,8 @@ files:
1699
1703
  - app/pb_kits/playbook/pb_select/select.html.erb
1700
1704
  - app/pb_kits/playbook/pb_select/select.rb
1701
1705
  - app/pb_kits/playbook/pb_select/select.test.js
1702
- - app/pb_kits/playbook/pb_selectable_card/_selectable_card.jsx
1703
1706
  - app/pb_kits/playbook/pb_selectable_card/_selectable_card.scss
1707
+ - app/pb_kits/playbook/pb_selectable_card/_selectable_card.tsx
1704
1708
  - app/pb_kits/playbook/pb_selectable_card/docs/_description.md
1705
1709
  - app/pb_kits/playbook/pb_selectable_card/docs/_footer.md
1706
1710
  - app/pb_kits/playbook/pb_selectable_card/docs/_selectable_card_block.html.erb
@@ -1725,6 +1729,7 @@ files:
1725
1729
  - app/pb_kits/playbook/pb_selectable_card/docs/index.js
1726
1730
  - app/pb_kits/playbook/pb_selectable_card/selectable_card.html.erb
1727
1731
  - app/pb_kits/playbook/pb_selectable_card/selectable_card.rb
1732
+ - app/pb_kits/playbook/pb_selectable_card/selectable_card.test.js
1728
1733
  - app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.jsx
1729
1734
  - app/pb_kits/playbook/pb_selectable_card_icon/_selectable_card_icon.scss
1730
1735
  - app/pb_kits/playbook/pb_selectable_card_icon/docs/_selectable_card_icon_checkmark.html.erb
@@ -1738,8 +1743,8 @@ files:
1738
1743
  - app/pb_kits/playbook/pb_selectable_card_icon/docs/index.js
1739
1744
  - app/pb_kits/playbook/pb_selectable_card_icon/selectable_card_icon.html.erb
1740
1745
  - app/pb_kits/playbook/pb_selectable_card_icon/selectable_card_icon.rb
1741
- - app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.jsx
1742
1746
  - app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.scss
1747
+ - app/pb_kits/playbook/pb_selectable_icon/_selectable_icon.tsx
1743
1748
  - app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_default.html.erb
1744
1749
  - app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_default.jsx
1745
1750
  - app/pb_kits/playbook/pb_selectable_icon/docs/_selectable_icon_options.html.erb
@@ -1749,6 +1754,7 @@ files:
1749
1754
  - app/pb_kits/playbook/pb_selectable_icon/docs/index.js
1750
1755
  - app/pb_kits/playbook/pb_selectable_icon/selectable_icon.html.erb
1751
1756
  - app/pb_kits/playbook/pb_selectable_icon/selectable_icon.rb
1757
+ - app/pb_kits/playbook/pb_selectable_icon/selectable_icon.test.js
1752
1758
  - app/pb_kits/playbook/pb_selectable_list/_item.jsx
1753
1759
  - app/pb_kits/playbook/pb_selectable_list/_selectable_list.jsx
1754
1760
  - app/pb_kits/playbook/pb_selectable_list/_selectable_list.scss
@@ -2364,9 +2370,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
2364
2370
  version: '0'
2365
2371
  required_rubygems_version: !ruby/object:Gem::Requirement
2366
2372
  requirements:
2367
- - - ">="
2373
+ - - ">"
2368
2374
  - !ruby/object:Gem::Version
2369
- version: '0'
2375
+ version: 1.3.1
2370
2376
  requirements: []
2371
2377
  rubygems_version: 3.3.7
2372
2378
  signing_key: