playbook_ui 14.20.0.pre.alpha.PLAY22398040 → 14.20.0.pre.alpha.PLAY22408048
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +116 -49
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +58 -2
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +16 -4
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +7 -3
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +10 -3
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +61 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_no_subrows.jsx +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows.jsx +57 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_pinned_rows_react.md +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +3 -3
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_advanced_table/index.js +2 -0
- data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +13 -4
- data/app/pb_kits/playbook/pb_draggable/context/index.tsx +17 -58
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +12 -3
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_close_on_select.jsx +42 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_close_on_select.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +14 -10
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +26 -15
- data/app/pb_kits/playbook/pb_popover/index.ts +9 -4
- data/app/pb_kits/playbook/pb_table/styles/_mobile_collapse.scss +1 -1
- data/dist/chunks/{_typeahead-CRW6dJbW.js → _typeahead-C0OGBz_9.js} +1 -1
- data/dist/chunks/_weekday_stacked-BbY_mMKV.js +45 -0
- data/dist/chunks/{lib-D5R1BjUn.js → lib-CLDGEByA.js} +1 -1
- data/dist/chunks/{pb_form_validation-BZ2AVAi_.js → pb_form_validation-C-ccDsK6.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.js +1 -1
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +9 -6
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_no_subrows.html.erb +0 -33
- data/dist/chunks/_weekday_stacked-CqoPM8b5.js +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87bff1055c6b09cbc4779f19f9dabbec88eb15968de35487bff99e9f94a0385c
|
4
|
+
data.tar.gz: a64264b358a91d00ce79688e42ebe1f35c44a5b62e23c5e59a6404a985596385
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80d9da8956b81920b2a2847ca764c4b50683eb350b32bd94948d8fcdd4a9560f00a8b6e0d91c8525d95bbf438eb528f3c59b0a71e22af982a79207cd17c77e35
|
7
|
+
data.tar.gz: b8e950da00f3107b3775c7e104999320216c9dd4c922dbd11a0357f60a1b539bc5f287d0300092945f38c7ff082fe5b075d54bade46f712ce535ce50c1512156
|
@@ -19,6 +19,71 @@ type RegularTableViewProps = {
|
|
19
19
|
subRowHeaders?: string[]
|
20
20
|
}
|
21
21
|
|
22
|
+
// Helper function for Table Rendering
|
23
|
+
const TableCellRenderer = ({
|
24
|
+
row,
|
25
|
+
collapsibleTrail = true,
|
26
|
+
loading = false,
|
27
|
+
stickyLeftColumn,
|
28
|
+
columnPinning
|
29
|
+
}: {
|
30
|
+
row: Row<GenericObject>
|
31
|
+
collapsibleTrail?: boolean
|
32
|
+
loading?: boolean | string
|
33
|
+
stickyLeftColumn?: string[]
|
34
|
+
columnPinning: { left: string[] }
|
35
|
+
}) => {
|
36
|
+
return (
|
37
|
+
<>
|
38
|
+
{row.getVisibleCells().map((cell: Cell<GenericObject, unknown>, i: number) => {
|
39
|
+
const isPinnedLeft = columnPinning.left.includes(cell.column.id);
|
40
|
+
const isLastCell = (() => {
|
41
|
+
const parent = cell.column.parent;
|
42
|
+
if (!parent) {
|
43
|
+
const last = row.getVisibleCells().at(-1);
|
44
|
+
return last?.column.id === cell.column.id;
|
45
|
+
}
|
46
|
+
|
47
|
+
const visibleSiblings = parent.columns.filter(col => col.getIsVisible());
|
48
|
+
return visibleSiblings.at(-1)?.id === cell.column.id;
|
49
|
+
})();
|
50
|
+
|
51
|
+
const { column } = cell;
|
52
|
+
|
53
|
+
return (
|
54
|
+
<td
|
55
|
+
align="right"
|
56
|
+
className={classnames(
|
57
|
+
`${cell.id}-cell position_relative`,
|
58
|
+
isChrome() ? "chrome-styles" : "",
|
59
|
+
isPinnedLeft && 'pinned-left',
|
60
|
+
stickyLeftColumn && stickyLeftColumn.length > 0 && isPinnedLeft && 'sticky-left',
|
61
|
+
isLastCell && 'last-cell',
|
62
|
+
)}
|
63
|
+
key={`${cell.id}-data`}
|
64
|
+
style={{
|
65
|
+
left: isPinnedLeft
|
66
|
+
? i === 1 // Accounting for set min-width for first column
|
67
|
+
? '180px'
|
68
|
+
: `${column.getStart("left")}px`
|
69
|
+
: undefined,
|
70
|
+
}}
|
71
|
+
>
|
72
|
+
{collapsibleTrail && i === 0 && row.depth > 0 && renderCollapsibleTrail(row.depth)}
|
73
|
+
<span id={`${cell.id}-span`}>
|
74
|
+
{loading ? (
|
75
|
+
<LoadingCell />
|
76
|
+
) : (
|
77
|
+
flexRender(cell.column.columnDef.cell, cell.getContext())
|
78
|
+
)}
|
79
|
+
</span>
|
80
|
+
</td>
|
81
|
+
);
|
82
|
+
})}
|
83
|
+
</>
|
84
|
+
)
|
85
|
+
}
|
86
|
+
|
22
87
|
export const RegularTableView = ({
|
23
88
|
collapsibleTrail = true,
|
24
89
|
subRowHeaders,
|
@@ -28,11 +93,14 @@ export const RegularTableView = ({
|
|
28
93
|
handleExpandOrCollapse,
|
29
94
|
inlineRowLoading,
|
30
95
|
loading,
|
31
|
-
responsive,
|
32
96
|
table,
|
33
97
|
selectableRows,
|
34
98
|
hasAnySubRows,
|
35
|
-
stickyLeftColumn
|
99
|
+
stickyLeftColumn,
|
100
|
+
pinnedRows,
|
101
|
+
headerHeight,
|
102
|
+
rowHeight,
|
103
|
+
sampleRowRef,
|
36
104
|
} = useContext(AdvancedTableContext)
|
37
105
|
|
38
106
|
|
@@ -50,9 +118,44 @@ export const RegularTableView = ({
|
|
50
118
|
const columnPinning = table.getState().columnPinning || { left: [] };
|
51
119
|
const columnDefinitions = table.options.meta?.columnDefinitions || [];
|
52
120
|
|
121
|
+
// Row pinning
|
122
|
+
function PinnedRow({ row }: { row: Row<any> }) {
|
123
|
+
return (
|
124
|
+
<tr
|
125
|
+
className={classnames(
|
126
|
+
`pinned-row`,
|
127
|
+
)}
|
128
|
+
style={{
|
129
|
+
backgroundColor: 'white',
|
130
|
+
position: 'sticky',
|
131
|
+
top:
|
132
|
+
row.getIsPinned() === 'top'
|
133
|
+
? `${row.getPinnedIndex() * rowHeight + headerHeight}px`
|
134
|
+
: undefined,
|
135
|
+
zIndex: '3'
|
136
|
+
}}
|
137
|
+
>
|
138
|
+
<TableCellRenderer
|
139
|
+
collapsibleTrail={collapsibleTrail}
|
140
|
+
columnPinning={columnPinning}
|
141
|
+
loading={loading}
|
142
|
+
row={row}
|
143
|
+
stickyLeftColumn={stickyLeftColumn}
|
144
|
+
/>
|
145
|
+
</tr>
|
146
|
+
)
|
147
|
+
}
|
148
|
+
|
149
|
+
const totalRows = pinnedRows ? table.getCenterRows() : table.getRowModel().rows
|
150
|
+
|
53
151
|
return (
|
54
152
|
<>
|
55
|
-
{table.
|
153
|
+
{pinnedRows && table.getTopRows().map((row: Row<GenericObject>) => (
|
154
|
+
<PinnedRow key={row.id}
|
155
|
+
row={row}
|
156
|
+
/>
|
157
|
+
))}
|
158
|
+
{totalRows.map((row: Row<GenericObject>, rowIndex: number) => {
|
56
159
|
const isExpandable = row.getIsExpanded();
|
57
160
|
const isFirstChildofSubrow = row.depth > 0 && row.index === 0;
|
58
161
|
const rowHasNoChildren = row.original?.children && !row.original.children.length ? true : false;
|
@@ -60,6 +163,7 @@ export const RegularTableView = ({
|
|
60
163
|
const isDataLoading = isExpandable && (inlineRowLoading && rowHasNoChildren) && (row.depth < columnDefinitions[0]?.cellAccessors?.length);
|
61
164
|
const rowBackground = isExpandable && ((!inlineRowLoading && row.getCanExpand()) || (inlineRowLoading && rowHasNoChildren));
|
62
165
|
const rowColor = row.getIsSelected() ? "bg-row-selection" : rowBackground ? "bg-silver" : "bg-white";
|
166
|
+
const isFirstRegularRow = rowIndex === 0 && !row.getIsPinned();
|
63
167
|
|
64
168
|
return (
|
65
169
|
<React.Fragment key={`${row.index}-${row.id}-${row.depth}-row`}>
|
@@ -77,6 +181,7 @@ export const RegularTableView = ({
|
|
77
181
|
<tr
|
78
182
|
className={`${rowColor} ${row.depth > 0 ? `depth-sub-row-${row.depth}` : ""}`}
|
79
183
|
id={`${row.index}-${row.id}-${row.depth}-row`}
|
184
|
+
ref={isFirstRegularRow ? sampleRowRef : null}
|
80
185
|
>
|
81
186
|
{/* Render custom checkbox column when we want selectableRows for non-expanding tables */}
|
82
187
|
{selectableRows && !hasAnySubRows && (
|
@@ -90,51 +195,13 @@ export const RegularTableView = ({
|
|
90
195
|
/>
|
91
196
|
</td>
|
92
197
|
)}
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
return last?.column.id === cell.column.id;
|
101
|
-
}
|
102
|
-
|
103
|
-
const visibleSiblings = parent.columns.filter(col => col.getIsVisible());
|
104
|
-
return visibleSiblings.at(-1)?.id === cell.column.id;
|
105
|
-
})();
|
106
|
-
|
107
|
-
const { column } = cell;
|
108
|
-
return (
|
109
|
-
<td
|
110
|
-
align="right"
|
111
|
-
className={classnames(
|
112
|
-
`${cell.id}-cell position_relative`,
|
113
|
-
isChrome() ? "chrome-styles" : "",
|
114
|
-
isPinnedLeft && 'pinned-left',
|
115
|
-
stickyLeftColumn && stickyLeftColumn.length > 0 && isPinnedLeft && 'sticky-left',
|
116
|
-
isLastCell && 'last-cell',
|
117
|
-
)}
|
118
|
-
key={`${cell.id}-data`}
|
119
|
-
style={{
|
120
|
-
left: isPinnedLeft
|
121
|
-
? i === 1 //Accounting for set min-width for first column
|
122
|
-
? '180px'
|
123
|
-
: `${column.getStart("left")}px`
|
124
|
-
: undefined,
|
125
|
-
}}
|
126
|
-
>
|
127
|
-
{collapsibleTrail && i === 0 && row.depth > 0 && renderCollapsibleTrail(row.depth)}
|
128
|
-
<span id={`${cell.id}-span`}>
|
129
|
-
{loading ? (
|
130
|
-
<LoadingCell />
|
131
|
-
) : (
|
132
|
-
flexRender(cell.column.columnDef.cell, cell.getContext())
|
133
|
-
)}
|
134
|
-
</span>
|
135
|
-
</td>
|
136
|
-
);
|
137
|
-
})}
|
198
|
+
<TableCellRenderer
|
199
|
+
collapsibleTrail={collapsibleTrail}
|
200
|
+
columnPinning={columnPinning}
|
201
|
+
loading={loading}
|
202
|
+
row={row}
|
203
|
+
stickyLeftColumn={stickyLeftColumn}
|
204
|
+
/>
|
138
205
|
</tr>
|
139
206
|
|
140
207
|
{/* Display LoadingInline if Row Data is querying and there are no children already */}
|
@@ -154,4 +221,4 @@ export const RegularTableView = ({
|
|
154
221
|
);
|
155
222
|
}
|
156
223
|
|
157
|
-
export default RegularTableView;
|
224
|
+
export default RegularTableView;
|
@@ -128,7 +128,7 @@ const isToggleExpansionEnabled =
|
|
128
128
|
|
129
129
|
let justifyHeader:justifyTypes;
|
130
130
|
|
131
|
-
if (header?.index === 0 && hasAnySubRows || (header?.index === 0 && inlineRowLoading)
|
131
|
+
if (header?.index === 0 && hasAnySubRows || (header?.index === 0 && inlineRowLoading)) {
|
132
132
|
justifyHeader = enableSorting ? "between" : "start";
|
133
133
|
} else {
|
134
134
|
justifyHeader = isLeafColumn ? "end" : "center";
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { createContext, useRef, useMemo, useEffect } from 'react';
|
1
|
+
import React, { createContext, useRef, useMemo, useEffect, useState, useCallback } from 'react';
|
2
2
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
3
3
|
|
4
4
|
import { Row } from "@tanstack/react-table";
|
@@ -23,6 +23,54 @@ export const AdvancedTableProvider = ({ children, ...props }: {
|
|
23
23
|
|
24
24
|
const table = props.table;
|
25
25
|
const isVirtualized = props.virtualizedRows || props.enableVirtualization;
|
26
|
+
|
27
|
+
// Pinned Row: height calculations for Header and Row
|
28
|
+
const headerRef = useRef(null);
|
29
|
+
const sampleRowRef = useRef(null);
|
30
|
+
|
31
|
+
const [headerHeight, setHeaderHeight] = useState(44);
|
32
|
+
const [rowHeight, setRowHeight] = useState(38);
|
33
|
+
|
34
|
+
const measureHeights = useCallback(() => {
|
35
|
+
if (headerRef.current) {
|
36
|
+
const headerRect = headerRef.current.getBoundingClientRect();
|
37
|
+
if (headerRect.height > 0) {
|
38
|
+
setHeaderHeight(headerRect.height);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
if (sampleRowRef.current) {
|
42
|
+
const rowRect = sampleRowRef.current.getBoundingClientRect();
|
43
|
+
if (rowRect.height > 0) {
|
44
|
+
setRowHeight(rowRect.height);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}, []);
|
48
|
+
|
49
|
+
useEffect(() => {
|
50
|
+
const resizeObserver = new ResizeObserver(() => {
|
51
|
+
measureHeights();
|
52
|
+
});
|
53
|
+
|
54
|
+
if (headerRef.current) {
|
55
|
+
resizeObserver.observe(headerRef.current);
|
56
|
+
}
|
57
|
+
|
58
|
+
if (sampleRowRef.current) {
|
59
|
+
resizeObserver.observe(sampleRowRef.current);
|
60
|
+
}
|
61
|
+
|
62
|
+
const timeoutId = setTimeout(measureHeights, 100);
|
63
|
+
|
64
|
+
return () => {
|
65
|
+
resizeObserver.disconnect();
|
66
|
+
clearTimeout(timeoutId);
|
67
|
+
};
|
68
|
+
}, [measureHeights]);
|
69
|
+
|
70
|
+
useEffect(() => {
|
71
|
+
measureHeights();
|
72
|
+
}, [table?.getRowModel().rows.length, measureHeights]);
|
73
|
+
|
26
74
|
|
27
75
|
// Create a flattened data array that includes ALL components for virtualization
|
28
76
|
const flattenedItems = useMemo(() => {
|
@@ -132,7 +180,15 @@ export const AdvancedTableProvider = ({ children, ...props }: {
|
|
132
180
|
virtualizer: isVirtualized ? virtualizer : null,
|
133
181
|
flattenedItems,
|
134
182
|
virtualizedRows: isVirtualized,
|
135
|
-
enableVirtualization: isVirtualized
|
183
|
+
enableVirtualization: isVirtualized,
|
184
|
+
rowPinning: props.rowPinning,
|
185
|
+
setRowPinning: props.setRowPinning,
|
186
|
+
keepPinnedRows: props.keepPinnedRows,
|
187
|
+
headerHeight,
|
188
|
+
rowHeight,
|
189
|
+
headerRef,
|
190
|
+
sampleRowRef,
|
191
|
+
measureHeights,
|
136
192
|
};
|
137
193
|
|
138
194
|
return (
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { useCallback, useEffect } from 'react';
|
2
|
-
import { Row } from "@tanstack/react-table";
|
2
|
+
import { Row, RowPinningState } from "@tanstack/react-table";
|
3
3
|
import { GenericObject } from "../../types";
|
4
4
|
import { updateExpandAndCollapseState } from "../Utilities/ExpansionControlHelpers";
|
5
5
|
|
@@ -6,7 +6,8 @@ import {
|
|
6
6
|
getPaginationRowModel,
|
7
7
|
getSortedRowModel,
|
8
8
|
RowSelectionState,
|
9
|
-
Row
|
9
|
+
Row,
|
10
|
+
RowPinningState
|
10
11
|
} from "@tanstack/react-table";
|
11
12
|
import { GenericObject } from "../../types";
|
12
13
|
import { createColumnHelper } from "@tanstack/react-table";
|
@@ -23,11 +24,14 @@ interface UseTableStateProps {
|
|
23
24
|
loading?: boolean | string;
|
24
25
|
pagination?: boolean;
|
25
26
|
paginationProps?: GenericObject;
|
27
|
+
pinnedRows?: {
|
28
|
+
value?: RowPinningState;
|
29
|
+
onChange?: (value: RowPinningState) => void;
|
30
|
+
};
|
26
31
|
virtualizedRows?: boolean;
|
27
32
|
tableOptions?: GenericObject;
|
28
33
|
onRowSelectionChange?: (arg: RowSelectionState) => void;
|
29
34
|
columnVisibilityControl?: GenericObject;
|
30
|
-
|
31
35
|
}
|
32
36
|
|
33
37
|
export function useTableState({
|
@@ -43,18 +47,24 @@ export function useTableState({
|
|
43
47
|
paginationProps,
|
44
48
|
virtualizedRows = false,
|
45
49
|
tableOptions,
|
46
|
-
columnVisibilityControl
|
50
|
+
columnVisibilityControl,
|
51
|
+
pinnedRows,
|
47
52
|
}: UseTableStateProps) {
|
48
53
|
// Create a local state for expanded and setExpanded if expandedControl not used
|
49
54
|
const [localExpanded, setLocalExpanded] = useState({});
|
50
55
|
const [loadingStateRowCount, setLoadingStateRowCount] = useState(initialLoadingRowsCount);
|
51
56
|
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
52
57
|
const [localColumnVisibility, setLocalColumnVisibility] = useState({});
|
58
|
+
const [localRowPinning, setLocalRowPinning] = useState<RowPinningState>({
|
59
|
+
top: [],
|
60
|
+
});
|
53
61
|
// Determine whether to use the prop or the local state
|
54
62
|
const expanded = expandedControl ? expandedControl.value : localExpanded;
|
55
63
|
const setExpanded = expandedControl ? expandedControl.onChange : setLocalExpanded;
|
56
64
|
const columnVisibility = (columnVisibilityControl && columnVisibilityControl.value) ? columnVisibilityControl.value : localColumnVisibility;
|
57
65
|
const setColumnVisibility = (columnVisibilityControl && columnVisibilityControl.onChange) ? columnVisibilityControl.onChange : setLocalColumnVisibility;
|
66
|
+
const rowPinning = pinnedRows && pinnedRows.value || localRowPinning;
|
67
|
+
const setRowPinning = (pinnedRows && pinnedRows.onChange) ? pinnedRows.onChange : setLocalRowPinning;
|
58
68
|
|
59
69
|
// Virtualized data handling (chunked loading)
|
60
70
|
const fetchSize = 20; // Number of rows per "page"
|
@@ -115,6 +125,7 @@ export function useTableState({
|
|
115
125
|
...(sortControl && { sorting }),
|
116
126
|
...(selectableRows && { rowSelection }),
|
117
127
|
...(columnVisibility && { columnVisibility }),
|
128
|
+
...(pinnedRows && { rowPinning }),
|
118
129
|
},
|
119
130
|
}), [
|
120
131
|
expanded,
|
@@ -123,6 +134,7 @@ export function useTableState({
|
|
123
134
|
selectableRows,
|
124
135
|
rowSelection,
|
125
136
|
columnVisibility,
|
137
|
+
rowPinning,
|
126
138
|
]);
|
127
139
|
|
128
140
|
// Pagination configuration
|
@@ -153,7 +165,7 @@ export function useTableState({
|
|
153
165
|
enableSortingRemoval: false,
|
154
166
|
sortDescFirst: true,
|
155
167
|
onRowSelectionChange: setRowSelection,
|
156
|
-
getRowId: selectableRows ? row => row.id : undefined,
|
168
|
+
getRowId: (selectableRows || pinnedRows) ? row => row.id : undefined,
|
157
169
|
onColumnVisibilityChange: setColumnVisibility,
|
158
170
|
meta: {
|
159
171
|
columnDefinitions
|
@@ -39,7 +39,8 @@ export const TableHeader = ({
|
|
39
39
|
hasAnySubRows,
|
40
40
|
showActionsBar,
|
41
41
|
selectableRows,
|
42
|
-
responsive
|
42
|
+
responsive,
|
43
|
+
headerRef
|
43
44
|
} = useContext(AdvancedTableContext)
|
44
45
|
|
45
46
|
const classes = classnames(
|
@@ -62,8 +63,11 @@ export const TableHeader = ({
|
|
62
63
|
id={id}
|
63
64
|
>
|
64
65
|
{/* Get the header groups (only one in this example) */}
|
65
|
-
{table.getHeaderGroups().map((headerGroup: HeaderGroup<GenericObject
|
66
|
-
<tr
|
66
|
+
{table.getHeaderGroups().map((headerGroup: HeaderGroup<GenericObject>, index: number) => (
|
67
|
+
<tr
|
68
|
+
key={`${headerGroup.id}-headerGroup`}
|
69
|
+
ref={index === 0 ? headerRef : null}
|
70
|
+
>
|
67
71
|
{!hasAnySubRows && selectableRows && (
|
68
72
|
<th className={customCellClassnames}>
|
69
73
|
<Checkbox
|
@@ -588,6 +588,11 @@
|
|
588
588
|
}
|
589
589
|
}
|
590
590
|
|
591
|
+
// Row Pinning - additional inline styles in RegularTableView.tsx
|
592
|
+
.pinned-row {
|
593
|
+
box-shadow: 0 4px 10px 0 rgba($shadow, 0.16) !important;
|
594
|
+
}
|
595
|
+
|
591
596
|
&.dark {
|
592
597
|
// Override default border color for dark mode
|
593
598
|
--column-border-color: #{$border_dark};
|
@@ -2,7 +2,7 @@ import React, { useRef, useEffect, useState, useCallback } from "react";
|
|
2
2
|
import classnames from "classnames";
|
3
3
|
|
4
4
|
import { GenericObject } from "../types";
|
5
|
-
import { Row, RowSelectionState } from "@tanstack/react-table";
|
5
|
+
import { Row, RowSelectionState, RowPinningState } from "@tanstack/react-table";
|
6
6
|
|
7
7
|
import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
|
8
8
|
import { globalProps, GlobalProps } from "../utilities/globalProps";
|
@@ -51,7 +51,11 @@ type AdvancedTableProps = {
|
|
51
51
|
onRowToggleClick?: (arg: Row<GenericObject>) => void
|
52
52
|
onToggleExpansionClick?: (arg: Row<GenericObject>) => void
|
53
53
|
pagination?: boolean,
|
54
|
-
paginationProps?: GenericObject
|
54
|
+
paginationProps?: GenericObject,
|
55
|
+
pinnedRows?: {
|
56
|
+
value?: RowPinningState;
|
57
|
+
onChange?: (value: RowPinningState) => void;
|
58
|
+
};
|
55
59
|
responsive?: "scroll" | "none",
|
56
60
|
selectableRows?: boolean,
|
57
61
|
showActionsBar?: boolean,
|
@@ -91,6 +95,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
91
95
|
onToggleExpansionClick,
|
92
96
|
pagination = false,
|
93
97
|
paginationProps,
|
98
|
+
pinnedRows,
|
94
99
|
responsive = "scroll",
|
95
100
|
showActionsBar = true,
|
96
101
|
selectableRows,
|
@@ -136,6 +141,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
136
141
|
tableOptions,
|
137
142
|
onRowSelectionChange,
|
138
143
|
columnVisibilityControl,
|
144
|
+
pinnedRows,
|
139
145
|
});
|
140
146
|
|
141
147
|
// Initialize table actions
|
@@ -241,7 +247,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
241
247
|
maxHeight ? `advanced-table-max-height-${maxHeight}` : '',
|
242
248
|
{
|
243
249
|
'advanced-table-fullscreen': isFullscreen,
|
244
|
-
'advanced-table-allow-fullscreen': allowFullScreen
|
250
|
+
'advanced-table-allow-fullscreen': allowFullScreen,
|
245
251
|
},
|
246
252
|
{'advanced-table-sticky-left-columns': stickyLeftColumn && stickyLeftColumn.length > 0},
|
247
253
|
columnGroupBorderColor ? `column-group-border-${columnGroupBorderColor}` : '',
|
@@ -302,6 +308,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
302
308
|
isFullscreen={isFullscreen}
|
303
309
|
loading={loading}
|
304
310
|
onExpandByDepthClick={onExpandByDepthClick}
|
311
|
+
pinnedRows={pinnedRows}
|
305
312
|
responsive={responsive}
|
306
313
|
selectableRows={selectableRows}
|
307
314
|
setExpanded={setExpanded}
|
@@ -3,6 +3,12 @@ import { render, screen, waitFor } from "../utilities/test-utils"
|
|
3
3
|
|
4
4
|
import { AdvancedTable, Pill } from "playbook-ui"
|
5
5
|
|
6
|
+
global.ResizeObserver = class {
|
7
|
+
observe() {}
|
8
|
+
unobserve() {}
|
9
|
+
disconnect() {}
|
10
|
+
};
|
11
|
+
|
6
12
|
const MOCK_DATA = [
|
7
13
|
{
|
8
14
|
year: "2021",
|
@@ -72,6 +78,36 @@ const MOCK_DATA_LOADING = [
|
|
72
78
|
},
|
73
79
|
]
|
74
80
|
|
81
|
+
const MOCK_DATA_WITH_ID = [
|
82
|
+
{
|
83
|
+
id: "1",
|
84
|
+
year: "2021",
|
85
|
+
quarter: null,
|
86
|
+
month: null,
|
87
|
+
day: null,
|
88
|
+
newEnrollments: "20",
|
89
|
+
scheduledMeetings: "10",
|
90
|
+
},
|
91
|
+
{
|
92
|
+
id: "2",
|
93
|
+
year: "2022",
|
94
|
+
quarter: null,
|
95
|
+
month: null,
|
96
|
+
day: null,
|
97
|
+
newEnrollments: "25",
|
98
|
+
scheduledMeetings: "15",
|
99
|
+
},
|
100
|
+
{
|
101
|
+
id: "3",
|
102
|
+
year: "2023",
|
103
|
+
quarter: null,
|
104
|
+
month: null,
|
105
|
+
day: null,
|
106
|
+
newEnrollments: "30",
|
107
|
+
scheduledMeetings: "20",
|
108
|
+
},
|
109
|
+
]
|
110
|
+
|
75
111
|
const columnDefinitions = [
|
76
112
|
{
|
77
113
|
accessor: "year",
|
@@ -512,3 +548,28 @@ test("allowFullScreen prop adds fullscreen class", () => {
|
|
512
548
|
const tableContainer = screen.getByRole("table").closest("div")
|
513
549
|
expect(tableContainer).toHaveClass("advanced-table-allow-fullscreen")
|
514
550
|
})
|
551
|
+
|
552
|
+
test("pinnedRows prop renders pinned rows at top", () => {
|
553
|
+
const pinnedRowsControl = {
|
554
|
+
value: { top: ["1", "3"] },
|
555
|
+
onChange: jest.fn()
|
556
|
+
}
|
557
|
+
|
558
|
+
render(
|
559
|
+
<AdvancedTable
|
560
|
+
columnDefinitions={columnDefinitions}
|
561
|
+
data={{ testid: testId }}
|
562
|
+
pinnedRows={pinnedRowsControl}
|
563
|
+
tableData={MOCK_DATA_WITH_ID}
|
564
|
+
/>
|
565
|
+
)
|
566
|
+
|
567
|
+
const kit = screen.getByTestId(testId)
|
568
|
+
const pinnedRows = kit.querySelectorAll(".pinned-row")
|
569
|
+
|
570
|
+
expect(pinnedRows).toHaveLength(2)
|
571
|
+
|
572
|
+
const firstPinnedRow = pinnedRows[0]
|
573
|
+
expect(firstPinnedRow).toHaveStyle("position: sticky")
|
574
|
+
expect(firstPinnedRow).toHaveStyle("background-color: white")
|
575
|
+
})
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import React, { useState } from "react"
|
2
|
+
import AdvancedTable from '../_advanced_table'
|
3
|
+
import MOCK_DATA from "./advanced_table_mock_data_with_id.json"
|
4
|
+
|
5
|
+
const AdvancedTableRowPinning = (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
|
+
const [pinnedRows, setPinnedRows] = useState({top: ["8", "9", "10", "11", "12", "13", "14"]})
|
39
|
+
|
40
|
+
return (
|
41
|
+
<div>
|
42
|
+
<AdvancedTable
|
43
|
+
columnDefinitions={columnDefinitions}
|
44
|
+
maxHeight="xs"
|
45
|
+
pinnedRows={{value: pinnedRows, onChange: setPinnedRows}}
|
46
|
+
tableData={MOCK_DATA}
|
47
|
+
tableProps={{sticky: true}}
|
48
|
+
{...props}
|
49
|
+
>
|
50
|
+
<AdvancedTable.Header enableSorting />
|
51
|
+
<AdvancedTable.Body />
|
52
|
+
</AdvancedTable>
|
53
|
+
</div>
|
54
|
+
)
|
55
|
+
}
|
56
|
+
|
57
|
+
export default AdvancedTableRowPinning
|
@@ -0,0 +1,5 @@
|
|
1
|
+
Use the `pinnedRows` prop to pin specific rows to the top of an Advanced Table. Pinned rows will remain at the top when scrolling through table data and reorganizing via sorting.
|
2
|
+
|
3
|
+
**NOTE:** This prop is in Beta. Current Requirements for V1:
|
4
|
+
- Sticky header required: Pinned rows must be used with `sticky: true` via `tableProps` (works with both responsive and non-responsive tables)
|
5
|
+
- Row ids required: Pass an array of row ids to the `top` property. For expandable rows, both parent and all its child row ids must be included individually
|
@@ -13,7 +13,6 @@ examples:
|
|
13
13
|
- advanced_table_column_headers: Multi-Header Columns
|
14
14
|
- advanced_table_column_headers_multiple: Multi-Header Columns (Multiple Levels)
|
15
15
|
- advanced_table_column_border_color_rails: Column Group Border Color
|
16
|
-
- advanced_table_no_subrows: Table with No Subrows or Expansion
|
17
16
|
- advanced_table_selectable_rows_rails: Selectable Rows
|
18
17
|
- advanced_table_selectable_rows_no_subrows_rails: Selectable Rows (No Subrows)
|
19
18
|
- advanced_table_selectable_rows_actions_rails: Selectable Rows (With Actions)
|
@@ -43,7 +42,7 @@ examples:
|
|
43
42
|
- advanced_table_column_headers_multiple: Multi-Header Columns (Multiple Levels)
|
44
43
|
- advanced_table_column_headers_custom_cell: Multi-Header Columns with Custom Cells
|
45
44
|
- advanced_table_column_border_color: Column Group Border Color
|
46
|
-
- advanced_table_no_subrows: Table with No Subrows
|
45
|
+
# - advanced_table_no_subrows: Table with No Subrows
|
47
46
|
- advanced_table_selectable_rows: Selectable Rows
|
48
47
|
- advanced_table_selectable_rows_no_subrows_react: Selectable Rows (No Subrows)
|
49
48
|
- advanced_table_selectable_rows_actions: Selectable Rows (With Actions)
|
@@ -53,4 +52,5 @@ examples:
|
|
53
52
|
- advanced_table_column_visibility: Column Visibility Control
|
54
53
|
- advanced_table_column_visibility_with_state: Column Visibility Control With State
|
55
54
|
- advanced_table_column_visibility_custom: Column Visibility Control with Custom Dropdown
|
56
|
-
- advanced_table_column_visibility_multi: Column Visibility Control with Multi-Header Columns
|
55
|
+
- advanced_table_column_visibility_multi: Column Visibility Control with Multi-Header Columns
|
56
|
+
- advanced_table_pinned_rows: Pinned Rows
|