playbook_ui 13.16.0.pre.alpha.play1141iconkitusinglibrary2060 → 13.16.0.pre.alpha.play1141iconkitusinglibrary2107

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +14 -12
  3. data/app/pb_kits/playbook/index.js +2 -1
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/CollapsibleTrail.tsx +30 -0
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +62 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/Components/LoadingCell.tsx +5 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/Components/SortIconButton.tsx +30 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/Components/SubRowHeaderRow.tsx +61 -0
  9. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +128 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/Components/ToggleIconButton.tsx +28 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +5 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/README.md +288 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +95 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +51 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/Utilities/BrowserCheck.tsx +5 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/Utilities/ExpansionControlHelpers.tsx +63 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/Utilities/IconHelpers.tsx +8 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/Utilities/types.ts +8 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +98 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +245 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +56 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.jsx +49 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +13 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort.jsx +57 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_description.md +1 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/_mock_data.js +278 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +6 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_loading.scss +71 -0
  30. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_pseudo_states.scss +12 -0
  31. data/app/pb_kits/playbook/pb_flex/_flex.tsx +1 -1
  32. data/app/pb_kits/playbook/pb_icon/_icon.scss +6 -48
  33. data/app/pb_kits/playbook/pb_icon/_icon.tsx +41 -99
  34. data/app/pb_kits/playbook/pb_icon/docs/_icon_custom.md +0 -9
  35. data/app/pb_kits/playbook/pb_icon/icon.rb +11 -20
  36. data/app/pb_kits/playbook/pb_nav/_nav_item.test.js +2 -2
  37. data/app/pb_kits/playbook/pb_table/_table.tsx +29 -29
  38. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  39. data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
  40. data/dist/menu.yml +4 -1
  41. data/dist/playbook-rails.js +6 -6
  42. data/lib/playbook/version.rb +1 -1
  43. metadata +29 -2
