playbook_ui 14.19.0 → 14.20.0.pre.rc.0

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +11 -1
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +148 -15
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +20 -3
  5. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +23 -13
  6. data/app/pb_kits/playbook/pb_advanced_table/Utilities/VisibilityTree.ts +47 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +9 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +7 -2
  9. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.jsx +57 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.md +4 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.jsx +62 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.md +1 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.jsx +82 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.md +1 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.jsx +65 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +1 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +4 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +5 -1
  19. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/advanced_table_sticky_mixin.scss +1 -0
  20. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +2 -2
  21. data/app/pb_kits/playbook/pb_file_upload/_file_upload.scss +13 -0
  22. data/app/pb_kits/playbook/pb_file_upload/_file_upload.tsx +11 -1
  23. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.html.erb +1 -0
  24. data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.jsx +41 -0
  25. data/app/pb_kits/playbook/pb_file_upload/docs/example.yml +2 -0
  26. data/app/pb_kits/playbook/pb_file_upload/docs/index.js +1 -0
  27. data/app/pb_kits/playbook/pb_file_upload/file_upload.html.erb +1 -0
  28. data/app/pb_kits/playbook/pb_file_upload/file_upload.rb +7 -1
  29. data/app/pb_kits/playbook/pb_file_upload/fileupload.test.js +18 -0
  30. data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +9 -9
  31. data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +2 -2
  32. data/app/pb_kits/playbook/pb_text_input/_text_input.scss +4 -2
  33. data/dist/chunks/{_typeahead-D62OcwsT.js → _typeahead-BPSIWtFT.js} +3 -3
  34. data/dist/chunks/_weekday_stacked-PfWrqC3z.js +45 -0
  35. data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
  36. data/dist/chunks/lib-B20MXZcW.js +29 -0
  37. data/dist/chunks/{pb_form_validation-BioH7DWv.js → pb_form_validation-WWvUXPKD.js} +1 -1
  38. data/dist/chunks/vendor.js +1 -1
  39. data/dist/playbook-doc.js +1 -1
  40. data/dist/playbook-rails-react-bindings.js +1 -1
  41. data/dist/playbook-rails.js +1 -1
  42. data/dist/playbook.css +1 -1
  43. data/lib/playbook/version.rb +2 -2
  44. metadata +18 -7
  45. data/dist/chunks/_weekday_stacked-Ceh9N0ow.js +0 -45
  46. data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
  47. data/dist/chunks/lib-CeKZrPmu.js +0 -29
@@ -0,0 +1,65 @@
1
+ import React, { useState } from "react"
2
+ import AdvancedTable from '../../pb_advanced_table/_advanced_table'
3
+ import MOCK_DATA from "./advanced_table_mock_data.json"
4
+
5
+ const AdvancedTableColumnVisibilityWithState = (props) => {
6
+ const columnDefinitions = [
7
+ {
8
+ accessor: "year",
9
+ label: "Year",
10
+ cellAccessors: ["quarter", "month", "day"],
11
+ id: "year"
12
+ },
13
+ {
14
+ accessor: "newEnrollments",
15
+ label: "New Enrollments",
16
+ id: "newEnrollments"
17
+ },
18
+ {
19
+ accessor: "scheduledMeetings",
20
+ label: "Scheduled Meetings",
21
+ id: "scheduledMeetings"
22
+ },
23
+ {
24
+ accessor: "attendanceRate",
25
+ label: "Attendance Rate",
26
+ id: "attendanceRate"
27
+ },
28
+ {
29
+ accessor: "completedClasses",
30
+ label: "Completed Classes",
31
+ id: "completedClasses"
32
+ },
33
+ {
34
+ accessor: "classCompletionRate",
35
+ label: "Class Completion Rate",
36
+ id: "classCompletionRate"
37
+ },
38
+ {
39
+ accessor: "graduatedStudents",
40
+ label: "Graduated Students",
41
+ id: "graduatedStudents"
42
+ },
43
+ ]
44
+
45
+ const [columnVisibility, setColumnVisibility] = useState({
46
+ newEnrollments: false
47
+ })
48
+
49
+ const columnVisibilityControl = {
50
+ value: columnVisibility,
51
+ onChange: setColumnVisibility,
52
+ }
53
+ return (
54
+ <div>
55
+ <AdvancedTable
56
+ columnDefinitions={columnDefinitions}
57
+ columnVisibilityControl={columnVisibilityControl}
58
+ tableData={MOCK_DATA}
59
+ {...props}
60
+ />
61
+ </div>
62
+ )
63
+ }
64
+
65
+ export default AdvancedTableColumnVisibilityWithState
@@ -0,0 +1 @@
1
+ The `columnVisibilityControl` prop also allows for greater control over the columnVisibility state. Devs can manage state themselves by passing in `value` and `onChange` as shown.
@@ -47,3 +47,7 @@ examples:
47
47
  - advanced_table_selectable_rows_header: Selectable Rows (No Actions Bar)
