playbook_ui 16.9.0.pre.alpha.playgroundsmore17219 → 16.9.0.pre.alpha.touchdragmulticontainers17268
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/RegularTableView.tsx +2 -1
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +5 -2
- data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +27 -2
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/StickyLayoutHelper.ts +100 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +36 -1
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +29 -0
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +7 -0
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +50 -0
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table_action_bar.js +31 -9
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_row_styling.jsx +2 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.html.erb +36 -44
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.jsx +10 -19
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_rails.md +0 -4
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_react.md +3 -5
- data/app/pb_kits/playbook/pb_advanced_table/index.js +20 -29
- data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +1 -1
- data/app/pb_kits/playbook/pb_background/_background.tsx +0 -2
- data/app/pb_kits/playbook/pb_background/background.test.js +1 -24
- data/app/pb_kits/playbook/pb_draggable/context/index.tsx +10 -2
- data/app/pb_kits/playbook/pb_draggable/docs/_draggable_independent_containers.html.erb +35 -0
- data/app/pb_kits/playbook/pb_draggable/docs/_draggable_independent_containers.jsx +81 -0
- data/app/pb_kits/playbook/pb_draggable/docs/_draggable_independent_containers_rails.md +8 -0
- data/app/pb_kits/playbook/pb_draggable/docs/_draggable_independent_containers_react.md +8 -0
- data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers_rails.md +3 -1
- data/app/pb_kits/playbook/pb_draggable/docs/_draggable_multiple_containers_react.md +3 -1
- data/app/pb_kits/playbook/pb_draggable/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_draggable/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_draggable/index.js +10 -3
- data/app/pb_kits/playbook/pb_draggable/touchDrag.test.js +27 -0
- data/app/pb_kits/playbook/pb_draggable/utilities/touchDrag.ts +36 -11
- data/dist/chunks/{_typeahead-CuXG_NFx.js → _typeahead-BGknAmsa.js} +1 -1
- data/dist/chunks/time_picker_helper-CVMV9ync.js +1 -0
- data/dist/chunks/vendor.js +2 -2
- 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 -4
- data/dist/chunks/time_picker_helper-Bx8nzyM8.js +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 89c52f53eea784d92355431d75ff12e5b12309cc1daa70b45c9811369a9d51d9
|
|
4
|
+
data.tar.gz: 8424c9aeabd6007e2ba9151207c40f798bad2c5243ceb597aa43b176859b5326
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2bd62a01ea9037bd4b5b86e6d70d947b08ddcc445f534db3edffabde5ab29c3d527dc779ba6b41552cd875078bbfb1d7287a1f1badbc9e0aa27d537cc8079aa4
|
|
7
|
+
data.tar.gz: bd30042e81eaa8205affab38ab44be73865af3adaec7d060be15a7aabb3058fe55d5a63a04fd3258a6be63d804da9c2eacdb02a540b62f0607e965f89ea0c529
|
|
@@ -136,6 +136,7 @@ export const RegularTableView = ({
|
|
|
136
136
|
pinnedRows,
|
|
137
137
|
headerHeight,
|
|
138
138
|
rowHeight,
|
|
139
|
+
actionBarHeight,
|
|
139
140
|
rowStyling = [],
|
|
140
141
|
sampleRowRef,
|
|
141
142
|
} = useContext(AdvancedTableContext)
|
|
@@ -172,7 +173,7 @@ export const RegularTableView = ({
|
|
|
172
173
|
position: 'sticky',
|
|
173
174
|
top:
|
|
174
175
|
row.getIsPinned() === 'top'
|
|
175
|
-
? `${row.getPinnedIndex() * rowHeight + headerHeight}px`
|
|
176
|
+
? `${row.getPinnedIndex() * rowHeight + headerHeight + actionBarHeight}px`
|
|
176
177
|
: undefined,
|
|
177
178
|
zIndex: '3'
|
|
178
179
|
}}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
showActionBar,
|
|
18
18
|
hideActionBar,
|
|
19
19
|
} from "../Utilities/ActionBarAnimationHelper";
|
|
20
|
+
import { scheduleStickyActionBarHeightUpdate } from "../Utilities/StickyLayoutHelper";
|
|
20
21
|
import { GenericObject } from "../../types";
|
|
21
22
|
|
|
22
23
|
interface TableActionBarProps {
|
|
@@ -39,7 +40,7 @@ const TableActionBar: React.FC<TableActionBarProps> = ({
|
|
|
39
40
|
type = "row-selection",
|
|
40
41
|
}) => {
|
|
41
42
|
const cardRef = useRef(null);
|
|
42
|
-
const { table, columnVisibilityControl, columnDefinitions } =
|
|
43
|
+
const { table, columnVisibilityControl, columnDefinitions, tableContainerRef } =
|
|
43
44
|
useContext(AdvancedTableContext);
|
|
44
45
|
|
|
45
46
|
// ----------- Column visibility logic -----------
|
|
@@ -131,8 +132,10 @@ const TableActionBar: React.FC<TableActionBarProps> = ({
|
|
|
131
132
|
} else {
|
|
132
133
|
hideActionBar(cardRef.current);
|
|
133
134
|
}
|
|
135
|
+
|
|
136
|
+
scheduleStickyActionBarHeightUpdate(tableContainerRef?.current ?? null);
|
|
134
137
|
}
|
|
135
|
-
}, [isVisible, type]);
|
|
138
|
+
}, [isVisible, type, tableContainerRef]);
|
|
136
139
|
|
|
137
140
|
const [showPopover, setShowPopover] = useState(false)
|
|
138
141
|
|
|
@@ -4,6 +4,7 @@ import { useVirtualizer } from '@tanstack/react-virtual';
|
|
|
4
4
|
import { Row } from "@tanstack/react-table";
|
|
5
5
|
import { GenericObject } from "../../types";
|
|
6
6
|
import { getRowHeightEstimate } from '../Utilities/TableContainerStyles';
|
|
7
|
+
import { measureElementHeight } from '../Utilities/StickyLayoutHelper';
|
|
7
8
|
|
|
8
9
|
const AdvancedTableContext = createContext<any>({});
|
|
9
10
|
|
|
@@ -30,8 +31,11 @@ export const AdvancedTableProvider = ({ children, ...props }: {
|
|
|
30
31
|
|
|
31
32
|
const [headerHeight, setHeaderHeight] = useState(44);
|
|
32
33
|
const [rowHeight, setRowHeight] = useState(38);
|
|
34
|
+
const [actionBarHeight, setActionBarHeight] = useState(0);
|
|
33
35
|
|
|
34
36
|
const measureHeights = useCallback(() => {
|
|
37
|
+
const wrapper = (props.tableContainerRef?.current || tableContainerRef.current) as HTMLElement | null;
|
|
38
|
+
|
|
35
39
|
if (headerRef.current) {
|
|
36
40
|
const headerElement = headerRef.current as HTMLElement;
|
|
37
41
|
const headerRect = headerElement.getBoundingClientRect();
|
|
@@ -45,7 +49,21 @@ export const AdvancedTableProvider = ({ children, ...props }: {
|
|
|
45
49
|
setRowHeight(rowRect.height);
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
|
-
|
|
52
|
+
|
|
53
|
+
if (wrapper) {
|
|
54
|
+
const actionBar = wrapper.querySelector(
|
|
55
|
+
".row-selection-actions-card.is-visible, .row-selection-actions-card.show-action-card"
|
|
56
|
+
) as HTMLElement | null;
|
|
57
|
+
const measuredActionBarHeight = actionBar
|
|
58
|
+
? measureElementHeight(actionBar)
|
|
59
|
+
: 0;
|
|
60
|
+
setActionBarHeight(measuredActionBarHeight);
|
|
61
|
+
wrapper.style.setProperty(
|
|
62
|
+
"--advanced-table-action-bar-height",
|
|
63
|
+
`${measuredActionBarHeight}px`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}, [props.tableContainerRef]);
|
|
49
67
|
|
|
50
68
|
useEffect(() => {
|
|
51
69
|
const resizeObserver = new ResizeObserver(() => {
|
|
@@ -56,6 +74,12 @@ export const AdvancedTableProvider = ({ children, ...props }: {
|
|
|
56
74
|
resizeObserver.observe(headerRef.current);
|
|
57
75
|
}
|
|
58
76
|
|
|
77
|
+
const wrapper = (props.tableContainerRef?.current || tableContainerRef.current) as HTMLElement | null;
|
|
78
|
+
const actionBar = wrapper?.querySelector(".row-selection-actions-card");
|
|
79
|
+
if (actionBar) {
|
|
80
|
+
resizeObserver.observe(actionBar);
|
|
81
|
+
}
|
|
82
|
+
|
|
59
83
|
if (sampleRowRef.current) {
|
|
60
84
|
resizeObserver.observe(sampleRowRef.current);
|
|
61
85
|
}
|
|
@@ -72,7 +96,7 @@ export const AdvancedTableProvider = ({ children, ...props }: {
|
|
|
72
96
|
|
|
73
97
|
useEffect(() => {
|
|
74
98
|
measureHeights();
|
|
75
|
-
}, [table?.getRowModel().rows.length, headerGroupCount, measureHeights]);
|
|
99
|
+
}, [table?.getRowModel().rows.length, headerGroupCount, props.isActionBarVisible, measureHeights]);
|
|
76
100
|
|
|
77
101
|
|
|
78
102
|
// Create a flattened data array that includes ALL components for virtualization
|
|
@@ -202,6 +226,7 @@ export const AdvancedTableProvider = ({ children, ...props }: {
|
|
|
202
226
|
keepPinnedRows: props.keepPinnedRows,
|
|
203
227
|
headerHeight,
|
|
204
228
|
rowHeight,
|
|
229
|
+
actionBarHeight,
|
|
205
230
|
headerRef,
|
|
206
231
|
sampleRowRef,
|
|
207
232
|
measureHeights,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const VISIBLE_ACTION_BAR_SELECTOR =
|
|
2
|
+
".row-selection-actions-card.is-visible, .row-selection-actions-card.show-action-card";
|
|
3
|
+
|
|
4
|
+
const ACTION_BAR_HEIGHT_TRANSITION_MS = 350;
|
|
5
|
+
|
|
6
|
+
export const measureElementHeight = (element: HTMLElement): number => {
|
|
7
|
+
const { height: rectHeight } = element.getBoundingClientRect();
|
|
8
|
+
const scrollHeight = element.scrollHeight;
|
|
9
|
+
const offsetHeight = element.offsetHeight;
|
|
10
|
+
|
|
11
|
+
return Math.ceil(Math.max(rectHeight, scrollHeight, offsetHeight));
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const updateStickyActionBarHeight = (
|
|
15
|
+
advancedTableWrapper: HTMLElement | null
|
|
16
|
+
): number => {
|
|
17
|
+
if (!advancedTableWrapper) return 0;
|
|
18
|
+
|
|
19
|
+
const actionBar = advancedTableWrapper.querySelector(
|
|
20
|
+
VISIBLE_ACTION_BAR_SELECTOR
|
|
21
|
+
) as HTMLElement | null;
|
|
22
|
+
|
|
23
|
+
if (!actionBar) {
|
|
24
|
+
advancedTableWrapper.style.setProperty(
|
|
25
|
+
"--advanced-table-action-bar-height",
|
|
26
|
+
"0px"
|
|
27
|
+
);
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const actionBarHeight = measureElementHeight(actionBar);
|
|
32
|
+
|
|
33
|
+
advancedTableWrapper.style.setProperty(
|
|
34
|
+
"--advanced-table-action-bar-height",
|
|
35
|
+
`${actionBarHeight}px`
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return actionBarHeight;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const scheduleStickyActionBarHeightUpdate = (
|
|
42
|
+
advancedTableWrapper: HTMLElement | null
|
|
43
|
+
): void => {
|
|
44
|
+
if (!advancedTableWrapper) return;
|
|
45
|
+
|
|
46
|
+
updateStickyActionBarHeight(advancedTableWrapper);
|
|
47
|
+
|
|
48
|
+
requestAnimationFrame(() => {
|
|
49
|
+
updateStickyActionBarHeight(advancedTableWrapper);
|
|
50
|
+
requestAnimationFrame(() => {
|
|
51
|
+
updateStickyActionBarHeight(advancedTableWrapper);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
window.setTimeout(() => {
|
|
56
|
+
updateStickyActionBarHeight(advancedTableWrapper);
|
|
57
|
+
}, ACTION_BAR_HEIGHT_TRANSITION_MS);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const updateStickyHeaderRowHeights = (
|
|
61
|
+
advancedTableWrapper: HTMLElement | null
|
|
62
|
+
): void => {
|
|
63
|
+
if (!advancedTableWrapper) return;
|
|
64
|
+
|
|
65
|
+
const table = advancedTableWrapper.querySelector("table.pb_table");
|
|
66
|
+
const thead = table?.querySelector("thead");
|
|
67
|
+
if (!thead) return;
|
|
68
|
+
|
|
69
|
+
const rows = Array.from(thead.querySelectorAll("tr"));
|
|
70
|
+
let totalHeight = 0;
|
|
71
|
+
|
|
72
|
+
rows.forEach((tr, index) => {
|
|
73
|
+
const height = tr.offsetHeight;
|
|
74
|
+
if (index === 0) {
|
|
75
|
+
advancedTableWrapper.style.setProperty(
|
|
76
|
+
"--advanced-table-header-row-0-height",
|
|
77
|
+
`${height}px`
|
|
78
|
+
);
|
|
79
|
+
} else if (index === 1) {
|
|
80
|
+
advancedTableWrapper.style.setProperty(
|
|
81
|
+
"--advanced-table-header-row-1-height",
|
|
82
|
+
`${height}px`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
totalHeight += height;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
advancedTableWrapper.style.setProperty(
|
|
89
|
+
"--advanced-table-header-height",
|
|
90
|
+
`${totalHeight}px`
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
updateStickyActionBarHeight(advancedTableWrapper);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const updateStickyLayoutHeights = (
|
|
97
|
+
advancedTableWrapper: HTMLElement | null
|
|
98
|
+
): void => {
|
|
99
|
+
updateStickyHeaderRowHeights(advancedTableWrapper);
|
|
100
|
+
};
|
|
@@ -364,6 +364,34 @@
|
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
&.advanced-table-sticky-header {
|
|
368
|
+
.row-selection-actions-card.show-action-card,
|
|
369
|
+
.row-selection-actions-card.is-visible {
|
|
370
|
+
background-color: $white;
|
|
371
|
+
left: 0;
|
|
372
|
+
position: sticky;
|
|
373
|
+
top: 0;
|
|
374
|
+
z-index: 5;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.pb_table.sticky-header {
|
|
378
|
+
thead,
|
|
379
|
+
.pb_advanced_table_header {
|
|
380
|
+
top: var(--advanced-table-action-bar-height, 0px);
|
|
381
|
+
z-index: 3;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
&.hidden-action-bar {
|
|
386
|
+
.pb_table.sticky-header {
|
|
387
|
+
thead,
|
|
388
|
+
.pb_advanced_table_header {
|
|
389
|
+
top: 0;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
367
395
|
// Max height overflow - the below prevents expansion from overflowing container at full screen for responsive and nonresponsive tables
|
|
368
396
|
&.advanced-table-max-height-xs {
|
|
369
397
|
max-height: 320px;
|
|
@@ -434,7 +462,7 @@
|
|
|
434
462
|
thead,
|
|
435
463
|
.pb_advanced_table_header {
|
|
436
464
|
position: sticky !important;
|
|
437
|
-
top: 44px !important;
|
|
465
|
+
top: calc(44px + var(--advanced-table-action-bar-height, 0px)) !important;
|
|
438
466
|
z-index: $z_10;
|
|
439
467
|
}
|
|
440
468
|
}
|
|
@@ -987,6 +1015,13 @@
|
|
|
987
1015
|
background-color: $bg_dark_card;
|
|
988
1016
|
}
|
|
989
1017
|
|
|
1018
|
+
&.advanced-table-sticky-header {
|
|
1019
|
+
.row-selection-actions-card.show-action-card,
|
|
1020
|
+
.row-selection-actions-card.is-visible {
|
|
1021
|
+
background-color: $bg_dark_card;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
990
1025
|
.loading-toggle-icon,
|
|
991
1026
|
.loading-cell {
|
|
992
1027
|
&::after {
|
|
@@ -18,6 +18,7 @@ import TableActionBar from "./Components/TableActionBar";
|
|
|
18
18
|
|
|
19
19
|
import { useTableState } from "./Hooks/useTableState";
|
|
20
20
|
import { useTableActions } from "./Hooks/useTableActions";
|
|
21
|
+
import { updateStickyLayoutHeights, scheduleStickyActionBarHeightUpdate } from "./Utilities/StickyLayoutHelper";
|
|
21
22
|
|
|
22
23
|
import Card from "../pb_card/_card"
|
|
23
24
|
import Flex from "../pb_flex/_flex"
|
|
@@ -283,6 +284,33 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
|
283
284
|
|
|
284
285
|
// Visibility flag for action bar
|
|
285
286
|
const isActionBarVisible = (selectableRows && showActionsBar && selectedRowsLength > 0) || columnVisibilityControl;
|
|
287
|
+
const isStickyHeader = Boolean(tableProps?.sticky);
|
|
288
|
+
|
|
289
|
+
useEffect(() => {
|
|
290
|
+
if (!isStickyHeader || !tableWrapperRef.current) return;
|
|
291
|
+
|
|
292
|
+
const wrapper = tableWrapperRef.current;
|
|
293
|
+
const updateHeights = () => updateStickyLayoutHeights(wrapper);
|
|
294
|
+
|
|
295
|
+
updateHeights();
|
|
296
|
+
scheduleStickyActionBarHeightUpdate(wrapper);
|
|
297
|
+
|
|
298
|
+
const resizeObserver = new ResizeObserver(updateHeights);
|
|
299
|
+
resizeObserver.observe(wrapper);
|
|
300
|
+
|
|
301
|
+
const actionBar = wrapper.querySelector(".row-selection-actions-card");
|
|
302
|
+
if (actionBar) {
|
|
303
|
+
resizeObserver.observe(actionBar);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const table = wrapper.querySelector("table.pb_table");
|
|
307
|
+
const thead = table?.querySelector("thead");
|
|
308
|
+
if (thead) {
|
|
309
|
+
resizeObserver.observe(thead);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return () => resizeObserver.disconnect();
|
|
313
|
+
}, [isStickyHeader, isActionBarVisible, columnDefinitions, tableData]);
|
|
286
314
|
|
|
287
315
|
const classes = classnames(
|
|
288
316
|
buildCss("pb_advanced_table"),
|
|
@@ -295,6 +323,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
|
295
323
|
'hidden-action-bar': (selectableRows || columnVisibilityControl) && !isActionBarVisible,
|
|
296
324
|
},
|
|
297
325
|
{'advanced-table-sticky-left-columns': stickyLeftColumn && stickyLeftColumn.length > 0},
|
|
326
|
+
{ 'advanced-table-sticky-header': isStickyHeader },
|
|
298
327
|
{ 'advanced-table-no-table-container': noTableCardContainer },
|
|
299
328
|
columnGroupBorderColor ? `column-group-border-${columnGroupBorderColor}` : '',
|
|
300
329
|
scrollBarNone ? 'advanced-table-hide-scrollbar' : '',
|
|
@@ -46,6 +46,7 @@ module Playbook
|
|
|
46
46
|
max_height_classname,
|
|
47
47
|
hide_scroll_bar_class,
|
|
48
48
|
hidden_action_bar_class,
|
|
49
|
+
sticky_header_class,
|
|
49
50
|
]
|
|
50
51
|
additional_classes << "column-group-border-#{column_group_border_color}" if column_group_border_color != "none"
|
|
51
52
|
additional_classes << "advanced-table-no-table-container" if no_table_card_container?
|
|
@@ -75,6 +76,12 @@ module Playbook
|
|
|
75
76
|
selectable_rows && !is_action_bar_visible ? "hidden-action-bar" : ""
|
|
76
77
|
end
|
|
77
78
|
|
|
79
|
+
def sticky_header_class
|
|
80
|
+
return "" unless table_props.is_a?(Hash)
|
|
81
|
+
|
|
82
|
+
table_props[:sticky] || table_props["sticky"] ? "advanced-table-sticky-header" : ""
|
|
83
|
+
end
|
|
84
|
+
|
|
78
85
|
def selected_rows
|
|
79
86
|
@selected_rows ||= []
|
|
80
87
|
end
|
|
@@ -418,6 +418,56 @@ test("tableProps prop functions as expected", () => {
|
|
|
418
418
|
const kit = screen.getByTestId(testId)
|
|
419
419
|
const table = kit.querySelector('table')
|
|
420
420
|
expect(table).toHaveClass("pb_table table-sm table-responsive-none data_table sticky-header ns_tabular")
|
|
421
|
+
expect(kit).toHaveClass("advanced-table-sticky-header")
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
test("sticky header with column visibility control offsets layout heights", async () => {
|
|
425
|
+
const columnDefsWithIds = columnDefinitions.map((col) => ({
|
|
426
|
+
...col,
|
|
427
|
+
id: col.accessor,
|
|
428
|
+
}))
|
|
429
|
+
|
|
430
|
+
render(
|
|
431
|
+
<AdvancedTable
|
|
432
|
+
columnDefinitions={columnDefsWithIds}
|
|
433
|
+
columnVisibilityControl={{ default: true }}
|
|
434
|
+
data={{ testid: testId }}
|
|
435
|
+
responsive="none"
|
|
436
|
+
tableData={MOCK_DATA}
|
|
437
|
+
tableProps={{ sticky: true }}
|
|
438
|
+
/>
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
const kit = screen.getByTestId(testId)
|
|
442
|
+
expect(kit).toHaveClass("advanced-table-sticky-header")
|
|
443
|
+
expect(kit).not.toHaveClass("hidden-action-bar")
|
|
444
|
+
|
|
445
|
+
const actionBar = kit.querySelector(".row-selection-actions-card.show-action-card")
|
|
446
|
+
expect(actionBar).toBeInTheDocument()
|
|
447
|
+
|
|
448
|
+
await waitFor(() => {
|
|
449
|
+
expect(kit.style.getPropertyValue("--advanced-table-action-bar-height")).toMatch(/^\d+px$/)
|
|
450
|
+
})
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
test("sticky header without column visibility control keeps zero action bar offset", async () => {
|
|
454
|
+
render(
|
|
455
|
+
<AdvancedTable
|
|
456
|
+
columnDefinitions={columnDefinitions}
|
|
457
|
+
data={{ testid: testId }}
|
|
458
|
+
responsive="none"
|
|
459
|
+
tableData={MOCK_DATA}
|
|
460
|
+
tableProps={{ sticky: true }}
|
|
461
|
+
/>
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
const kit = screen.getByTestId(testId)
|
|
465
|
+
expect(kit).toHaveClass("advanced-table-sticky-header")
|
|
466
|
+
expect(kit).not.toHaveClass("hidden-action-bar")
|
|
467
|
+
|
|
468
|
+
await waitFor(() => {
|
|
469
|
+
expect(kit.style.getPropertyValue("--advanced-table-action-bar-height")).toBe("0px")
|
|
470
|
+
})
|
|
421
471
|
})
|
|
422
472
|
|
|
423
473
|
test("enableExpansionIcon changes icon", () => {
|
|
@@ -1,26 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
scheduleStickyActionBarHeightUpdate,
|
|
3
|
+
updateStickyActionBarHeight,
|
|
4
|
+
} from "./Utilities/StickyLayoutHelper";
|
|
5
|
+
|
|
6
|
+
// Card kit defaults to `transition-property: all`, which can animate height/opacity
|
|
7
|
+
// during expand/collapse. Limit transitions to decorative properties only.
|
|
8
|
+
const ACTION_BAR_TRANSITION_PROPERTIES = "border-color, box-shadow";
|
|
9
|
+
|
|
1
10
|
function showActionBar(actionBar, selectedCount) {
|
|
2
11
|
// Get container
|
|
3
12
|
const tableContainer = actionBar.closest('.pb_advanced_table');
|
|
4
13
|
|
|
5
|
-
//
|
|
6
|
-
|
|
14
|
+
// Update the count before measuring height so the label is included on first show
|
|
15
|
+
const countElement = actionBar.querySelector(".selected-count");
|
|
16
|
+
if (countElement) {
|
|
17
|
+
countElement.textContent = `${selectedCount} Selected`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Expand without animating height so sticky offsets measure the final size
|
|
21
|
+
actionBar.style.transitionProperty = "none";
|
|
7
22
|
actionBar.style.overflow = "visible";
|
|
8
23
|
actionBar.style.opacity = "1";
|
|
9
|
-
actionBar.style.transitionProperty = "all";
|
|
10
|
-
actionBar.style.transitionTimingFunction = "ease-in-out";
|
|
11
24
|
actionBar.classList.remove("p_none");
|
|
12
25
|
actionBar.classList.add("p_xs", "is-visible", "show-action-card");
|
|
26
|
+
actionBar.style.height = "auto";
|
|
27
|
+
|
|
28
|
+
// Force layout so padding/content are included before measuring
|
|
29
|
+
void actionBar.offsetHeight;
|
|
30
|
+
|
|
31
|
+
const expandedHeight = actionBar.scrollHeight;
|
|
32
|
+
actionBar.style.height = `${expandedHeight}px`;
|
|
13
33
|
|
|
14
34
|
// Remove hidden-action-bar class when action bar is shown
|
|
15
35
|
if (tableContainer) {
|
|
16
36
|
tableContainer.classList.remove("hidden-action-bar");
|
|
37
|
+
updateStickyActionBarHeight(tableContainer);
|
|
38
|
+
scheduleStickyActionBarHeightUpdate(tableContainer);
|
|
17
39
|
}
|
|
18
40
|
|
|
19
|
-
|
|
20
|
-
const countElement = actionBar.querySelector(".selected-count");
|
|
21
|
-
if (countElement) {
|
|
22
|
-
countElement.textContent = `${selectedCount} Selected`;
|
|
23
|
-
}
|
|
41
|
+
actionBar.style.transitionProperty = ACTION_BAR_TRANSITION_PROPERTIES;
|
|
24
42
|
}
|
|
25
43
|
|
|
26
44
|
function hideActionBar(actionBar) {
|
|
@@ -28,6 +46,7 @@ function hideActionBar(actionBar) {
|
|
|
28
46
|
const tableContainer = actionBar.closest('.pb_advanced_table');
|
|
29
47
|
|
|
30
48
|
// Hide action bar directly
|
|
49
|
+
actionBar.style.transitionProperty = "none";
|
|
31
50
|
actionBar.style.height = "0px";
|
|
32
51
|
actionBar.style.overflow = "hidden";
|
|
33
52
|
actionBar.style.opacity = "0";
|
|
@@ -37,7 +56,10 @@ function hideActionBar(actionBar) {
|
|
|
37
56
|
// Add hidden-action-bar class when action bar is hidden
|
|
38
57
|
if (tableContainer) {
|
|
39
58
|
tableContainer.classList.add("hidden-action-bar");
|
|
59
|
+
updateStickyActionBarHeight(tableContainer);
|
|
40
60
|
}
|
|
61
|
+
|
|
62
|
+
actionBar.style.transitionProperty = ACTION_BAR_TRANSITION_PROPERTIES;
|
|
41
63
|
}
|
|
42
64
|
|
|
43
65
|
export function updateSelectionActionBar(table, selectedCount) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import AdvancedTable from '../_advanced_table'
|
|
3
|
-
import
|
|
3
|
+
import MOCK_DATA_WITH_ID from "./advanced_table_mock_data_with_id.json"
|
|
4
4
|
import colors from '../../tokens/exports/_colors.module.scss'
|
|
5
5
|
|
|
6
6
|
|
|
@@ -55,7 +55,7 @@ const rowStyling = [
|
|
|
55
55
|
<AdvancedTable
|
|
56
56
|
columnDefinitions={columnDefinitions}
|
|
57
57
|
rowStyling={rowStyling}
|
|
58
|
-
tableData={
|
|
58
|
+
tableData={MOCK_DATA_WITH_ID}
|
|
59
59
|
{...props}
|
|
60
60
|
/>
|
|
61
61
|
</div>
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.html.erb
CHANGED
|
@@ -1,47 +1,39 @@
|
|
|
1
1
|
<% column_definitions = [
|
|
2
|
-
{
|
|
3
|
-
accessor: "year",
|
|
4
|
-
label: "Year",
|
|
5
|
-
},
|
|
6
|
-
{
|
|
7
|
-
accessor: "newEnrollments",
|
|
8
|
-
label: "New Enrollments",
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
accessor: "scheduledMeetings",
|
|
12
|
-
label: "Scheduled Meetings",
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
accessor: "attendanceRate",
|
|
16
|
-
label: "Attendance Rate",
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
accessor: "completedClasses",
|
|
20
|
-
label: "Completed Classes",
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
accessor: "classCompletionRate",
|
|
24
|
-
label: "Class Completion Rate",
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
accessor: "graduatedStudents",
|
|
28
|
-
label: "Graduated Students",
|
|
29
|
-
}
|
|
30
|
-
] %>
|
|
31
|
-
|
|
32
|
-
<% table_data = 15.times.map do |index|
|
|
33
2
|
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
3
|
+
accessor: "year",
|
|
4
|
+
label: "Year",
|
|
5
|
+
cellAccessors: ["quarter", "month", "day"],
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
accessor: "newEnrollments",
|
|
9
|
+
label: "New Enrollments",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
accessor: "scheduledMeetings",
|
|
13
|
+
label: "Scheduled Meetings",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
accessor: "attendanceRate",
|
|
17
|
+
label: "Attendance Rate",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
accessor: "completedClasses",
|
|
21
|
+
label: "Completed Classes",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
accessor: "classCompletionRate",
|
|
25
|
+
label: "Class Completion Rate",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
accessor: "graduatedStudents",
|
|
29
|
+
label: "Graduated Students",
|
|
30
|
+
},
|
|
31
|
+
] %>
|
|
44
32
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
<%= pb_rails("advanced_table", props: {
|
|
34
|
+
id: "table_props_sticky_table",
|
|
35
|
+
table_data: @table_data,
|
|
36
|
+
column_definitions: column_definitions,
|
|
37
|
+
max_height: "xs",
|
|
38
|
+
table_props: { sticky: true },
|
|
39
|
+
}) %>
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header.jsx
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import React from "react"
|
|
2
2
|
import AdvancedTable from '../../pb_advanced_table/_advanced_table'
|
|
3
|
-
|
|
4
|
-
const tableData = Array.from({ length: 15 }, (_, index) => ({
|
|
5
|
-
year: String(2020 + index),
|
|
6
|
-
newEnrollments: String(20 + index),
|
|
7
|
-
scheduledMeetings: String(10 + index),
|
|
8
|
-
attendanceRate: `${50 + index}%`,
|
|
9
|
-
completedClasses: String(3 + index),
|
|
10
|
-
classCompletionRate: `${30 + index}%`,
|
|
11
|
-
graduatedStudents: String(19 + index),
|
|
12
|
-
}))
|
|
3
|
+
import MOCK_DATA from "./advanced_table_mock_data.json"
|
|
13
4
|
|
|
14
5
|
const AdvancedTableTablePropsStickyHeader = (props) => {
|
|
15
6
|
const columnDefinitions = [
|
|
16
7
|
{
|
|
17
8
|
accessor: "year",
|
|
18
9
|
label: "Year",
|
|
10
|
+
cellAccessors: ["quarter", "month", "day"],
|
|
19
11
|
},
|
|
20
12
|
{
|
|
21
13
|
accessor: "newEnrollments",
|
|
@@ -44,18 +36,17 @@ const AdvancedTableTablePropsStickyHeader = (props) => {
|
|
|
44
36
|
]
|
|
45
37
|
|
|
46
38
|
const tableProps = {
|
|
47
|
-
sticky: true
|
|
39
|
+
sticky: true,
|
|
48
40
|
}
|
|
49
41
|
|
|
50
42
|
return (
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
</div>
|
|
43
|
+
<AdvancedTable
|
|
44
|
+
columnDefinitions={columnDefinitions}
|
|
45
|
+
maxHeight="xs"
|
|
46
|
+
tableData={MOCK_DATA}
|
|
47
|
+
tableProps={tableProps}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
59
50
|
)
|
|
60
51
|
}
|
|
61
52
|
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_rails.md
CHANGED
|
@@ -2,10 +2,6 @@ Create a sticky header that works for responsive Advanced Tables by setting `sti
|
|
|
2
2
|
|
|
3
3
|
**NOTE**: This behavior requires a `max_height` to work. The header is sticky within the table container, allowing for it to work along with the first column stickiness of a responsive table on smaller screen sizes.
|
|
4
4
|
|
|
5
|
-
Scroll inside the table preview to see the header stick.
|
|
6
|
-
|
|
7
|
-
This example builds flat table data inline for the docs preview. For typical `table_data` setup, see [Default (Required Props)](/kits/advanced_table/default/rails#advanced_table_beta).
|
|
8
|
-
|
|
9
5
|
Expand the table above to see this in action.
|
|
10
6
|
|
|
11
7
|
A sticky header on a nonresponsive table is demonstrated in the ["Sticky Header"](https://playbook.powerapp.cloud/kits/advanced_table#sticky-header) doc example above.
|
data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_table_props_sticky_header_react.md
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
Create a sticky header that works for responsive Advanced Tables by setting `sticky: true` via `tableProps` and
|
|
1
|
+
Create a sticky header that works for responsive Advanced Tables by setting `sticky: true` via `tableProps` and giving the AdvancedTable a `maxHeight` using our [Max Height](https://playbook.powerapp.cloud/global_props/max_height) global prop.
|
|
2
2
|
|
|
3
|
-
**NOTE**: The header is sticky within the table
|
|
3
|
+
**NOTE**: This behavior requires a `maxHeight` to work. The header is sticky within the table container, allowing for it to work along with the first column stickiness of a responsive table on smaller screen sizes.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Expand the table above to see responsive behavior in action.
|
|
5
|
+
Expand the table above to see this in action.
|
|
8
6
|
|
|
9
7
|
A sticky header on a nonresponsive table is demonstrated in the ["Sticky Header"](https://playbook.powerapp.cloud/kits/advanced_table/react#sticky-header) doc example above.
|