playbook_ui 14.19.0 → 14.20.0.pre.alpha.revert4453PBNTR933reactdraggablebugdragbtwnexamples7854
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 +11 -1
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +175 -16
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +56 -25
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +23 -13
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/VisibilityTree.ts +47 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +6 -10
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +7 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.jsx +57 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.md +4 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.jsx +62 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.jsx +82 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.jsx +66 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +3 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +4 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +5 -1
- data/app/pb_kits/playbook/pb_advanced_table/scss_partials/advanced_table_sticky_mixin.scss +1 -0
- data/app/pb_kits/playbook/pb_draggable/context/index.tsx +17 -58
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -1
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +77 -19
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.html.erb +31 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_rails.md +5 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.jsx +56 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.jsx +58 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.html.erb +20 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_display_rails.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.html.erb +19 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_rails.md +3 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.html.erb +20 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.jsx +57 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_autocomplete.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.html.erb +50 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_custom_options.jsx +105 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.html.erb +22 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_with_default.jsx +67 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.jsx +11 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display.md +1 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.html.erb +33 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_custom_display_rails.md +3 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +11 -1
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +5 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +3 -3
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +16 -2
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +34 -13
- data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +3 -1
- data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +0 -6
- data/app/pb_kits/playbook/pb_dropdown/index.js +336 -30
- data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +39 -12
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +2 -2
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +16 -12
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +79 -13
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +58 -0
- data/app/pb_kits/playbook/pb_file_upload/_file_upload.scss +13 -0
- data/app/pb_kits/playbook/pb_file_upload/_file_upload.tsx +11 -1
- data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.html.erb +1 -0
- data/app/pb_kits/playbook/pb_file_upload/docs/_file_upload_error.jsx +41 -0
- data/app/pb_kits/playbook/pb_file_upload/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_file_upload/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_file_upload/file_upload.html.erb +1 -0
- data/app/pb_kits/playbook/pb_file_upload/file_upload.rb +7 -1
- data/app/pb_kits/playbook/pb_file_upload/fileupload.test.js +18 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +1 -0
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +1 -0
- data/app/pb_kits/playbook/pb_form_group/_error_state_mixin.scss +2 -2
- data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +19 -12
- data/app/pb_kits/playbook/pb_home_address_street/_home_address_street.tsx +13 -7
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +2 -2
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_color.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_color.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_default.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_default.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_disabled_options_parent_default.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_error.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_error.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_label.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_react_hook.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_reset.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_return_all_selected.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids.html.erb +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids.md +2 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids_react.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_selected_ids_react.md +3 -1
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single.html.erb +22 -22
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single.jsx +22 -22
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single_children_only.html.erb +22 -22
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_single_children_only.jsx +22 -22
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_children_with_radios.jsx +11 -11
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_with_form.html.erb +11 -11
- data/app/pb_kits/playbook/pb_person/_person.tsx +12 -2
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +9 -9
- data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +2 -2
- data/app/pb_kits/playbook/pb_text_input/_text_input.scss +4 -2
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +73 -3
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.jsx +23 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_preserve_input.md +1 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_typeahead/docs/index.js +1 -0
- data/dist/chunks/_typeahead-C-CI5Vgw.js +22 -0
- data/dist/chunks/_weekday_stacked-BCiM3zWM.js +45 -0
- data/dist/chunks/lazysizes-B7xYodB-.js +1 -0
- data/dist/chunks/lib-D5R1BjUn.js +29 -0
- data/dist/chunks/{pb_form_validation-BioH7DWv.js → pb_form_validation-BZ2AVAi_.js} +1 -1
- data/dist/chunks/vendor.js +1 -1
- data/dist/playbook-doc.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/kit_base.rb +3 -3
- data/lib/playbook/version.rb +2 -2
- metadata +38 -8
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default.html.erb +0 -10
- data/dist/chunks/_typeahead-D62OcwsT.js +0 -22
- data/dist/chunks/_weekday_stacked-Ceh9N0ow.js +0 -45
- data/dist/chunks/lazysizes-DHz07jlL.js +0 -1
- data/dist/chunks/lib-CeKZrPmu.js +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d810ce992ce83180c727b57ffd2015356b7860a523383f4a8810b4b964c6ea1e
|
4
|
+
data.tar.gz: 7674cda91f367bc7ad377806520109d2ffd1cd9076e51c34fb5f1e3baf37120c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5d3b8da029137dbf003df505ec900c151d0986db08089339e685d89a7a38ba4b830bf745ea5701aa439bdd2df0f9febcd5728caf65a642be9f1e58579fca37e
|
7
|
+
data.tar.gz: 8304eed6d900e0a9f052b7dec2066c713606a906b7f749bd47b36553dfb0ac2df3e8ecf4f76ca1c15d80a88398dfa0b5efc954d7ca0ca109d94eb8aa5292c01f
|
@@ -93,7 +93,17 @@ export const RegularTableView = ({
|
|
93
93
|
|
94
94
|
{row.getVisibleCells().map((cell: Cell<GenericObject, unknown>, i: number) => {
|
95
95
|
const isPinnedLeft = columnPinning.left.includes(cell.column.id);
|
96
|
-
const isLastCell =
|
96
|
+
const isLastCell = (() => {
|
97
|
+
const parent = cell.column.parent;
|
98
|
+
if (!parent) {
|
99
|
+
const last = row.getVisibleCells().at(-1);
|
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
|
+
|
97
107
|
const { column } = cell;
|
98
108
|
return (
|
99
109
|
<td
|
@@ -1,52 +1,211 @@
|
|
1
|
-
import React, { useEffect, useRef } from "react";
|
1
|
+
import React, { useEffect, useRef, useContext, useState } from "react";
|
2
|
+
|
3
|
+
import AdvancedTableContext from "../Context/AdvancedTableContext";
|
4
|
+
import { buildVisibilityTree } from "../Utilities/VisibilityTree";
|
5
|
+
|
2
6
|
import Card from "../../pb_card/_card";
|
3
7
|
import Caption from "../../pb_caption/_caption";
|
4
8
|
import Flex from "../../pb_flex/_flex";
|
5
9
|
import FlexItem from "../../pb_flex/_flex_item";
|
6
|
-
import
|
10
|
+
import Icon from "../../pb_icon/_icon";
|
11
|
+
import Checkbox from "../../pb_checkbox/_checkbox";
|
12
|
+
import SectionSeparator from "../../pb_section_separator/_section_separator";
|
13
|
+
import Tooltip from "../../pb_tooltip/_tooltip";
|
14
|
+
import PbReactPopover from "../../pb_popover/_popover";
|
15
|
+
|
16
|
+
import {
|
17
|
+
showActionBar,
|
18
|
+
hideActionBar,
|
19
|
+
} from "../Utilities/ActionBarAnimationHelper";
|
20
|
+
import { GenericObject } from "../../types";
|
7
21
|
|
8
22
|
interface TableActionBarProps {
|
9
|
-
isVisible: boolean;
|
23
|
+
isVisible: boolean | GenericObject | undefined;
|
10
24
|
selectedCount: number;
|
11
25
|
actions?: React.ReactNode[] | React.ReactNode;
|
26
|
+
type?: string;
|
27
|
+
}
|
28
|
+
|
29
|
+
interface VisibilityNode {
|
30
|
+
id?: string | undefined;
|
31
|
+
label?: string | undefined;
|
32
|
+
children?: VisibilityNode[];
|
12
33
|
}
|
13
34
|
|
14
35
|
const TableActionBar: React.FC<TableActionBarProps> = ({
|
15
36
|
isVisible,
|
16
37
|
selectedCount,
|
17
|
-
actions
|
38
|
+
actions,
|
39
|
+
type = "row-selection",
|
18
40
|
}) => {
|
19
41
|
const cardRef = useRef(null);
|
42
|
+
const { table, columnVisibilityControl, columnDefinitions } =
|
43
|
+
useContext(AdvancedTableContext);
|
44
|
+
|
45
|
+
// ----------- Column visibility logic -----------
|
46
|
+
const includeIds = columnVisibilityControl?.includeIds;
|
47
|
+
const firstLeafId = table.getAllLeafColumns()[0]?.id;
|
48
|
+
// Get the first leaf column ID to exclude it from the visibility tree
|
49
|
+
// This is to avoid showing the first column in the dropdown
|
50
|
+
// as toggling it's visibility breaks the expanded row functionality
|
51
|
+
const tree = buildVisibilityTree(columnDefinitions, includeIds).filter(node => node.id !== firstLeafId);
|
52
|
+
|
53
|
+
const renderLeaf = (id: string, label: string) => {
|
54
|
+
const col = table.getColumn(id);
|
55
|
+
const show = col.getIsVisible();
|
56
|
+
|
57
|
+
const handleVisibilityChange = () => {
|
58
|
+
col.toggleVisibility();
|
59
|
+
if (columnVisibilityControl?.onColumnVisibilityChange) {
|
60
|
+
const updatedVisibilityState = {
|
61
|
+
...table.getAllColumns().reduce((acc: { [x: string]: any; }, col: { id: string | number; getIsVisible: () => any; }) => {
|
62
|
+
acc[col.id] = col.getIsVisible();
|
63
|
+
return acc;
|
64
|
+
}, {}),
|
65
|
+
};
|
66
|
+
columnVisibilityControl?.onColumnVisibilityChange(updatedVisibilityState);
|
67
|
+
}
|
68
|
+
};
|
69
|
+
|
70
|
+
return (
|
71
|
+
<Checkbox
|
72
|
+
checked={show}
|
73
|
+
key={id}
|
74
|
+
onChange={handleVisibilityChange}
|
75
|
+
paddingBottom="xs"
|
76
|
+
text={label}
|
77
|
+
/>
|
78
|
+
);
|
79
|
+
};
|
80
|
+
|
81
|
+
const gatherLeafIds = (node: VisibilityNode): string[] =>
|
82
|
+
node.children && node.children.length
|
83
|
+
? node.children.flatMap(gatherLeafIds)
|
84
|
+
: node.id
|
85
|
+
? [node.id]
|
86
|
+
: [];
|
87
|
+
|
88
|
+
const renderGroup = (node: VisibilityNode ) => {
|
89
|
+
const leaves = gatherLeafIds(node);
|
90
|
+
const visibleArray = leaves.map((id) => table.getColumn(id).getIsVisible());
|
91
|
+
const allOn = visibleArray.every(Boolean);
|
92
|
+
const someOn = visibleArray.some(Boolean);
|
93
|
+
|
94
|
+
const handleGroupVisibilityChange = () => {
|
95
|
+
leaves.forEach((id) => table.getColumn(id).toggleVisibility(!allOn));
|
96
|
+
if (columnVisibilityControl?.onColumnVisibilityChange) {
|
97
|
+
const updatedVisibilityState = {
|
98
|
+
...table.getAllColumns().reduce((acc: { [x: string]: any; }, col: { id: string | number; getIsVisible: () => any; }) => {
|
99
|
+
acc[col.id] = col.getIsVisible();
|
100
|
+
return acc;
|
101
|
+
}, {}),
|
102
|
+
};
|
103
|
+
columnVisibilityControl?.onColumnVisibilityChange(updatedVisibilityState);
|
104
|
+
}
|
105
|
+
};
|
106
|
+
return (
|
107
|
+
<>
|
108
|
+
<Checkbox
|
109
|
+
checked={allOn}
|
110
|
+
indeterminate={!allOn && someOn}
|
111
|
+
onChange={handleGroupVisibilityChange}
|
112
|
+
paddingBottom="xs"
|
113
|
+
text={node.label}
|
114
|
+
/>
|
115
|
+
<Flex flexDirection="column"
|
116
|
+
paddingLeft="lg"
|
117
|
+
>
|
118
|
+
{node?.children?.map((child) =>
|
119
|
+
child.children ? renderGroup(child) : renderLeaf(child.id, child.label),
|
120
|
+
)}
|
121
|
+
</Flex>
|
122
|
+
</>
|
123
|
+
);
|
124
|
+
};
|
125
|
+
// ------------ End of column visibility logic --------
|
20
126
|
|
21
127
|
useEffect(() => {
|
22
|
-
if (cardRef.current) {
|
128
|
+
if (cardRef.current && type === "row-selection") {
|
23
129
|
if (isVisible) {
|
24
130
|
showActionBar(cardRef.current);
|
25
131
|
} else {
|
26
132
|
hideActionBar(cardRef.current);
|
27
133
|
}
|
28
134
|
}
|
29
|
-
}, [isVisible]);
|
135
|
+
}, [isVisible, type]);
|
136
|
+
|
137
|
+
const [showPopover, setShowPopover] = useState(false)
|
138
|
+
|
139
|
+
const togglePopover = () => setShowPopover((prev) => !prev)
|
140
|
+
const handleShouldClose = (shouldClose: boolean) =>
|
141
|
+
setShowPopover(!shouldClose)
|
142
|
+
|
143
|
+
const popoverReference = (
|
144
|
+
<Tooltip
|
145
|
+
placement="top"
|
146
|
+
text="Column Configuration"
|
147
|
+
>
|
148
|
+
<div onClick={togglePopover}>
|
149
|
+
<Icon
|
150
|
+
color="primary"
|
151
|
+
cursor="pointer"
|
152
|
+
icon="sliders-h"
|
153
|
+
/>
|
154
|
+
</div>
|
155
|
+
</Tooltip>
|
156
|
+
)
|
30
157
|
|
31
158
|
return (
|
32
159
|
<Card
|
33
160
|
borderNone={!isVisible}
|
34
|
-
className={`${
|
161
|
+
className={`${
|
162
|
+
isVisible && "show-action-card row-selection-actions-card"
|
163
|
+
}`}
|
35
164
|
htmlOptions={{ ref: cardRef as any }}
|
36
165
|
padding={`${isVisible ? "xs" : "none"}`}
|
37
166
|
>
|
38
167
|
<Flex
|
39
168
|
alignItems="center"
|
40
|
-
justify="between"
|
169
|
+
justify={type === "row-selection" ? "between" : "end"}
|
41
170
|
>
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
171
|
+
{type === "row-selection" ? (
|
172
|
+
<>
|
173
|
+
<Caption color="light"
|
174
|
+
paddingLeft="xs"
|
175
|
+
size="xs"
|
176
|
+
>
|
177
|
+
{selectedCount} Selected
|
178
|
+
</Caption>
|
179
|
+
<FlexItem>{actions}</FlexItem>
|
180
|
+
</>
|
181
|
+
) : (
|
182
|
+
<PbReactPopover
|
183
|
+
closeOnClick="outside"
|
184
|
+
placement="bottom-end"
|
185
|
+
reference={popoverReference}
|
186
|
+
shouldClosePopover={handleShouldClose}
|
187
|
+
show={showPopover}
|
188
|
+
zIndex={3}
|
189
|
+
>
|
190
|
+
<>
|
191
|
+
<Caption
|
192
|
+
paddingY="sm"
|
193
|
+
text="Columns Config"
|
194
|
+
textAlign="center"
|
195
|
+
/>
|
196
|
+
<SectionSeparator paddingBottom="xs" />
|
197
|
+
{tree.map((node: VisibilityNode) => (
|
198
|
+
<Flex cursor="pointer"
|
199
|
+
flexDirection="column"
|
200
|
+
key={node.id}
|
201
|
+
paddingX="xs"
|
202
|
+
>
|
203
|
+
{node.children ? renderGroup(node) : renderLeaf(node.id, node.label)}
|
204
|
+
</Flex>
|
205
|
+
))}
|
206
|
+
</>
|
207
|
+
</PbReactPopover>
|
208
|
+
)}
|
50
209
|
</Flex>
|
51
210
|
</Card>
|
52
211
|
);
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useContext } from "react"
|
1
|
+
import React, { useContext, useState } from "react"
|
2
2
|
import classnames from "classnames"
|
3
3
|
import { flexRender, Header, Table, RowModel } from "@tanstack/react-table"
|
4
4
|
|
@@ -8,10 +8,8 @@ import { GlobalProps } from "../../utilities/globalProps"
|
|
8
8
|
|
9
9
|
import Flex from "../../pb_flex/_flex"
|
10
10
|
import Checkbox from "../../pb_checkbox/_checkbox"
|
11
|
-
import
|
12
|
-
import
|
13
|
-
import DropdownOption from "../../pb_dropdown/subcomponents/DropdownOption"
|
14
|
-
import DropdownContainer from "../../pb_dropdown/subcomponents/DropdownContainer"
|
11
|
+
import SectionSeparator from "../../pb_section_separator/_section_separator"
|
12
|
+
import PbReactPopover from "../../pb_popover/_popover";
|
15
13
|
import Icon from "../../pb_icon/_icon"
|
16
14
|
|
17
15
|
import { SortIconButton } from "./SortIconButton"
|
@@ -79,9 +77,26 @@ export const TableHeaderCell = ({
|
|
79
77
|
header?.column.getLeafColumns().length === 1 &&
|
80
78
|
header?.column.getLeafColumns()[0].id === header.column.id
|
81
79
|
|
82
|
-
const
|
83
|
-
|
84
|
-
(
|
80
|
+
const columnHasVisibleLeaf = (col: any): boolean =>
|
81
|
+
col.getIsVisible?.() ||
|
82
|
+
(Array.isArray(col.columns) &&
|
83
|
+
col.columns.some((child: any) => columnHasVisibleLeaf(child)));
|
84
|
+
|
85
|
+
// Check on column position in stack + visibility to add the vertical border
|
86
|
+
const isLastHeaderCell = (() => {
|
87
|
+
if (!header) return false;
|
88
|
+
|
89
|
+
if (header.colSpan > 1 && header.column.parent !== undefined) return true;
|
90
|
+
|
91
|
+
const parent = header.column.parent;
|
92
|
+
|
93
|
+
if (!parent) {
|
94
|
+
const topHeaders = table?.getHeaderGroups()[0].headers.filter((h: any) => columnHasVisibleLeaf(h.column));
|
95
|
+
return topHeaders?.at(-1)?.id === header.id;
|
96
|
+
}
|
97
|
+
const visibleSiblings = parent.columns.filter(columnHasVisibleLeaf);
|
98
|
+
return visibleSiblings.at(-1) === header.column;
|
99
|
+
})();
|
85
100
|
|
86
101
|
const cellClassName = classnames(
|
87
102
|
"table-header-cells",
|
@@ -119,6 +134,20 @@ const isToggleExpansionEnabled =
|
|
119
134
|
justifyHeader = isLeafColumn ? "end" : "center";
|
120
135
|
}
|
121
136
|
|
137
|
+
const [showPopover, setShowPopover] = useState(false)
|
138
|
+
|
139
|
+
const togglePopover = () => setShowPopover((prev) => !prev)
|
140
|
+
const handleShouldClose = (shouldClose: boolean) =>
|
141
|
+
setShowPopover(!shouldClose)
|
142
|
+
|
143
|
+
const popoverReference = (
|
144
|
+
<div className="gray-icon toggle-all-icon"
|
145
|
+
onClick={togglePopover}
|
146
|
+
>
|
147
|
+
<Icon icon={displayIcon(toggleExpansionIcon)[0]} />
|
148
|
+
</div>
|
149
|
+
)
|
150
|
+
|
122
151
|
const handleExpandDepth = (depth: number) => {
|
123
152
|
if (onExpandByDepthClick) {
|
124
153
|
const flatRows = table?.getRowModel().flatRows
|
@@ -174,31 +203,33 @@ const isToggleExpansionEnabled =
|
|
174
203
|
<ToggleIconButton onClick={handleExpandOrCollapse} />
|
175
204
|
)}
|
176
205
|
{isToggleExpansionEnabled && hasAnySubRows && expandByDepth && (
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
<DropdownOption
|
186
|
-
key={index}
|
187
|
-
option={option}
|
188
|
-
padding="none"
|
206
|
+
|
207
|
+
<PbReactPopover
|
208
|
+
closeOnClick="any"
|
209
|
+
placement="bottom-start"
|
210
|
+
reference={popoverReference}
|
211
|
+
shouldClosePopover={handleShouldClose}
|
212
|
+
show={showPopover}
|
213
|
+
zIndex={3}
|
189
214
|
>
|
215
|
+
{expandByDepth.map((option:{ [key: string]: any }, index: number) => (
|
216
|
+
<>
|
190
217
|
<Flex
|
191
218
|
alignItems="center"
|
219
|
+
className="pb-advanced-table-popover-option"
|
220
|
+
cursor="pointer"
|
192
221
|
htmlOptions={{onClick: () => {handleExpandDepth(option.depth)} }}
|
193
222
|
paddingX="sm"
|
194
223
|
paddingY="xs"
|
195
224
|
>
|
196
225
|
{option.label}
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
226
|
+
</Flex>
|
227
|
+
{index !== expandByDepth.length - 1 && <SectionSeparator/>}
|
228
|
+
</>
|
229
|
+
))}
|
230
|
+
</PbReactPopover>
|
231
|
+
|
232
|
+
|
202
233
|
)}
|
203
234
|
|
204
235
|
{isToggleExpansionEnabledLoading &&(
|
@@ -26,6 +26,8 @@ interface UseTableStateProps {
|
|
26
26
|
virtualizedRows?: boolean;
|
27
27
|
tableOptions?: GenericObject;
|
28
28
|
onRowSelectionChange?: (arg: RowSelectionState) => void;
|
29
|
+
columnVisibilityControl?: GenericObject;
|
30
|
+
|
29
31
|
}
|
30
32
|
|
31
33
|
export function useTableState({
|
@@ -40,16 +42,19 @@ export function useTableState({
|
|
40
42
|
pagination = false,
|
41
43
|
paginationProps,
|
42
44
|
virtualizedRows = false,
|
43
|
-
tableOptions
|
45
|
+
tableOptions,
|
46
|
+
columnVisibilityControl
|
44
47
|
}: UseTableStateProps) {
|
45
48
|
// Create a local state for expanded and setExpanded if expandedControl not used
|
46
49
|
const [localExpanded, setLocalExpanded] = useState({});
|
47
50
|
const [loadingStateRowCount, setLoadingStateRowCount] = useState(initialLoadingRowsCount);
|
48
51
|
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
49
|
-
|
52
|
+
const [localColumnVisibility, setLocalColumnVisibility] = useState({});
|
50
53
|
// Determine whether to use the prop or the local state
|
51
54
|
const expanded = expandedControl ? expandedControl.value : localExpanded;
|
52
55
|
const setExpanded = expandedControl ? expandedControl.onChange : setLocalExpanded;
|
56
|
+
const columnVisibility = (columnVisibilityControl && columnVisibilityControl.value) ? columnVisibilityControl.value : localColumnVisibility;
|
57
|
+
const setColumnVisibility = (columnVisibilityControl && columnVisibilityControl.onChange) ? columnVisibilityControl.onChange : setLocalColumnVisibility;
|
53
58
|
|
54
59
|
// Virtualized data handling (chunked loading)
|
55
60
|
const fetchSize = 20; // Number of rows per "page"
|
@@ -104,17 +109,21 @@ export function useTableState({
|
|
104
109
|
}]), [columnDefinitions, sortControl]);
|
105
110
|
|
106
111
|
// Custom state based on features enabled
|
107
|
-
const customState = useCallback(() => {
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
112
|
+
const customState = useCallback(() => ({
|
113
|
+
state: {
|
114
|
+
expanded,
|
115
|
+
...(sortControl && { sorting }),
|
116
|
+
...(selectableRows && { rowSelection }),
|
117
|
+
...(columnVisibility && { columnVisibility }),
|
118
|
+
},
|
119
|
+
}), [
|
120
|
+
expanded,
|
121
|
+
sortControl,
|
122
|
+
sorting,
|
123
|
+
selectableRows,
|
124
|
+
rowSelection,
|
125
|
+
columnVisibility,
|
126
|
+
]);
|
118
127
|
|
119
128
|
// Pagination configuration
|
120
129
|
const paginationInitializer = useMemo(() => {
|
@@ -145,6 +154,7 @@ export function useTableState({
|
|
145
154
|
sortDescFirst: true,
|
146
155
|
onRowSelectionChange: setRowSelection,
|
147
156
|
getRowId: selectableRows ? row => row.id : undefined,
|
157
|
+
onColumnVisibilityChange: setColumnVisibility,
|
148
158
|
meta: {
|
149
159
|
columnDefinitions
|
150
160
|
},
|
@@ -0,0 +1,47 @@
|
|
1
|
+
export interface VisibilityNode {
|
2
|
+
id: string;
|
3
|
+
label: string;
|
4
|
+
children?: VisibilityNode[];
|
5
|
+
}
|
6
|
+
export const buildVisibilityTree = (
|
7
|
+
defs: any[],
|
8
|
+
allowed?: string[] | null
|
9
|
+
): VisibilityNode[] =>
|
10
|
+
defs
|
11
|
+
.map((def) => {
|
12
|
+
const isGroup = Array.isArray(def.columns) && def.columns.length > 0;
|
13
|
+
|
14
|
+
// No filter at all → keep it
|
15
|
+
if (!allowed?.length) {
|
16
|
+
return isGroup
|
17
|
+
? {
|
18
|
+
id: def.id,
|
19
|
+
label: def.label,
|
20
|
+
children: buildVisibilityTree(def.columns, allowed),
|
21
|
+
}
|
22
|
+
: { id: def.id, label: def.label };
|
23
|
+
}
|
24
|
+
|
25
|
+
// 1️⃣ If *this* ID is explicitly allowed → keep it & all its children
|
26
|
+
if (allowed.includes(def.id)) {
|
27
|
+
return isGroup
|
28
|
+
? {
|
29
|
+
id: def.id,
|
30
|
+
label: def.label,
|
31
|
+
children: buildVisibilityTree(def.columns, null),
|
32
|
+
}
|
33
|
+
: { id: def.id, label: def.label };
|
34
|
+
}
|
35
|
+
|
36
|
+
// Otherwise, if it’s a group, recurse & keep only if kids survive
|
37
|
+
if (isGroup) {
|
38
|
+
const kids = buildVisibilityTree(def.columns, allowed).filter(Boolean);
|
39
|
+
return kids.length
|
40
|
+
? { id: def.id, label: def.label, children: kids }
|
41
|
+
: null;
|
42
|
+
}
|
43
|
+
|
44
|
+
// Leaf not allowed → drop it
|
45
|
+
return null;
|
46
|
+
})
|
47
|
+
.filter(Boolean);
|
@@ -150,13 +150,6 @@
|
|
150
150
|
box-sizing: border-box !important;
|
151
151
|
}
|
152
152
|
}
|
153
|
-
.expand-by-depth-dropdown-wrapper {
|
154
|
-
position: unset !important;
|
155
|
-
}
|
156
|
-
.expand-by-depth-dropdown {
|
157
|
-
width: unset !important;
|
158
|
-
text-align: left;
|
159
|
-
}
|
160
153
|
}
|
161
154
|
|
162
155
|
.pb_advanced_table_body {
|
@@ -545,14 +538,12 @@
|
|
545
538
|
background-color: $white;
|
546
539
|
box-shadow: $shadow_deep;
|
547
540
|
}
|
541
|
+
|
548
542
|
@include advanced-table-sticky-mixin(
|
549
543
|
$border_light,
|
550
544
|
$white,
|
551
545
|
lighten($silver, $opacity_7)
|
552
546
|
);
|
553
|
-
|
554
|
-
// Apply border colors for sticky columns
|
555
|
-
@include apply-sticky-colors("light");
|
556
547
|
}
|
557
548
|
|
558
549
|
// Responsive Styles
|
@@ -818,3 +809,8 @@
|
|
818
809
|
}
|
819
810
|
}
|
820
811
|
}
|
812
|
+
|
813
|
+
// Outside of the pb_advanced_table class for popover
|
814
|
+
.pb-advanced-table-popover-option:hover {
|
815
|
+
background-color: $bg_light;
|
816
|
+
}
|
@@ -35,6 +35,7 @@ type AdvancedTableProps = {
|
|
35
35
|
className?: string
|
36
36
|
columnDefinitions: GenericObject[]
|
37
37
|
columnGroupBorderColor?: "text_lt_default" | "text_lt_light" | "text_lt_lighter" | "text_dk_default" | "text_dk_light" | "text_dk_lighter"
|
38
|
+
columnVisibilityControl?: GenericObject
|
38
39
|
dark?: boolean
|
39
40
|
data?: { [key: string]: string }
|
40
41
|
enableToggleExpansion?: "all" | "header" | "none"
|
@@ -73,6 +74,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
73
74
|
className,
|
74
75
|
columnDefinitions,
|
75
76
|
columnGroupBorderColor,
|
77
|
+
columnVisibilityControl,
|
76
78
|
dark = false,
|
77
79
|
data = {},
|
78
80
|
enableToggleExpansion = "header",
|
@@ -132,7 +134,8 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
132
134
|
paginationProps,
|
133
135
|
virtualizedRows,
|
134
136
|
tableOptions,
|
135
|
-
onRowSelectionChange
|
137
|
+
onRowSelectionChange,
|
138
|
+
columnVisibilityControl,
|
136
139
|
});
|
137
140
|
|
138
141
|
// Initialize table actions
|
@@ -252,7 +255,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
252
255
|
: {};
|
253
256
|
|
254
257
|
// Visibility flag for action bar
|
255
|
-
const isActionBarVisible = selectableRows && showActionsBar && selectedRowsLength > 0;
|
258
|
+
const isActionBarVisible = (selectableRows && showActionsBar && selectedRowsLength > 0) || columnVisibilityControl;
|
256
259
|
|
257
260
|
return (
|
258
261
|
<>
|
@@ -286,6 +289,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
286
289
|
<AdvancedTableProvider
|
287
290
|
columnDefinitions={columnDefinitions}
|
288
291
|
columnGroupBorderColor={columnGroupBorderColor}
|
292
|
+
columnVisibilityControl={columnVisibilityControl}
|
289
293
|
enableToggleExpansion={enableToggleExpansion}
|
290
294
|
enableVirtualization={virtualizedRows}
|
291
295
|
expandByDepth={expandByDepth}
|
@@ -316,6 +320,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
316
320
|
actions={actions}
|
317
321
|
isVisible={isActionBarVisible}
|
318
322
|
selectedCount={selectedRowsLength}
|
323
|
+
type={columnVisibilityControl ? "column-visibility" : "row-selection"}
|
319
324
|
/>
|
320
325
|
|
321
326
|
{/* Main Table */}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import React from "react"
|
2
|
+
import AdvancedTable from '../../pb_advanced_table/_advanced_table'
|
3
|
+
import MOCK_DATA from "./advanced_table_mock_data.json"
|
4
|
+
|
5
|
+
const AdvancedTableColumnVisibility = (props) => {
|
6
|
+
const columnDefinitions = [
|
7
|
+
{
|
8
|
+
accessor: "year",
|
9
|
+
label: "Year",
|
10
|
+
cellAccessors: ["quarter", "month", "day"],
|
11
|
+
id: "year"
|
12
|
+
},
|
13
|
+
{
|
14
|
+
accessor: "newEnrollments",
|
15
|
+
label: "New Enrollments",
|
16
|
+
id: "newEnrollments"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
accessor: "scheduledMeetings",
|
20
|
+
label: "Scheduled Meetings",
|
21
|
+
id: "scheduledMeetings"
|
22
|
+
},
|
23
|
+
{
|
24
|
+
accessor: "attendanceRate",
|
25
|
+
label: "Attendance Rate",
|
26
|
+
id: "attendanceRate"
|
27
|
+
},
|
28
|
+
{
|
29
|
+
accessor: "completedClasses",
|
30
|
+
label: "Completed Classes",
|
31
|
+
id: "completedClasses"
|
32
|
+
},
|
33
|
+
{
|
34
|
+
accessor: "classCompletionRate",
|
35
|
+
label: "Class Completion Rate",
|
36
|
+
id: "classCompletionRate"
|
37
|
+
},
|
38
|
+
{
|
39
|
+
accessor: "graduatedStudents",
|
40
|
+
label: "Graduated Students",
|
41
|
+
id: "graduatedStudents"
|
42
|
+
},
|
43
|
+
]
|
44
|
+
|
45
|
+
return (
|
46
|
+
<div>
|
47
|
+
<AdvancedTable
|
48
|
+
columnDefinitions={columnDefinitions}
|
49
|
+
columnVisibilityControl={{default: true}}
|
50
|
+
tableData={MOCK_DATA}
|
51
|
+
{...props}
|
52
|
+
/>
|
53
|
+
</div>
|
54
|
+
)
|
55
|
+
}
|
56
|
+
|
57
|
+
export default AdvancedTableColumnVisibility
|
@@ -0,0 +1,4 @@
|
|
1
|
+
The `columnVisibilityControl` prop allows users to toggle the visibility of table columns dynamically.
|
2
|
+
|
3
|
+
The default can be enabled simply by passing `{ default:true }` to the prop as shown. This will render the header with the icon enabled dropdown. The dropdown contains all columns present in the Table and any can be toggled on or off via the checkboxes.
|
4
|
+
**NOTE**: The first column will not be shown in the dropdown as an option since all the expansion logic/functionality lives there and it should always be visible.
|