48
48
  - advanced_table_inline_editing: Inline Cell Editing
49
49
  - advanced_table_fullscreen: Fullscreen
50
+ - advanced_table_column_visibility: Column Visibility Control
51
+ - advanced_table_column_visibility_with_state: Column Visibility Control With State
52
+ - advanced_table_column_visibility_custom: Column Visibility Control with Custom Dropdown
53
+ - advanced_table_column_visibility_multi: Column Visibility Control with Multi-Header Columns
@@ -27,4 +27,8 @@ export { default as AdvancedTableStickyColumns } from './_advanced_table_sticky_
27
27
  export { default as AdvancedTableStickyHeader } from './_advanced_table_sticky_header.jsx'
28
28
  export { default as AdvancedTableStickyColumnsAndHeader } from './_advanced_table_sticky_columns_and_header.jsx'
29
29
  export { default as AdvancedTableExpandByDepth } from './_advanced_table_expand_by_depth.jsx'
30
- export { default as AdvancedTableColumnBorderColor} from './_advanced_table_column_border_color.jsx'
30
+ export { default as AdvancedTableColumnBorderColor} from './_advanced_table_column_border_color.jsx'
31
+ export { default as AdvancedTableColumnVisibility } from './_advanced_table_column_visibility.jsx'
32
+ export { default as AdvancedTableColumnVisibilityCustom } from './_advanced_table_column_visibility_custom.jsx'
33
+ export { default as AdvancedTableColumnVisibilityMulti } from './_advanced_table_column_visibility_multi.jsx'
34
+ export { default as AdvancedTableColumnVisibilityWithState } from './_advanced_table_column_visibility_with_state.jsx'
@@ -77,6 +77,7 @@
77
77
  top: 0;
78
78
  left: 0;
79
79
  border-radius: unset;
80
+ z-index: 5;
80
81
  }
81
82
 
82
83
  .checkbox-cell {
@@ -6,7 +6,7 @@ import {
6
6
  buildDataProps,
7
7
  buildHtmlProps
8
8
  } from "../../utilities/props";
9
- import { globalProps } from "../../utilities/globalProps";
9
+ import { globalProps, GlobalProps } from "../../utilities/globalProps";
10
10
 
11
11
  import DropdownContext from "../context";
12
12
 
@@ -24,7 +24,7 @@ type DropdownContainerProps = {
24
24
  htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
25
25
  id?: string;
26
26
  searchbar?: boolean;
27
- };
27
+ } & GlobalProps;
28
28
 
29
29
  const DropdownContainer = (props: DropdownContainerProps) => {
30
30
  const {
@@ -9,10 +9,23 @@
9
9
  border: none;
10
10
  width: 0;
11
11
  }
12
+ &.error {
13
+ [class^='pb_card_kit'] {
14
+ border-color: $error;
15
+ }
16
+ [class^='pb_body_kit'][status="negative"] {
17
+ margin-top: $space_xs;
18
+ }
19
+ }
12
20
  }
13
21
 
14
22
  .dark [class*='pb_file_upload_kit'] {
15
23
  [class*='pb_card_kit'] {
16
24
  border: 1px $text_dk_lighter dashed;
17
25
  }
26
+ &.error {
27
+ [class^='pb_card_kit'] {
28
+ border-color: $error_dark;
29
+ }
30
+ }
18
31
  }
@@ -22,6 +22,7 @@ type FileUploadProps = {
22
22
  maxSize?: number,
23
23
  onFilesAccepted: Callback<File, File>,
24
24
  onFilesRejected: (error: string, files: readonly FileRejection[]) => void,
25
+ error?: string,
25
26
  }
26
27
 