@@ -0,0 +1,288 @@
1
+ # Advanced Table Kit Data Structure
2
+
3
+ The AdvancedTable Kit's `tableData` prop consumes the data that will render the table and as such has a specific structure. It must be an array of objects, where the key/value pairs will become the values rendered within each column. If children are present, they must also take the form of an array of objects. The kit will automatically render `children` as subRows.
4
+
5
+ Here is the data structure being used within the kits doc examples:
6
+
7
+ ```
8
+ const MOCK_DATA = [
9
+ {
10
+ year: "2021",
11
+ quarter: null,
12
+ month: null,
13
+ day: null,
14
+ newEnrollments: "20",
15
+ scheduledMeetings: "10",
16
+ attendanceRate: "51%",
17
+ completedClasses: "3",
18
+ classCompletionRate: "33%",
19
+ graduatedStudents: "19",
20
+ children: [
21
+ {
22
+ year: "2021",
23
+ quarter: "Q1",
24
+ month: null,
25
+ day: null,
26
+ newEnrollments: "2",
27
+ scheduledMeetings: "35",
28
+ attendanceRate: "32%",
29
+ completedClasses: "15",
30
+ classCompletionRate: "52%",
31
+ graduatedStudents: "36",
32
+ children: [
33
+ {
34
+ year: "2021",
35
+ quarter: "Q1",
36
+ month: "January",
37
+ day: null,
38
+ newEnrollments: "16",
39
+ scheduledMeetings: "20",
40
+ attendanceRate: "11%",
41
+ completedClasses: "13",
42
+ classCompletionRate: "47%",
43
+ graduatedStudents: "28",
44
+ children: [
45
+ {
46
+ year: "2021",
47
+ quarter: "Q1",
48
+ month: "January",
49
+ day: "10",
50
+ newEnrollments: "34",
51
+ scheduledMeetings: "28",
52
+ attendanceRate: "97%",
53
+ completedClasses: "20",
54
+ classCompletionRate: "15%",
55
+ graduatedStudents: "17",
56
+ },
57
+ {
58
+ year: "2021",
59
+ quarter: "Q1",
60
+ month: "January",
61
+ day: "20",
62
+ newEnrollments: "43",
63
+ scheduledMeetings: "23",
64
+ attendanceRate: "66%",
65
+ completedClasses: "26",
66
+ classCompletionRate: "47%",
67
+ graduatedStudents: "9",
68
+ },
69
+ ],
70
+ },
71
+ {
72
+ year: "2021",
73
+ quarter: "Q1",
74
+ month: "February",
75
+ day: null,
76
+ newEnrollments: "20",
77
+ scheduledMeetings: "41",
78
+ attendanceRate: "95%",
79
+ completedClasses: "26",
80
+ classCompletionRate: "83%",
81
+ graduatedStudents: "43",
82
+ children: [
83
+ {
84
+ year: "2011",
85
+ quarter: "Q1",
86
+ month: "February",
87
+ day: "15",
88
+ newEnrollments: "19",
89
+ scheduledMeetings: "35",
90
+ attendanceRate: "69%",
91
+ completedClasses: "8",
92
+ classCompletionRate: "75%",
93
+ graduatedStudents: "23",
94
+ },
95
+ ],
96
+ },
97
+ ],
98
+ },
99
+ ],
100
+ },
101
+ {
102
+ year: "2022",
103
+ quarter: null,
104
+ month: null,
105
+ day: null,
106
+ newEnrollments: "25",
107
+ scheduledMeetings: "17",
108
+ attendanceRate: "75%",
109
+ completedClasses: "5",
110
+ classCompletionRate: "45%",
111
+ graduatedStudents: "32",
112
+ children: [
113
+ {
114
+ year: "2022",
115
+ quarter: "Q1",
116
+ month: null,
117
+ day: null,
118
+ newEnrollments: "2",
119
+ scheduledMeetings: "35",
120
+ attendanceRate: "32%",
121
+ completedClasses: "15",
122
+ classCompletionRate: "52%",
123
+ graduatedStudents: "36",
124
+ children: [
125
+ {
126
+ year: "2022",
127
+ quarter: "Q1",
128
+ month: "January",
129
+ day: null,
130
+ newEnrollments: "16",
131
+ scheduledMeetings: "20",
132
+ attendanceRate: "11%",
133
+ completedClasses: "13",
134
+ classCompletionRate: "47%",
135
+ graduatedStudents: "28",
136
+ children: [
137
+ {
138
+ year: "2022",
139
+ quarter: "Q1",
140
+ month: "January",
141
+ day: "15",
142
+ newEnrollments: "34",
143
+ scheduledMeetings: "28",
144
+ attendanceRate: "97%",
145
+ completedClasses: "20",
146
+ classCompletionRate: "15%",
147
+ graduatedStudents: "17",
148
+ },
149
+ {
150
+ year: "2022",
151
+ quarter: "Q1",
152
+ month: "January",
153
+ day: "25",
154
+ newEnrollments: "43",
155
+ scheduledMeetings: "23",
156
+ attendanceRate: "66%",
157
+ completedClasses: "26",
158
+ classCompletionRate: "47%",
159
+ graduatedStudents: "9",
160
+ },
161
+ ],
162
+ },
163
+ {
164
+ year: "2022",
165
+ quarter: "Q1",
166
+ month: "May",
167
+ day: null,
168
+ newEnrollments: "20",
169
+ scheduledMeetings: "41",
170
+ attendanceRate: "95%",
171
+ completedClasses: "26",
172
+ classCompletionRate: "83%",
173
+ graduatedStudents: "43",
174
+ children: [
175
+ {
176
+ year: "2011",
177
+ quarter: "Q1",
178
+ month: "May",
179
+ day: "2",
180
+ newEnrollments: "19",
181
+ scheduledMeetings: "35",
182
+ attendanceRate: "69%",
183
+ completedClasses: "8",
184
+ classCompletionRate: "75%",
185
+ graduatedStudents: "23",
186
+ },
187
+ ],
188
+ },
189
+ ],
190
+ },
191
+ ],
192
+ },
193
+ {
194
+ year: "2023",
195
+ quarter: null,
196
+ month: null,
197
+ day: null,
198
+ newEnrollments: "10",
199
+ scheduledMeetings: "15",
200
+ attendanceRate: "65%",
201
+ completedClasses: "4",
202
+ classCompletionRate: "49%",
203
+ graduatedStudents: "29",
204
+ children: [
205
+ {
206
+ year: "2023",
207
+ quarter: "Q1",
208
+ month: null,
209
+ day: null,
210
+ newEnrollments: "2",
211
+ scheduledMeetings: "35",
212
+ attendanceRate: "32%",
213
+ completedClasses: "15",
214
+ classCompletionRate: "52%",
215
+ graduatedStudents: "36",
216
+ children: [
217
+ {
218
+ year: "2023",
219
+ quarter: "Q1",
220
+ month: "March",
221
+ day: null,
222
+ newEnrollments: "16",
223
+ scheduledMeetings: "20",
224
+ attendanceRate: "11%",
225
+ completedClasses: "13",
226
+ classCompletionRate: "47%",
227
+ graduatedStudents: "28",
228
+ children: [
229
+ {
230
+ year: "2023",
231
+ quarter: "Q1",
232
+ month: "March",
233
+ day: "10",
234
+ newEnrollments: "34",
235
+ scheduledMeetings: "28",
236
+ attendanceRate: "97%",
237
+ completedClasses: "20",
238
+ classCompletionRate: "15%",
239
+ graduatedStudents: "17",
240
+ },
241
+ {
242
+ year: "2023",
243
+ quarter: "Q1",
244
+ month: "March",
245
+ day: "11",
246
+ newEnrollments: "43",
247
+ scheduledMeetings: "23",
248
+ attendanceRate: "66%",
249
+ completedClasses: "26",
250
+ classCompletionRate: "47%",
251
+ graduatedStudents: "9",
252
+ },
253
+ ],
254
+ },
255
+ {
256
+ year: "2023",
257
+ quarter: "Q1",
258
+ month: "April",
259
+ day: null,
260
+ newEnrollments: "20",
261
+ scheduledMeetings: "41",
262
+ attendanceRate: "95%",
263
+ completedClasses: "26",
264
+ classCompletionRate: "83%",
265
+ graduatedStudents: "43",
266
+ children: [
267
+ {
268
+ year: "2023",
269
+ quarter: "Q1",
270
+ month: "April",
271
+ day: "15",
272
+ newEnrollments: "19",
273
+ scheduledMeetings: "35",
274
+ attendanceRate: "69%",
275
+ completedClasses: "8",
276
+ classCompletionRate: "75%",
277
+ graduatedStudents: "23",
278
+ },
279
+ ],
280
+ },
281
+ ],
282
+ },
283
+ ],
284
+ },
285
+ ];
286
+
287
+
288
+ ```
@@ -0,0 +1,95 @@
1
+ import React, { useContext } from "react"
2
+ import LoadingInline from "../../pb_loading_inline/_loading_inline"
3
+ import { flexRender, Row } from "@tanstack/react-table"
4
+
5
+ import { SubRowHeaderRow } from "../Components/SubRowHeaderRow"
6
+ import { LoadingCell } from "../Components/LoadingCell"
7
+ import { renderCollapsibleTrail } from "../Components/CollapsibleTrail"
8
+ import AdvancedTableContext from "../Context/AdvancedTableContext"
9
+ import { isChrome } from "../Utilities/BrowserCheck"
10
+ import { DataType } from "../Utilities/types"
11
+
12
+ type TableBodyProps = {
13
+ collapsibleTrail?: boolean
14
+ subRowHeaders?: string[]
15
+ }
16
+
17
+ export const TableBody = ({
18
+ collapsibleTrail = true,
19
+ subRowHeaders,
20
+ }: TableBodyProps) => {
21
+ const {
22
+ enableToggleExpansion,
23
+ handleExpandOrCollapse,
24
+ loading,
25
+ table,
26
+ } = useContext(AdvancedTableContext)
27
+ return (
28
+ <>
29
+ <tbody>
30
+ {table.getRowModel().rows.map((row: Row<DataType>) => {
31
+ const isExpandable = row.getIsExpanded()
32
+ const isFirstChildofSubrow = row.depth > 0 && row.index === 0
33
+ const rowHasNoChildren = !row.original.children?.length
34
+ const numberOfColumns = table.getAllFlatColumns().length
35
+
36
+ return (
37
+ <React.Fragment key={`${row.index}-${row.id}-${row.depth}-row`}>
38
+ {isFirstChildofSubrow && subRowHeaders && (
39
+ <SubRowHeaderRow
40
+ collapsibleTrail={collapsibleTrail}
41
+ enableToggleExpansion={enableToggleExpansion}
42
+ onClick={handleExpandOrCollapse}
43
+ row={row}
44
+ subRowHeaders={subRowHeaders}
45
+ table={table}
46
+ />
47
+ )}
48
+
49
+ <tr
50
+ className={`${isExpandable ? "bg-silver" : "bg-white"} ${
51
+ row.depth > 0 ? `depth-sub-row-${row.depth}` : ""
52
+ }`}
53
+ id={`${row.index}-${row.id}-${row.depth}-row`}
54
+ >
55
+ {row.getVisibleCells().map((cell, i) => (
56
+ <td
57
+ align="right"
58
+ className={`${cell.id}-cell position_relative ${
59
+ isChrome() ? "chrome-styles" : ""
60
+ }`}
61
+ key={`${cell.id}-data`}
62
+ >
63
+ {collapsibleTrail &&
64
+ i === 0 &&
65
+ row.depth > 0 &&
66
+ renderCollapsibleTrail(row.depth)}
67
+ <span id={`${cell.id}-span`}>
68
+ {loading ? (
69
+ <LoadingCell />
70
+ ) : (
71
+ flexRender(
72
+ cell.column.columnDef.cell,
73
+ cell.getContext()
74
+ )
75
+ )}
76
+ </span>
77
+ </td>
78
+ ))}
79
+ </tr>
80
+
81
+ {/* Display LoadingInline if Row Data is querying and there are no children already */}
82
+ {isExpandable && rowHasNoChildren && row.depth === 0 ? (
83
+ <tr key={`${row.id}-row`}>
84
+ <td colSpan={numberOfColumns}>
85
+ <LoadingInline />
86
+ </td>
87
+ </tr>
88
+ ) : null}
89
+ </React.Fragment>
90
+ )
91
+ })}
92
+ </tbody>
93
+ </>
94
+ )
95
+ }
@@ -0,0 +1,51 @@
1
+ import React, { useContext } from "react"
2
+ import { HeaderGroup } from "@tanstack/react-table"
3
+ import AdvancedTableContext from "../Context/AdvancedTableContext"
4
+ import { TableHeaderCell } from "../Components/TableHeaderCell"
5
+ import { DataType } from "../Utilities/types"
6
+
7
+ type TableHeaderProps = {
8
+ children?: React.ReactNode | React.ReactNode[]
9
+ enableSorting?: boolean
10
+ headerId?: string
11
+ sortIcon?: string | string[]
12
+ }
13
+
14
+ export const TableHeader = ({
15
+ children,
16
+ enableSorting = false,
17
+ headerId,
18
+ sortIcon = ["arrow-up-short-wide", "arrow-down-short-wide"],
19
+ }: TableHeaderProps) => {
20
+ const {
21
+ enableToggleExpansion,
22
+ handleExpandOrCollapse,
23
+ loading,
24
+ table,
25
+ } = useContext(AdvancedTableContext)
26
+
27
+ return (
28
+ <>
29
+ <thead>
30
+ {/* Get the header groups (only one in this example) */}
31
+ {table.getHeaderGroups().map((headerGroup: HeaderGroup<DataType>) => (
32
+ <tr key={`${headerGroup.id}-headerGroup`}>
33
+ {headerGroup.headers.map(header => (
34
+ <TableHeaderCell
35
+ enableSorting={enableSorting}
36
+ enableToggleExpansion={enableToggleExpansion}
37
+ handleExpandOrCollapse={handleExpandOrCollapse}
38
+ header={header}
39
+ headerChildren={children}
40
+ headerId={headerId}
41
+ key={`${header.id}-header`}
42
+ loading={loading}
43
+ sortIcon={sortIcon}
44
+ />
45
+ ))}
46
+ </tr>
47
+ ))}
48
+ </thead>
49
+ </>
50
+ )
51
+ }
@@ -0,0 +1,5 @@
1
+ //Checking browser. Using this to add classname and css for browser specific issues with table borders
2
+ export const isChrome = () => {
3
+ const userAgent = navigator.userAgent.toLowerCase()
4
+ return userAgent.includes("chrome") && !userAgent.includes("edg")
5
+ }
@@ -0,0 +1,63 @@
1
+ import { RowModel } from "@tanstack/react-table"
2
+ import { DataType, ExpandedStateObject } from "./types"
3
+
4
+ const filterExpandableRows = (expandedState: Record<string, boolean>) => {
5
+ for (const expandedRow in expandedState) {
6
+ if (expandedState[expandedRow] === false) {
7
+ delete expandedState[expandedRow]
8
+ }
9
+ }
10
+ return expandedState
11
+ }
12
+
13
+ export const updateExpandAndCollapseState = (
14
+ tableRows: RowModel<DataType>,
15
+ expanded: Record<string, boolean>,
16
+ targetParent: string
17
+ ) => {
18
+ const updateExpandedRows: Record<string, boolean> = {}
19
+ const rows = tableRows.flatRows
20
+ // Variable checks if all rows in a section have same expansion state or not
21
+ let isExpansionConsistent = true
22
+ const areRowsExpanded = new Set<boolean>()
23
+
24
+ // Update isExpansionConsistent variable
25
+ for (const row of rows) {
26
+ if (
27
+ row.getCanExpand() &&
28
+ (targetParent === undefined
29
+ ? row.depth === 0
30
+ : targetParent === row.parentId)
31
+ ) {
32
+ areRowsExpanded.add(row.getIsExpanded())
33
+ if (areRowsExpanded.size > 1) {
34
+ isExpansionConsistent = false
35
+ break
36
+ }
37
+ }
38
+ }
39
+
40
+ // The if statement runs only for row depth 0, the else statement for the rest
41
+ if (targetParent === undefined) {
42
+ rows.forEach(row => {
43
+ if (row.depth === 0) {
44
+ updateExpandedRows[row.id] = !isExpansionConsistent
45
+ ? true
46
+ : !row.getIsExpanded()
47
+ }
48
+ })
49
+ } else {
50
+ for (const row of rows) {
51
+ if (row.getCanExpand() && targetParent === row.parentId) {
52
+ updateExpandedRows[row.id] = !isExpansionConsistent
53
+ ? true
54
+ : !row.getIsExpanded()
55
+ }
56
+ }
57
+ }
58
+
59
+ return filterExpandableRows({
60
+ ...(expanded as ExpandedStateObject),
61
+ ...updateExpandedRows,
62
+ })
63
+ }
@@ -0,0 +1,8 @@
1
+ // Logic for handling icons related props to allow for string OR array of strings
2
+ export const displayIcon = (icon: string | string[]) => {
3
+ if (typeof icon === "string") {
4
+ return [icon, icon]
5
+ }
6
+ return icon
7
+ }
8
+
@@ -0,0 +1,8 @@
1
+ import { ExpandedState } from "@tanstack/react-table"
2
+
3
+ export type ExpandedStateObject = Extract<
4
+ ExpandedState,
5
+ Record<string, boolean>
6
+ >
7
+
8
+ export type DataType = { [key: string]: any }
@@ -0,0 +1,98 @@
1
+ @import "../tokens/colors";
2
+ @import "../tokens/opacity";
3
+ @import "../tokens/border_radius";
4
+ @import "../tokens/spacing";
5
+ @import "./scss_partials/loading";
6
+ @import "./scss_partials/pseudo_states";
7
+
8
+ .pb_advanced_table {
9
+ $border-color: 1px solid $border_light !important;
10
+
11
+ [id$="-span"] {
12
+ word-wrap: normal;
13
+ }
14
+
15
+ .bg-silver {
16
+ background-color: lighten($silver, $opacity_7);
17
+ }
18
+
19
+ .bg-white {
20
+ background-color: $white;
21
+ }
22
+
23
+ .full-width {
24
+ width: 100%;
25
+ }
26
+
27
+ .table-header-cells:first-child {
28
+ min-width: 180px;
29
+ }
30
+
31
+ .table-header-cells-active:first-child {
32
+ color: $primary !important;
33
+ }
34
+
35
+ // Icons
36
+ .button-icon {
37
+ display: flex;
38
+ justify-content: center;
39
+ align-items: center;
40
+ background: none;
41
+ border: none;
42
+ }
43
+
44
+ .gray-icon {
45
+ color: $text_lt_light;
46
+ @extend %primary-color-pseudo;
47
+ }
48
+
49
+ .sort-button-icon {
50
+ @extend .button-icon;
51
+ padding: 2px;
52
+ }
53
+
54
+ .toggle-all-icon {
55
+ @extend .button-icon;
56
+ @extend %primary-color-pseudo;
57
+ padding: 2px 0;
58
+
59
+ &:focus-visible {
60
+ border-radius: $border_rad_lighter;
61
+ }
62
+ }
63
+
64
+ .expand-toggle-icon {
65
+ @extend .button-icon;
66
+ @extend %primary-color-pseudo;
67
+ position: relative;
68
+ bottom: 1px;
69
+ width: 18px;
70
+ height: 18px;
71
+ border-radius: 50%;
72
+ }
73
+
74
+ .header-sort-button {
75
+ @extend %primary-color-pseudo;
76
+ width: 100%;
77
+
78
+ &:focus-visible {
79
+ border-radius: $border_rad_heavier;
80
+ }
81
+ }
82
+
83
+ // Vertical separator
84
+ .table-header-cells:first-child,
85
+ td:first-child {
86
+ box-shadow: 1px 0px 0px 0px #e4e8f0 !important;
87
+ }
88
+
89
+ .chrome-styles:first-child {
90
+ border-right: $border-color;
91
+ }
92
+
93
+ .table-card {
94
+ .chrome-styles:first-child {
95
+ border-right: $transparent !important;
96
+ }
97
+ }
98
+ }