playbook_ui 13.16.0 → 13.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +14 -12
  3. data/app/pb_kits/playbook/_reset.scss +2 -2
  4. data/app/pb_kits/playbook/index.js +2 -1
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/CollapsibleTrail.tsx +30 -0
  6. data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +62 -0
  7. data/app/pb_kits/playbook/pb_advanced_table/Components/LoadingCell.tsx +5 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/Components/SortIconButton.tsx +30 -0
  9. data/app/pb_kits/playbook/pb_advanced_table/Components/SubRowHeaderRow.tsx +61 -0
  10. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +127 -0
  11. data/app/pb_kits/playbook/pb_advanced_table/Components/ToggleIconButton.tsx +28 -0
  12. data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +5 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/README.md +288 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +95 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +51 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/Utilities/BrowserCheck.tsx +5 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/Utilities/ExpansionControlHelpers.tsx +63 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/Utilities/IconHelpers.tsx +8 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/Utilities/types.ts +8 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +98 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +246 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +345 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_collapsible_trail.jsx +52 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_collapsible_trail.md +1 -0
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.jsx +49 -0
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +18 -0
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_expanded_control.jsx +59 -0
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_expanded_control.md +18 -0
  29. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading.jsx +60 -0
  30. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading.md +3 -0
  31. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort.jsx +52 -0
  32. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort.md +5 -0
  33. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_control.jsx +63 -0
  34. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_control.md +3 -0
  35. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_subrow_headers.jsx +57 -0
  36. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_subrow_headers.md +3 -0
  37. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_options.jsx +61 -0
  38. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_options.md +3 -0
  39. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.jsx +55 -0
  40. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.md +1 -0
  41. data/app/pb_kits/playbook/pb_advanced_table/docs/_description.md +1 -0
  42. data/app/pb_kits/playbook/pb_advanced_table/docs/_mock_data.js +278 -0
  43. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +12 -0
  44. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +9 -0
  45. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_loading.scss +72 -0
  46. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_pseudo_states.scss +12 -0
  47. data/app/pb_kits/playbook/pb_collapsible/_collapsible.scss +2 -2
  48. data/app/pb_kits/playbook/pb_date_picker/sass_partials/_flatpickr_styles.scss +1 -1
  49. data/app/pb_kits/playbook/pb_flex/_flex.tsx +1 -1
  50. data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +1 -1
  51. data/app/pb_kits/playbook/pb_layout/_layout.tsx +2 -1
  52. data/app/pb_kits/playbook/pb_layout/layout.test.js +8 -4
  53. data/app/pb_kits/playbook/pb_legend/_legend.tsx +6 -6
  54. data/app/pb_kits/playbook/pb_lightbox/Carousel/Slides.tsx +4 -4
  55. data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnail.tsx +1 -1
  56. data/app/pb_kits/playbook/pb_lightbox/Carousel/index.tsx +3 -3
  57. data/app/pb_kits/playbook/pb_lightbox/Header/_lightbox_header.tsx +30 -22
  58. data/app/pb_kits/playbook/pb_lightbox/_lightbox.tsx +5 -5
  59. data/app/pb_kits/playbook/pb_line_graph/_line_graph.tsx +4 -4
  60. data/app/pb_kits/playbook/pb_list/_list.tsx +15 -15
  61. data/app/pb_kits/playbook/pb_list/_list_item.tsx +1 -1
  62. data/app/pb_kits/playbook/pb_loading_inline/_loading_inline.tsx +9 -9
  63. data/app/pb_kits/playbook/pb_map/_map.tsx +8 -8
  64. data/app/pb_kits/playbook/pb_map/_map_controls.tsx +15 -7
  65. data/app/pb_kits/playbook/pb_map/_map_custom_button.tsx +4 -2
  66. data/app/pb_kits/playbook/pb_message/_message.tsx +1 -1
  67. data/app/pb_kits/playbook/pb_message/_message_mention.tsx +6 -6
  68. data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +46 -42
  69. data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.tsx +20 -20
  70. data/app/pb_kits/playbook/pb_nav/_item.tsx +56 -47
  71. data/app/pb_kits/playbook/pb_nav/_nav.tsx +15 -15
  72. data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.html.erb +5 -7
  73. data/app/pb_kits/playbook/pb_popover/_popover.tsx +12 -14
  74. data/app/pb_kits/playbook/pb_popover/docs/_popover_actionable_content.html.erb +30 -0
  75. data/app/pb_kits/playbook/pb_popover/docs/_popover_actionable_content.jsx +57 -0
  76. data/app/pb_kits/playbook/pb_popover/docs/example.yml +2 -1
  77. data/app/pb_kits/playbook/pb_popover/docs/index.js +1 -0
  78. data/app/pb_kits/playbook/pb_popover/popover.test.js +29 -31
  79. data/app/pb_kits/playbook/pb_table/_table.tsx +32 -29
  80. data/app/pb_kits/playbook/pb_table/docs/_table_striped.html.erb +48 -0
  81. data/app/pb_kits/playbook/pb_table/docs/_table_striped.jsx +58 -0
  82. data/app/pb_kits/playbook/pb_table/docs/_table_striped.md +1 -0
  83. data/app/pb_kits/playbook/pb_table/docs/example.yml +2 -0
  84. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  85. data/app/pb_kits/playbook/pb_table/styles/_all.scss +1 -0
  86. data/app/pb_kits/playbook/pb_table/styles/_striped.scss +19 -0
  87. data/app/pb_kits/playbook/pb_table/table.rb +7 -1
  88. data/app/pb_kits/playbook/pb_table/table.test.js +5 -0
  89. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +1 -1
  90. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_highlight.jsx +4 -2
  91. data/app/pb_kits/playbook/playbook-doc.js +2 -0
  92. data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
  93. data/dist/menu.yml +105 -3
  94. data/dist/playbook-rails.js +14 -6
  95. data/dist/reset.css +1 -2
  96. data/lib/playbook/version.rb +2 -2
  97. metadata +50 -2
