playbook_ui 13.16.0 → 13.17.0.pre.alpha.nodealphaupgrade2157
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +14 -12
- data/app/pb_kits/playbook/_reset.scss +2 -2
- data/app/pb_kits/playbook/index.js +2 -1
- data/app/pb_kits/playbook/pb_advanced_table/Components/CollapsibleTrail.tsx +30 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +62 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/LoadingCell.tsx +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/SortIconButton.tsx +30 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/SubRowHeaderRow.tsx +61 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +127 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/ToggleIconButton.tsx +28 -0
- data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/README.md +288 -0
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +95 -0
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +51 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/BrowserCheck.tsx +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/ExpansionControlHelpers.tsx +63 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/IconHelpers.tsx +8 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/types.ts +8 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +98 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +246 -0
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +345 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_collapsible_trail.jsx +52 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_collapsible_trail.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.jsx +49 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +18 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_expanded_control.jsx +59 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_expanded_control.md +18 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading.jsx +60 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_loading.md +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort.jsx +52 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort.md +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_control.jsx +63 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort_control.md +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_subrow_headers.jsx +57 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_subrow_headers.md +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_options.jsx +61 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_options.md +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.jsx +55 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_description.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_mock_data.js +278 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +12 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +9 -0
- data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_loading.scss +72 -0
- data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_pseudo_states.scss +12 -0
- data/app/pb_kits/playbook/pb_collapsible/_collapsible.scss +2 -2
- data/app/pb_kits/playbook/pb_date_picker/sass_partials/_flatpickr_styles.scss +1 -1
- data/app/pb_kits/playbook/pb_flex/_flex.tsx +1 -1
- data/app/pb_kits/playbook/pb_label_value/_label_value.tsx +1 -1
- data/app/pb_kits/playbook/pb_layout/_layout.tsx +2 -1
- data/app/pb_kits/playbook/pb_layout/layout.test.js +8 -4
- data/app/pb_kits/playbook/pb_legend/_legend.tsx +6 -6
- data/app/pb_kits/playbook/pb_lightbox/Carousel/Slides.tsx +4 -4
- data/app/pb_kits/playbook/pb_lightbox/Carousel/Thumbnail.tsx +1 -1
- data/app/pb_kits/playbook/pb_lightbox/Carousel/index.tsx +3 -3
- data/app/pb_kits/playbook/pb_lightbox/Header/_lightbox_header.tsx +30 -22
- data/app/pb_kits/playbook/pb_lightbox/_lightbox.tsx +5 -5
- data/app/pb_kits/playbook/pb_line_graph/_line_graph.tsx +4 -4
- data/app/pb_kits/playbook/pb_list/_list.tsx +15 -15
- data/app/pb_kits/playbook/pb_list/_list_item.tsx +1 -1
- data/app/pb_kits/playbook/pb_loading_inline/_loading_inline.tsx +9 -9
- data/app/pb_kits/playbook/pb_map/_map.tsx +8 -8
- data/app/pb_kits/playbook/pb_map/_map_controls.tsx +15 -7
- data/app/pb_kits/playbook/pb_map/_map_custom_button.tsx +4 -2
- data/app/pb_kits/playbook/pb_message/_message.tsx +1 -1
- data/app/pb_kits/playbook/pb_message/_message_mention.tsx +6 -6
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +46 -42
- data/app/pb_kits/playbook/pb_multiple_users_stacked/_multiple_users_stacked.tsx +20 -20
- data/app/pb_kits/playbook/pb_nav/_item.tsx +56 -47
- data/app/pb_kits/playbook/pb_nav/_nav.tsx +15 -15
- data/app/pb_kits/playbook/pb_phone_number_input/docs/_phone_number_input_validation.html.erb +5 -7
- data/app/pb_kits/playbook/pb_popover/_popover.tsx +12 -14
- data/app/pb_kits/playbook/pb_popover/docs/_popover_actionable_content.html.erb +30 -0
- data/app/pb_kits/playbook/pb_popover/docs/_popover_actionable_content.jsx +57 -0
- data/app/pb_kits/playbook/pb_popover/docs/example.yml +2 -1
- data/app/pb_kits/playbook/pb_popover/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_popover/popover.test.js +29 -31
- data/app/pb_kits/playbook/pb_table/_table.tsx +32 -29
- data/app/pb_kits/playbook/pb_table/docs/_table_striped.html.erb +48 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_striped.jsx +58 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_striped.md +1 -0
- data/app/pb_kits/playbook/pb_table/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_table/styles/_all.scss +1 -0
- data/app/pb_kits/playbook/pb_table/styles/_striped.scss +19 -0
- data/app/pb_kits/playbook/pb_table/table.rb +7 -1
- data/app/pb_kits/playbook/pb_table/table.test.js +5 -0
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +1 -1
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_with_highlight.jsx +4 -2
- data/app/pb_kits/playbook/playbook-doc.js +2 -0
- data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
- data/dist/menu.yml +105 -3
- data/dist/playbook-rails.js +14 -6
- data/dist/reset.css +1 -2
- data/lib/playbook/version.rb +2 -2
- metadata +55 -7
@@ -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.
|