27
28
  const getFormattedFileSize = (fileSize: number): string => {
@@ -36,6 +37,7 @@ const FileUpload = (props: FileUploadProps): React.ReactElement => {
36
37
  customMessage,
37
38
  dark = false,
38
39
  data = {},
40
+ error,
39
41
  htmlOptions = {},
40
42
  maxSize,
41
43
  onFilesAccepted = noop,
@@ -100,7 +102,7 @@ const FileUpload = (props: FileUploadProps): React.ReactElement => {
100
102
 
101
103
  return (
102
104
  <div
103
- className={classnames(buildCss('pb_file_upload_kit'), globalProps(props), className)}
105
+ className={classnames(buildCss('pb_file_upload_kit'), { 'error': error }, globalProps(props), className)}
104
106
  {...dataProps}
105
107
  {...htmlProps}
106
108
  {...getRootProps()}
@@ -118,6 +120,14 @@ const FileUpload = (props: FileUploadProps): React.ReactElement => {
118
120
  }
119
121
  </Body>
120
122
  </Card>
123
+ {error && (
124
+ <Body
125
+ dark={dark}
126
+ marginTop="xxs"
127
+ status="negative"
128
+ text={error}
129
+ />
130
+ )}
121
131
  </div>
122
132
  )
123
133
  }
@@ -0,0 +1 @@
1
+ <%= pb_rails("file_upload", props: {id: "error", error: raw(pb_rails("icon", props: { icon: "warning" }) + " Please upload a valid file")}) %>
@@ -0,0 +1,41 @@
1
+ import React, { useState } from 'react'
2
+ import FileUpload from '../_file_upload'
3
+ import List from '../../pb_list/_list'
4
+ import ListItem from '../../pb_list/_list_item'
5
+ import Icon from '../../pb_icon/_icon'
6
+
7
+ const AcceptedFilesList = ({ files }) => (
8
+ <List>
9
+ {files.map((file) => (
10
+ <ListItem key={file.name}>{file.name}</ListItem>
11
+ ))}
12
+ </List>
13
+ )
14
+
15
+ const FileUploadError = (props) => {
16
+ const [filesToUpload, setFilesToUpload] = useState([])
17
+
18
+ const handleOnFilesAccepted = (files) => {
19
+ setFilesToUpload([...filesToUpload, ...files])
20
+ }
21
+
22
+ const error = (<>
23
+ <Icon icon="warning" /> Please upload a valid file
24
+ </>)
25
+
26
+ return (
27
+ <div>
28
+ <AcceptedFilesList
29
+ files={filesToUpload}
30
+ {...props}
31
+ />
32
+ <FileUpload
33
+ error={error}
34
+ onFilesAccepted={handleOnFilesAccepted}
35
+ {...props}
36
+ />
37
+ </div>
38
+ )
39
+ }
40
+
41
+ export default FileUploadError
@@ -3,6 +3,7 @@ examples:
3
3
  rails:
4
4
  - file_upload_default: File Upload
5
5
  - file_upload_custom: Custom
6
+ - file_upload_error: Error
6
7
 
7
8
  react:
8
9
  - file_upload_default: Default List of files to upload
@@ -10,3 +11,4 @@ examples:
10
11
  - file_upload_custom_message: Add a custom message
11
12
  - file_upload_custom_description: Add your one accepted files description
12
13
  - file_upload_max_size: Set a file size limit
14
+ - file_upload_error: Error
@@ -3,3 +3,4 @@ export { default as FileUploadAccept } from './_file_upload_accept.jsx'
3
3
  export { default as FileUploadCustomMessage } from './_file_upload_custom_message.jsx'
4
4
  export { default as FileUploadCustomDescription } from './_file_upload_custom_description.jsx'
5
5
  export { default as FileUploadMaxSize } from './_file_upload_max_size.jsx'
6
+ export { default as FileUploadError } from './_file_upload_error.jsx'
@@ -9,6 +9,7 @@
9
9
  <%= pb_rails("text_input", props: {
10
10
  type: "file",
11
11
  dark: object.dark,
12
+ error: object.error.presence,
12
13
  input_options: {
13
14
  id: "upload-#{object.id}",
14
15
  classname: "cursor_pointer",
@@ -21,14 +21,20 @@ module Playbook
21
21
  prop :input_options, type: Playbook::Props::HashProp,
22
22
  default: {}
23
23
 
24
+ prop :error, type: Playbook::Props::String
25
+
24
26
  def classname
25
27
  file_upload_class = generate_classname("pb_file_upload_kit")
26
- file_upload_class + full_width_class
28
+ file_upload_class + error_class + full_width_class
27
29
  end
28
30
 
29
31
  def full_width_class
30
32
  full_width ? " full_width" : ""
31
33
  end
34
+
35
+ def error_class
36
+ error.present? ? "_error" : ""
37
+ end
32
38
  end
33
39
  end
34
40
  end
@@ -50,3 +50,21 @@ test('displays custom message', () => {
50
50
  const kit = screen.getByTestId(testid)
51
51
  expect(kit).toHaveTextContent('Hello world!')
52
52
  })
53
+
54
+ test('handles error state with error prop', () => {
55
+ const errorText = "Test error message"
56
+ render(
57
+ <FileUpload
58
+ data={{ testid: testid }}
59
+ error={errorText}
60
+ />
61
+ )
62
+
63
+ const kit = screen.getByTestId(testid)
64
+
65
+ expect(kit).toHaveClass('pb_file_upload_kit')
66
+ expect(kit).toHaveClass('error')
67
+
68
+ const errorElement = screen.getByText(errorText)
69
+ expect(errorElement).toBeInTheDocument()
70
+ })
@@ -42,7 +42,7 @@ $flag-min-resolution: 192dpi;
42
42
  .iti__country-list {
43
43
  min-width: $dropdown-min-width;
44
44
  }
45
- // iti-spacer-horizontal's default is 8px, or $space_xs
45
+ // iti-spacer-horizontal's default is 8px, or $space_xs
46
46
  .iti__country-list .iti__flag, .iti__country-name {
47
47
  margin-right: $space_xs;
48
48
  }
@@ -60,7 +60,7 @@ $flag-min-resolution: 192dpi;
60
60
  color: $focus_input_light;
61
61
  }
62
62
 
63
- .dropdown_open {
63
+ .dropdown_open:not(.error) {
64
64
  .text_input {
65
65
  border-color: $primary !important;
66
66
  }
@@ -76,7 +76,7 @@ $flag-min-resolution: 192dpi;
76
76
  }
77
77
 
78
78
  .iti__divider {
79
- border-bottom: 1px solid $border_light !important;
79
+ border-bottom: 1px solid $border_light !important;
80
80
  }
81
81
 
82
82
  .iti__selected-country-primary {
@@ -96,7 +96,7 @@ $flag-min-resolution: 192dpi;
96
96
  justify-content: center;
97
97
  align-items: center;
98
98
  border-width: 0;
99
- border-radius: $space_xxs;
99
+ border-radius: $space_xxs;
100
100
 
101
101
  &[aria-expanded="true"] {
102
102
  color: $primary_action;
@@ -199,7 +199,7 @@ $flag-min-resolution: 192dpi;
199
199
  }
200
200
 
201
201
  .iti__dropdown-content {
202
- border-radius: $space_xs;
202
+ border-radius: $space_xs;
203
203
  border: 1px solid $border_light !important;
204
204
  position: absolute;
205
205
  top: 100%;
@@ -228,13 +228,13 @@ $flag-min-resolution: 192dpi;
228
228
  }
229
229
 
230
230
  .iti__dropdown-content {
231
- border-radius: $space_xs;
231
+ border-radius: $space_xs;
232
232
  border: 1px solid $border_dark !important;
233
233
  .iti__search-input {
234
234
  background-color: $bg_dark_card;
235
235
  &:hover {
236
236
  background-color: $bg_dark_card;
237
- }
237
+ }
238
238
  &:active,
239
239
  &:focus {
240
240
  background-color: $card_dark;
@@ -243,7 +243,7 @@ $flag-min-resolution: 192dpi;
243
243
  }
244
244
 
245
245
  .iti__divider {
246
- border-bottom: 1px solid $border_dark !important;
246
+ border-bottom: 1px solid $border_dark !important;
247
247
  }
248
248
 
249
249
  .iti__country-list {
@@ -278,7 +278,7 @@ $flag-min-resolution: 192dpi;
278
278
  color: $white;
279
279
  }
280
280
  }
281
-
281
+
282
282
  @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: $flag-min-resolution) {
283
283
  .iti__flag {
284
284
  background-image: url("https://unpkg.com/intl-tel-input@24.6.0/build/img/flags@2x.png");
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import classnames from 'classnames'
3
3
 
4
4
  import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
5
- import { globalProps, globalInlineProps } from '../utilities/globalProps'
5
+ import { globalProps, globalInlineProps, GlobalProps } from '../utilities/globalProps'
6
6
 
7
7
  import Caption from '../pb_caption/_caption'
8
8
 
@@ -19,7 +19,7 @@ type SectionSeparatorProps = {
19
19
  orientation?: "horizontal" | "vertical",
20
20
  text?: string,
21
21
  variant?: "card" | "background",
22
- }
22
+ } & GlobalProps
23
23
 
24
24
  const SectionSeparator = (props: SectionSeparatorProps): React.ReactElement => {
25
25
  const {
@@ -71,7 +71,8 @@
71
71
  }
72
72
  &.error {
73
73
  .text_input_wrapper {
74
- input,
74
+ // The `:not` here prevents error styling from affecting the country search input in the Phone Number Input Kit.
75
+ input:not(.iti__search-input),
75
76
  .text_input {
76
77
  border-color: $error_dark;
77
78
  }
@@ -102,7 +103,8 @@
102
103
  [class*="pb_body_kit"] {
103
104
  margin-top: $space_xs / 2;
104
105
  }
105
- input,
106
+ // The `:not` here prevents error styling from affecting the country search input in the Phone Number Input Kit.
107
+ input:not(.iti__search-input),
106
108
  .text_input {
107
109
  border-color: $error;
108
110
  }