@@ -0,0 +1,246 @@
1
+ import React, { useState, useEffect, useCallback } from "react";
2
+ import classnames from "classnames";
3
+ import { buildAriaProps, buildCss, buildDataProps } from "../utilities/props";
4
+ import { globalProps, GlobalProps } from "../utilities/globalProps";
5
+ import Table from "../pb_table/_table";
6
+ import {
7
+ createColumnHelper,
8
+ getCoreRowModel,
9
+ getExpandedRowModel,
10
+ getSortedRowModel,
11
+ Row,
12
+ useReactTable,
13
+ Getter,
14
+ } from "@tanstack/react-table";
15
+
16
+ import { updateExpandAndCollapseState } from "./Utilities/ExpansionControlHelpers";
17
+
18
+ import { CustomCell } from "./Components/CustomCell";
19
+ import AdvancedTableContext from "./Context/AdvancedTableContext";
20
+ import { TableHeader } from "./SubKits/TableHeader";
21
+ import { TableBody } from "./SubKits/TableBody";
22
+
23
+ import { DataType, ExpandedStateObject } from "./Utilities/types";
24
+
25
+ type AdvancedTableProps = {
26
+ aria?: { [key: string]: string };
27
+ children?: React.ReactNode | React.ReactNode[];
28
+ className?: string;
29
+ columnDefinitions: DataType[];
30
+ data?: { [key: string]: string };
31
+ enableToggleExpansion?: "all" | "header";
32
+ expandedControl?: DataType;
33
+ id?: string;
34
+ initialLoadingRowsCount?: number;
35
+ loading?: boolean | string;
36
+ onRowToggleClick?: (arg: Row<DataType>) => void;
37
+ onToggleExpansionClick?: (arg: Row<DataType>) => void;
38
+ sortControl?: DataType;
39
+ tableData: DataType[];
40
+ tableOptions?: DataType;
41
+ tableProps?: DataType;
42
+ toggleExpansionIcon?: string | string[];
43
+ } & GlobalProps;
44
+
45
+ const AdvancedTable = (props: AdvancedTableProps) => {
46
+ const {
47
+ aria = {},
48
+ children,
49
+ className,
50
+ columnDefinitions,
51
+ data = {},
52
+ enableToggleExpansion = "header",
53
+ expandedControl,
54
+ id,
55
+ initialLoadingRowsCount = 10,
56
+ loading,
57
+ onRowToggleClick,
58
+ onToggleExpansionClick,
59
+ sortControl,
60
+ tableData,
61
+ tableOptions,
62
+ tableProps,
63
+ toggleExpansionIcon = "arrows-from-line",
64
+ } = props;
65
+
66
+ const [loadingStateRowCount, setLoadingStateRowCount] = useState(
67
+ initialLoadingRowsCount
68
+ );
69
+
70
+ // Create a local state for expanded and setExpanded if expandedControl not used
71
+ const [localExpanded, setLocalExpanded] = useState({});
72
+
73
+ // Determine whether to use the prop or the local state
74
+ const expanded = expandedControl ? expandedControl.value : localExpanded;
75
+ const setExpanded = expandedControl
76
+ ? expandedControl.onChange
77
+ : setLocalExpanded;
78
+
79
+ const columnHelper = createColumnHelper<DataType>();
80
+
81
+ //Create cells for first columns
82
+ const createCellFunction = (cellAccessors: string[]) => {
83
+ const columnCells = ({
84
+ row,
85
+ getValue,
86
+ }: {
87
+ row: Row<DataType>;
88
+ getValue: Getter<string>;
89
+ }) => {
90
+ const rowData = row.original;
91
+
92
+ switch (row.depth) {
93
+ case 0: {
94
+ return (
95
+ <CustomCell
96
+ getValue={getValue}
97
+ onRowToggleClick={onRowToggleClick}
98
+ row={row}
99
+ />
100
+ );
101
+ }
102
+ default: {
103
+ // Handle other depths based on cellAccessors
104
+ const depthAccessor = cellAccessors[row.depth - 1]; // Adjust index for depth
105
+ const accessorValue = rowData[depthAccessor];
106
+ return accessorValue ? (
107
+ <CustomCell row={row}
108
+ value={accessorValue}
109
+ />
110
+ ) : (
111
+ "N/A"
112
+ );
113
+ }
114
+ }
115
+ };
116
+
117
+ return columnCells;
118
+ };
119
+
120
+ //Create column array in format needed by Tanstack
121
+ const columns =
122
+ columnDefinitions &&
123
+ columnDefinitions.map((column) => {
124
+ // Define the base column structure
125
+ const columnStructure = {
126
+ ...columnHelper.accessor(column.accessor, {
127
+ header: column.label,
128
+ }),
129
+ };
130
+ if (column.cellAccessors) {
131
+ columnStructure.cell = createCellFunction(column.cellAccessors);
132
+ }
133
+ return columnStructure;
134
+ });
135
+
136
+ //Syntax for sorting Array if we want to manage state ourselves
137
+ const sorting = [
138
+ {
139
+ id: columnDefinitions[0].accessor,
140
+ desc:
141
+ sortControl && sortControl.value !== null
142
+ ? !sortControl.value.desc
143
+ : false,
144
+ },
145
+ ];
146
+
147
+ const expandAndSortState = () => {
148
+ if (sortControl) {
149
+ return { state: { expanded, sorting } };
150
+ } else {
151
+ return { state: { expanded } };
152
+ }
153
+ };
154
+
155
+ //initialize table
156
+ const table = useReactTable({
157
+ data: loading ? Array(loadingStateRowCount).fill({}) : tableData,
158
+ columns,
159
+ onExpandedChange: setExpanded,
160
+ getSubRows: (row) => row.children,
161
+ getCoreRowModel: getCoreRowModel(),
162
+ getExpandedRowModel: getExpandedRowModel(),
163
+ getSortedRowModel: getSortedRowModel(),
164
+ enableSortingRemoval: false,
165
+ sortDescFirst: true,
166
+ ...expandAndSortState(),
167
+ ...tableOptions,
168
+ });
169
+
170
+ const tableRows = table.getRowModel();
171
+
172
+ // Set table row count for loading state
173
+ const updateLoadingStateRowCount = useCallback(() => {
174
+ const rowsCount = table.getRowModel().rows.length;
175
+ if (rowsCount !== loadingStateRowCount && rowsCount !== 0) {
176
+ setLoadingStateRowCount(rowsCount);
177
+ }
178
+ }, [tableData, loadingStateRowCount]);
179
+
180
+ useEffect(() => {
181
+ if (!loading) {
182
+ updateLoadingStateRowCount();
183
+ }
184
+ }, [loading, updateLoadingStateRowCount]);
185
+
186
+ const handleExpandOrCollapse = (row: Row<DataType>) => {
187
+ onToggleExpansionClick && onToggleExpansionClick(row);
188
+
189
+ const expandedState = expanded as ExpandedStateObject;
190
+ const targetParent = row?.parentId;
191
+ return setExpanded(
192
+ updateExpandAndCollapseState(tableRows, expandedState, targetParent)
193
+ );
194
+ };
195
+
196
+ const ariaProps = buildAriaProps(aria);
197
+ const dataProps = buildDataProps(data);
198
+ const classes = classnames(
199
+ buildCss("pb_advanced_table"),
200
+ globalProps(props),
201
+ className
202
+ );
203
+
204
+ return (
205
+ <div {...ariaProps}
206
+ {...dataProps}
207
+ className={classes}
208
+ id={id}
209
+ >
210
+ <AdvancedTableContext.Provider
211
+ value={{
212
+ table,
213
+ handleExpandOrCollapse,
214
+ loading,
215
+ enableToggleExpansion,
216
+ toggleExpansionIcon,
217
+ setExpanded,
218
+ expanded,
219
+ sortControl,
220
+ }}
221
+ >
222
+ <Table
223
+ className={`${loading ? "content-loading" : ""}`}
224
+ dataTable
225
+ numberSpacing="tabular"
226
+ responsive="none"
227
+ {...tableProps}
228
+ >
229
+ {children ? (
230
+ children
231
+ ) : (
232
+ <>
233
+ <TableHeader />
234
+ <TableBody />
235
+ </>
236
+ )}
237
+ </Table>
238
+ </AdvancedTableContext.Provider>
239
+ </div>
240
+ );
241
+ };
242
+
243
+ AdvancedTable.Header = TableHeader;
244
+ AdvancedTable.Body = TableBody;
245
+
246
+ export default AdvancedTable;
@@ -0,0 +1,345 @@
1
+ import React, {useState} from "react";
2
+ import { render, screen } from "../utilities/test-utils";
3
+
4
+ import { AdvancedTable } from "../";
5
+
6
+ const MOCK_DATA = [
7
+ {
8
+ year: "2021",
9
+ quarter: null,
10
+ month: null,
11
+ day: null,
12
+ newEnrollments: "20",
13
+ scheduledMeetings: "10",
14
+ children: [
15
+ {
16
+ year: "2021",
17
+ quarter: "Q1",
18
+ month: null,
19
+ day: null,
20
+ newEnrollments: "2",
21
+ scheduledMeetings: "35",
22
+ },
23
+ ],
24
+ },
25
+ {
26
+ year: "2022",
27
+ quarter: null,
28
+ month: null,
29
+ day: null,
30
+ newEnrollments: "20",
31
+ scheduledMeetings: "10",
32
+ children: [
33
+ {
34
+ year: "2022",
35
+ quarter: "Q1",
36
+ month: null,
37
+ day: null,
38
+ newEnrollments: "2",
39
+ scheduledMeetings: "35",
40
+ },
41
+ ],
42
+ },
43
+ ];
44
+
45
+ const columnDefinitions = [
46
+ {
47
+ accessor: "year",
48
+ label: "Year",
49
+ cellAccessors: ["quarter", "month", "day"],
50
+ },
51
+ {
52
+ accessor: "newEnrollments",
53
+ label: "New Enrollments",
54
+ },
55
+ {
56
+ accessor: "scheduledMeetings",
57
+ label: "Scheduled Meetings",
58
+ },
59
+ ];
60
+
61
+ const subRowHeaders = ["Quarter"]
62
+
63
+ const testId = "advanced_table";
64
+
65
+ const AdvancedTableExpandControl = () => {
66
+ const [expanded, setExpanded] = useState({'0': true})
67
+
68
+ const expandedControl = {
69
+ value: expanded,
70
+ onChange: setExpanded,
71
+ }
72
+
73
+ return (
74
+ <div>
75
+ <AdvancedTable
76
+ columnDefinitions={columnDefinitions}
77
+ data={{ testid: testId }}
78
+ expandedControl={expandedControl}
79
+ tableData={MOCK_DATA}
80
+ />
81
+ </div>
82
+ );
83
+ }
84
+
85
+ const AdvancedTableSortControl = () => {
86
+ const [isSortDesc, setIsSortDesc] = useState({desc: false})
87
+
88
+ const sortControl = {
89
+ value: isSortDesc,
90
+ onChange: setIsSortDesc,
91
+ }
92
+
93
+ return (
94
+ <div>
95
+ <AdvancedTable
96
+ columnDefinitions={columnDefinitions}
97
+ data={{testid: testId}}
98
+ sortControl={sortControl}
99
+ tableData={MOCK_DATA}
100
+ >
101
+ <AdvancedTable.Header enableSorting />
102
+ <AdvancedTable.Body />
103
+ </AdvancedTable>
104
+ </div>
105
+ );
106
+ }
107
+
108
+ const tableOptions = {
109
+ initialState: {
110
+ sorting: [
111
+ {
112
+ id: "year",
113
+ desc: true,
114
+ },
115
+ ],
116
+ },
117
+ }
118
+
119
+ const tableProps = {
120
+ container: false,
121
+ sticky: true
122
+ }
123
+
124
+ test("Generates default kit and classname", () => {
125
+ render(
126
+ <AdvancedTable
127
+ columnDefinitions={columnDefinitions}
128
+ data={{ testid: testId }}
129
+ tableData={MOCK_DATA}
130
+ />
131
+ );
132
+
133
+ const kit = screen.getByTestId(testId);
134
+ expect(kit).toBeInTheDocument();
135
+ expect(kit).toHaveClass('pb_advanced_table')
136
+ });
137
+
138
+ test("Generates aria label", () => {
139
+ render(
140
+ <AdvancedTable
141
+ aria={{label:testId}}
142
+ columnDefinitions={columnDefinitions}
143
+ data={{ testid: testId }}
144
+ tableData={MOCK_DATA}
145
+ />
146
+ );
147
+
148
+ const kit = screen.getByTestId(testId);
149
+ expect(kit).toHaveAttribute('aria-label', testId)
150
+ });
151
+
152
+ test("Row toggle button exists and toggles subrows open and closed", () => {
153
+ render(
154
+ <AdvancedTable
155
+ columnDefinitions={columnDefinitions}
156
+ data={{ testid: testId }}
157
+ tableData={MOCK_DATA}
158
+ />
159
+ );
160
+
161
+ const kit = screen.getByTestId(testId);
162
+ const rowButton = kit.querySelector(".gray-icon.expand-toggle-icon")
163
+ expect(rowButton).toBeInTheDocument()
164
+ const subRow1 = kit.querySelector(".bg-white.depth-sub-row-1")
165
+ expect(subRow1).not.toBeInTheDocument()
166
+ rowButton.click()
167
+ const subRow = kit.querySelector(".bg-white.depth-sub-row-1")
168
+ expect(subRow).toBeInTheDocument()
169
+ });
170
+
171
+ test("toggleExpansionAll button exists and toggles subrows open and closed", () => {
172
+ render(
173
+ <AdvancedTable
174
+ columnDefinitions={columnDefinitions}
175
+ data={{ testid: testId }}
176
+ tableData={MOCK_DATA}
177
+ />
178
+ );
179
+
180
+ const kit = screen.getByTestId(testId);
181
+ const toggleButton = kit.querySelector(".gray-icon.toggle-all-icon")
182
+ expect(toggleButton).toBeInTheDocument()
183
+ const subRow1 = kit.querySelector(".bg-white.depth-sub-row-1")
184
+ expect(subRow1).not.toBeInTheDocument()
185
+ toggleButton.click()
186
+ const subRow = kit.querySelector(".bg-white.depth-sub-row-1")
187
+ expect(subRow).toBeInTheDocument()
188
+ });
189
+
190
+ test("loading state + initialLoadingRowCount prop", () => {
191
+ render(
192
+ <AdvancedTable
193
+ columnDefinitions={columnDefinitions}
194
+ data={{ testid: testId }}
195
+ initialLoadingRowsCount={13}
196
+ loading
197
+ tableData={MOCK_DATA}
198
+ />
199
+ );
200
+
201
+ const kit = screen.getByTestId(testId);
202
+ const table = kit.querySelector('table')
203
+ expect(table).toHaveClass('pb_table table-sm table-responsive-none table-card data_table ns_tabular content-loading')
204
+
205
+ const tableBody = kit.querySelector('tbody')
206
+ const tableRows = tableBody.getElementsByTagName('tr')
207
+ expect(tableRows).toHaveLength(13)
208
+ });
209
+
210
+ test("subRowHeaders are rendered", () => {
211
+ render(
212
+ <AdvancedTable
213
+ columnDefinitions={columnDefinitions}
214
+ data={{ testid: testId }}
215
+ tableData={MOCK_DATA}
216
+ >
217
+ <AdvancedTable.Header />
218
+ <AdvancedTable.Body subRowHeaders={subRowHeaders}/>
219
+ </AdvancedTable>
220
+ );
221
+
222
+ const kit = screen.getByTestId(testId);
223
+
224
+ const rowButton = kit.querySelector(".gray-icon.expand-toggle-icon")
225
+ rowButton.click()
226
+
227
+ const subRowHeader = kit.querySelector(".custom-row.bg-silver")
228
+ expect(subRowHeader).toBeInTheDocument()
229
+ });
230
+
231
+ test("expandControl prop works as expected", () => {
232
+ render (<AdvancedTableExpandControl/>)
233
+
234
+ const kit = screen.getByTestId(testId);
235
+ const subRow = kit.querySelector(".bg-white.depth-sub-row-1")
236
+ expect(subRow).toBeInTheDocument()
237
+ })
238
+
239
+ test("tableOptions prop functions as expected", () => {
240
+ render(
241
+ <AdvancedTable
242
+ columnDefinitions={columnDefinitions}
243
+ data={{ testid: testId }}
244
+ tableData={MOCK_DATA}
245
+ tableOptions={tableOptions}
246
+ />
247
+ );
248
+
249
+ const kit = screen.getByTestId(testId);
250
+ const row1 = kit.getElementsByTagName('tr')[1]
251
+
252
+ expect(row1.id).toBe("1-1-0-row")
253
+ });
254
+
255
+ test("tableProps prop functions as expected", () => {
256
+ render(
257
+ <AdvancedTable
258
+ columnDefinitions={columnDefinitions}
259
+ data={{ testid: testId }}
260
+ tableData={MOCK_DATA}
261
+ tableProps={tableProps}
262
+ />
263
+ );
264
+
265
+ const kit = screen.getByTestId(testId);
266
+ const table = kit.querySelector('table')
267
+ expect(table).toHaveClass("pb_table table-sm table-responsive-none data_table sticky-header ns_tabular")
268
+ });
269
+
270
+ test("enableExpansionIcon changes icon", () => {
271
+ render(
272
+ <AdvancedTable
273
+ columnDefinitions={columnDefinitions}
274
+ data={{ testid: testId }}
275
+ tableData={MOCK_DATA}
276
+ tableProps={tableProps}
277
+ toggleExpansionIcon= "chevron-up"
278
+ />
279
+ );
280
+
281
+ const kit = screen.getByTestId(testId);
282
+ const tableHead = kit.querySelector('table')
283
+ const toggleIcon= tableHead.querySelector(".pb_icon_kit")
284
+ expect(toggleIcon).toHaveClass("fa-chevron-up")
285
+ });
286
+
287
+ test("sortIcon changes icon", () => {
288
+ render(
289
+ <AdvancedTable
290
+ columnDefinitions={columnDefinitions}
291
+ data={{ testid: testId }}
292
+ tableData={MOCK_DATA}
293
+ tableProps={tableProps}
294
+ >
295
+ <AdvancedTable.Header
296
+ enableSorting
297
+ sortIcon= {["chevron-up","chevron-down"]}
298
+ />
299
+ <AdvancedTable.Body />
300
+ </AdvancedTable>
301
+ );
302
+
303
+ const kit = screen.getByTestId(testId);
304
+ const sortIcon = kit.querySelector('.sort-button-icon')
305
+ const icon= sortIcon.querySelector(".pb_icon_kit")
306
+ expect(icon).toHaveClass("fa-chevron-down")
307
+ });
308
+
309
+ test("Sort icon renders with enableSorting + sortControl works as expected", () => {
310
+ render (<AdvancedTableSortControl/>)
311
+
312
+ const kit = screen.getByTestId(testId);
313
+ const sortIcon = kit.querySelector(".sort-button-icon")
314
+ expect(sortIcon).toBeInTheDocument()
315
+
316
+ const row1 = kit.getElementsByTagName('tr')[1]
317
+
318
+ expect(row1.id).toBe("1-1-0-row")
319
+ })
320
+
321
+ test("sort button exists and sorts column data", () => {
322
+ render(
323
+ <AdvancedTable
324
+ columnDefinitions={columnDefinitions}
325
+ data={{ testid: testId }}
326
+ tableData={MOCK_DATA}
327
+ >
328
+ <AdvancedTable.Header enableSorting />
329
+ <AdvancedTable.Body />
330
+ </AdvancedTable>
331
+ );
332
+
333
+ const kit = screen.getByTestId(testId);
334
+
335
+ const sortButton= kit.querySelector(".pb_flex_kit_orientation_row_justify_content_between_align_items_top_spacing_none.pl_xxs.cursor_pointer.header-sort-button.pb_th_link")
336
+ expect(sortButton).toBeInTheDocument()
337
+
338
+ const row1 = kit.getElementsByTagName('tr')[1]
339
+
340
+ expect(row1.id).toBe("0-0-0-row")
341
+ sortButton.click()
342
+
343
+ const row2 = kit.getElementsByTagName('tr')[2]
344
+ expect(row2.id).toBe("0-0-0-row")
345
+ });
@@ -0,0 +1,52 @@
1
+ import React from "react";
2
+ import { AdvancedTable } from "../../";
3
+ import { MOCK_DATA } from "./_mock_data";
4
+
5
+ const AdvancedTableCollapsibleTrail = (props) => {
6
+ const columnDefinitions = [
7
+ {
8
+ accessor: "year",
9
+ label: "Year",
10
+ cellAccessors: ["quarter", "month", "day"],
11
+ },
12
+ {
13
+ accessor: "newEnrollments",
14
+ label: "New Enrollments",
15
+ },
16
+ {
17
+ accessor: "scheduledMeetings",
18
+ label: "Scheduled Meetings",
19
+ },
20
+ {
21
+ accessor: "attendanceRate",
22
+ label: "Attendance Rate",
23
+ },
24
+ {
25
+ accessor: "completedClasses",
26
+ label: "Completed Classes",
27
+ },
28
+ {
29
+ accessor: "classCompletionRate",
30
+ label: "Class Completion Rate",
31
+ },
32
+ {
33
+ accessor: "graduatedStudents",
34
+ label: "Graduated Students",
35
+ },
36
+ ];
37
+
38
+ return (
39
+ <div>
40
+ <AdvancedTable
41
+ columnDefinitions={columnDefinitions}
42
+ tableData={MOCK_DATA}
43
+ {...props}
44
+ >
45
+ <AdvancedTable.Header />
46
+ <AdvancedTable.Body collapsibleTrail={false} />
47
+ </AdvancedTable>
48
+ </div>
49
+ );
50
+ };
51
+
52
+ export default AdvancedTableCollapsibleTrail;
@@ -0,0 +1 @@
1
+ `collapsibleTrail` is an optional prop that is set to 'true' by default. If set to 'false', it will remove the trail on the left of rows when subRows are toggled open.
@@ -0,0 +1,49 @@
1
+ import React from "react";
2
+ import { AdvancedTable } from "../../";
3
+ import { MOCK_DATA } from "./_mock_data";
4
+
5
+ const AdvancedTableDefault = (props) => {
6
+ const columnDefinitions = [
7
+ {
8
+ accessor: "year",
9
+ label: "Year",
10
+ cellAccessors: ["quarter", "month", "day"],
11
+ },
12
+ {
13
+ accessor: "newEnrollments",
14
+ label: "New Enrollments",
15
+ },
16
+ {
17
+ accessor: "scheduledMeetings",
18
+ label: "Scheduled Meetings",
19
+ },
20
+ {
21
+ accessor: "attendanceRate",
22
+ label: "Attendance Rate",
23
+ },
24
+ {
25
+ accessor: "completedClasses",
26
+ label: "Completed Classes",
27
+ },
28
+ {
29
+ accessor: "classCompletionRate",
30
+ label: "Class Completion Rate",
31
+ },
32
+ {
33
+ accessor: "graduatedStudents",
34
+ label: "Graduated Students",
35
+ },
36
+ ];
37
+
38
+ return (
39
+ <div>
40
+ <AdvancedTable
41
+ columnDefinitions={columnDefinitions}
42
+ tableData={MOCK_DATA}
43
+ {...props}
44
+ />
45
+ </div>
46
+ );
47
+ };
48
+
49
+ export default AdvancedTableDefault;
@@ -0,0 +1,18 @@
1
+ The AdvancedTable kit accepts tree data and automatically renders expansion controls for nested subrows, to any depth, based on the data it is given. In it's simplest form, __the kit has two required props__:
2
+
3
+ ### tableData
4
+
5
+ `tableData` accepts an array of objects as the table data. Each object is a table row, and each key:value pair within an object is a column value within that row. Nested children within a data object are automatically rendered as subrows under their parent row. Each parent row is prepended with expansion controls for toggling its nested child rows. The `toggleExpansionAll` button in the first column header can also be used to toggle expansion of all parent rows within the table.
6
+
7
+ For a visual of the data structure needed for `tableData`, see [here](https://github.com/powerhome/playbook/tree/master/playbook/app/pb_kits/playbook/pb_advanced_table#readme).
8
+
9
+ ### columnDefinitions
10
+
11
+ `columnDefinitions` maps to the columns prop on the Tanstack table. Column definitions are the single most important part of building a table as they are responsible for building the underlying data model that is used for all sorting, expansion, etc. `ColumnDefinitions` in the AdvancedTable kit is a array of objects as seen in the code snippet below. Each object within the array has two REQUIRED items:
12
+
13
+ - `accessor`: this is the key from your data for the value you want rendered in that column
14
+ - `label`: this is what will be rendered as the column header label
15
+
16
+ There is also one optional item that is only required if the table has nested data:
17
+
18
+ - `cellAccessors`: This is an array of strings that represent keys from your data object. This is only required for the first column in case of nested data. If you have nested data, the AdvancedTable needs to know what to render in that first column for nested items. This array represents the nested data in the order you want it rendered.