playbook_ui 14.18.1.pre.rc.0 → 14.19.0.pre.alpha.PLAY21297675

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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +0 -1
  3. data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +11 -1
  4. data/app/pb_kits/playbook/pb_advanced_table/Components/TableActionBar.tsx +148 -15
  5. data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +20 -3
  6. data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +23 -13
  7. data/app/pb_kits/playbook/pb_advanced_table/Utilities/VisibilityTree.ts +47 -0
  8. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +313 -21
  9. data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +12 -3
  10. data/app/pb_kits/playbook/pb_advanced_table/advanced_table.rb +6 -1
  11. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_beta.md +0 -6
  12. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_border_color.jsx +80 -0
  13. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_border_color.md +3 -0
  14. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_border_color_rails.html.erb +58 -0
  15. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_border_color_rails.md +3 -0
  16. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.jsx +57 -0
  17. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility.md +4 -0
  18. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.jsx +62 -0
  19. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_custom.md +1 -0
  20. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.jsx +82 -0
  21. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_multi.md +1 -0
  22. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.jsx +65 -0
  23. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_visibility_with_state.md +1 -0
  24. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_no_subrows_rails.md +5 -1
  25. data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_selectable_rows_no_subrows.jsx → _advanced_table_selectable_rows_no_subrows_react.jsx} +2 -2
  26. data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_selectable_rows_rails.md +3 -2
  27. data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +10 -5
  28. data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +7 -2
  29. data/app/pb_kits/playbook/pb_advanced_table/flat_advanced_table.js +106 -0
  30. data/app/pb_kits/playbook/pb_advanced_table/index.js +228 -11
  31. data/app/pb_kits/playbook/pb_advanced_table/scss_partials/advanced_table_sticky_mixin.scss +1 -0
  32. data/app/pb_kits/playbook/pb_advanced_table/table_body.rb +9 -1
  33. data/app/pb_kits/playbook/pb_advanced_table/table_header.rb +0 -3
  34. data/app/pb_kits/playbook/pb_advanced_table/table_row.rb +1 -2
  35. data/app/pb_kits/playbook/pb_avatar/_avatar.scss +4 -0
  36. data/app/pb_kits/playbook/pb_avatar/_avatar.tsx +3 -0
  37. data/app/pb_kits/playbook/pb_avatar/avatar.html.erb +3 -3
  38. data/app/pb_kits/playbook/pb_avatar/avatar.rb +2 -0
  39. data/app/pb_kits/playbook/pb_avatar/avatar.test.js +18 -0
  40. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_grayscale.html.erb +5 -0
  41. data/app/pb_kits/playbook/pb_avatar/docs/_avatar_grayscale.jsx +16 -0
  42. data/app/pb_kits/playbook/pb_avatar/docs/example.yml +2 -0
  43. data/app/pb_kits/playbook/pb_avatar/docs/index.js +1 -0
  44. data/app/pb_kits/playbook/pb_card/card.html.erb +1 -1
  45. data/app/pb_kits/playbook/pb_card/card.rb +12 -0
  46. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_error.html.erb +2 -2
  47. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_drop_zones.html.erb +22 -1
  48. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_drop_zones_line.html.erb +55 -0
  49. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_drop_zones_line_rails.md +5 -0
  50. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_drop_zones_rails.md +5 -0
  51. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_event_listeners.jsx +59 -0
  52. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_event_listeners_react.md +1 -0
  53. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +2 -0
  54. data/app/pb_kits/playbook/pb_draggable/docs/index.js +2 -1
  55. data/app/pb_kits/playbook/pb_draggable/draggable_container.rb +11 -1
  56. data/app/pb_kits/playbook/pb_draggable/draggable_item.rb +11 -1
  57. data/app/pb_kits/playbook/pb_draggable/index.js +4 -2
  58. data/app/pb_kits/playbook/pb_draggable/subcomponents/DraggableItem.tsx +33 -5
  59. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +5 -0
  60. data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +5 -16
  61. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_error.html.erb +5 -2
  62. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete.html.erb +28 -0
  63. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete.jsx +17 -64
  64. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete_with_subcomponents.html.erb +58 -0
  65. data/app/pb_kits/playbook/pb_dropdown/docs/{_dropdown_with_autocomplete_and_custom_display.jsx → _dropdown_with_autocomplete_with_subcomponents.jsx} +11 -25
  66. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete_with_subcomponents.md +1 -0
  67. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_external_control.md +1 -0
  68. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_search.jsx +61 -0
  69. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_search.md +2 -0
  70. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_search_rails.html.erb +52 -0
  71. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_search_rails.md +2 -0
  72. data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +7 -4
  73. data/app/pb_kits/playbook/pb_dropdown/docs/index.js +2 -2
  74. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +2 -2
  75. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +4 -0
  76. data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +45 -1
  77. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +10 -0
  78. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.rb +3 -0
  79. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.html.erb +12 -2
  80. data/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb +3 -1
  81. data/app/pb_kits/playbook/pb_dropdown/index.js +57 -0
  82. data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +26 -0
  83. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownContainer.tsx +3 -4
  84. data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +4 -4
  85. data/app/pb_kits/playbook/pb_empty_state/_empty_state.scss +8 -1
  86. data/app/pb_kits/playbook/pb_empty_state/docs/_empty_state_alignment.html.erb +27 -0
  87. data/app/pb_kits/playbook/pb_empty_state/docs/_empty_state_default.html.erb +7 -0
  88. data/app/pb_kits/playbook/pb_empty_state/docs/_empty_state_orientation.html.erb +12 -0
  89. data/app/pb_kits/playbook/pb_empty_state/docs/_empty_state_size.html.erb +23 -0
  90. data/app/pb_kits/playbook/pb_empty_state/docs/example.yml +5 -1
  91. data/app/pb_kits/playbook/pb_empty_state/empty_state.html.erb +19 -0
  92. data/app/pb_kits/playbook/pb_empty_state/empty_state.rb +123 -0
  93. data/app/pb_kits/playbook/pb_message/_message.tsx +3 -0
  94. data/app/pb_kits/playbook/pb_message/docs/_message_grayscale.html.erb +9 -0
  95. data/app/pb_kits/playbook/pb_message/docs/_message_grayscale.jsx +21 -0
  96. data/app/pb_kits/playbook/pb_message/docs/example.yml +2 -0
  97. data/app/pb_kits/playbook/pb_message/docs/index.js +1 -0
  98. data/app/pb_kits/playbook/pb_message/message.html.erb +2 -1
  99. data/app/pb_kits/playbook/pb_message/message.rb +1 -0
  100. data/app/pb_kits/playbook/pb_overlay/_overlay.scss +2 -1
  101. data/app/pb_kits/playbook/pb_overlay/docs/_overlay_vertical_dynamic_multi_directional.jsx +1 -1
  102. data/app/pb_kits/playbook/pb_overlay/subcomponents/_overlay_token.tsx +5 -4
  103. data/app/pb_kits/playbook/pb_section_separator/_section_separator.tsx +2 -2
  104. data/app/pb_kits/playbook/pb_select/_select.scss +10 -0
  105. data/app/pb_kits/playbook/pb_select/docs/_select_error.html.erb +1 -1
  106. data/app/pb_kits/playbook/pb_table/docs/_table_with_collapsible_with_custom_click.jsx +7 -7
  107. data/app/pb_kits/playbook/pb_table/subcomponents/_table_row.tsx +5 -5
  108. data/app/pb_kits/playbook/pb_text_input/docs/_text_input_error.html.erb +1 -1
  109. data/app/pb_kits/playbook/pb_textarea/docs/_textarea_error.html.erb +5 -1
  110. data/app/pb_kits/playbook/pb_typeahead/docs/_typeahead_error_state.html.erb +8 -1
  111. data/app/pb_kits/playbook/pb_user/_user.tsx +3 -0
  112. data/app/pb_kits/playbook/pb_user/docs/_user_grayscale.html.erb +6 -0
  113. data/app/pb_kits/playbook/pb_user/docs/_user_grayscale.jsx +16 -0
  114. data/app/pb_kits/playbook/pb_user/docs/example.yml +2 -0
  115. data/app/pb_kits/playbook/pb_user/docs/index.js +1 -0
  116. data/app/pb_kits/playbook/pb_user/user.html.erb +2 -1
  117. data/app/pb_kits/playbook/pb_user/user.rb +1 -0
  118. data/dist/chunks/{_typeahead-D8CsVBZO.js → _typeahead-BPSIWtFT.js} +3 -3
  119. data/dist/chunks/_weekday_stacked-BeuPAmxG.js +45 -0
  120. data/dist/chunks/{lib-BmTAc7Nc.js → lib-B20MXZcW.js} +2 -2
  121. data/dist/chunks/{pb_form_validation-BWjy4bFn.js → pb_form_validation-WWvUXPKD.js} +1 -1
  122. data/dist/chunks/vendor.js +1 -1
  123. data/dist/menu.yml +6 -14
  124. data/dist/playbook-doc.js +2 -2
  125. data/dist/playbook-rails-react-bindings.js +1 -1
  126. data/dist/playbook-rails.js +1 -1
  127. data/dist/playbook.css +1 -1
  128. data/lib/playbook/version.rb +2 -2
  129. metadata +52 -21
  130. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_autocomplete_and_custom_display.md +0 -1
  131. data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_with_hook.jsx +0 -79
  132. data/app/pb_kits/playbook/pb_gantt_chart/_gantt_chart.scss +0 -3
  133. data/app/pb_kits/playbook/pb_gantt_chart/_gantt_chart.tsx +0 -72
  134. data/app/pb_kits/playbook/pb_gantt_chart/docs/_gantt_chart_default.jsx +0 -53
  135. data/app/pb_kits/playbook/pb_gantt_chart/docs/example.yml +0 -7
  136. data/app/pb_kits/playbook/pb_gantt_chart/docs/index.js +0 -1
  137. data/app/pb_kits/playbook/pb_gantt_chart/gantt_chart.test.jsx +0 -19
  138. data/dist/chunks/_weekday_stacked-CHQsoCdP.js +0 -45
  139. /data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_selectable_rows_react.md → _advanced_table_selectable_rows.md} +0 -0
  140. /data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_selectable_rows_no_subrows.html.erb → _advanced_table_selectable_rows_no_subrows_rails.html.erb} +0 -0
  141. /data/app/pb_kits/playbook/pb_advanced_table/docs/{_advanced_table_selectable_rows.html.erb → _advanced_table_selectable_rows_rails.html.erb} +0 -0
  142. /data/app/pb_kits/playbook/pb_draggable/docs/{_draggable_drop_zones_line.md → _draggable_drop_zones_line_react.md} +0 -0
  143. /data/app/pb_kits/playbook/pb_draggable/docs/{_draggable_event_listeners.md → _draggable_event_listeners_rails.md} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 676d756bcd1eb62b676282c0e74441ffade83e9b25d10e796a50bdbe822d84aa
4
- data.tar.gz: 389e14aff56bbe684b8ecda79b54db9e4903142ebf20ab6a9227a36b6b12879d
3
+ metadata.gz: 93df013c8d48a5c077ccdb15133ab4682b05d667db94eba9bdd6e8accba7d472
4
+ data.tar.gz: '085bc5dffd842ea4fc4fe35f8579b517523ad0e02f6b9692fe33faecbf6b9284'
5
5
  SHA512:
6
- metadata.gz: cf48871b90e1b69e6b52380b9af3228843758e70d1889744044bfccb80e12f2dfeb590b552489a838c13d8b04157c6ed20b84fcd50d648472fad7197c12e4b45
7
- data.tar.gz: 591f7a30be8318184e0b1fe2679b04758666464a1fc3e705172530389bb6c81327b7f60083ea1607225f280b477545d3ec274f82d8eb5e978158deba63903668
6
+ metadata.gz: 463d71189c32e8500ca647672d4202ffbfb23e0d73c068eaf50a0779752a0f91d9151bcfce121cc3050066a1a0897eb13b86b05328630aa6f5e3ee80baa50586
7
+ data.tar.gz: 00d153cdde95a0761c7515b5fb5de2dff87d10cb7f7e1e16e2f092bee31f1110ed713c6c3599fb57fb11bc347800f6bb1510798990904ad84629580d42a427e4
@@ -40,7 +40,6 @@
40
40
  @import 'pb_form/form';
41
41
  @import 'pb_form_group/form_group';
42
42
  @import 'pb_form_pill/form_pill';
43
- @import 'pb_gantt_chart/gantt_chart';
44
43
  @import 'pb_gauge/gauge';
45
44
  @import 'pb_hashtag/hashtag';
46
45
  @import 'pb_highlight/highlight';
@@ -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 = cell.column.parent?.columns?.at(-1)?.id === cell.column.id;
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,25 +1,112 @@
1
- import React, { useEffect, useRef } from "react";
1
+ import React, { useEffect, useRef, useContext } 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 { showActionBar, hideActionBar } from "../Utilities/ActionBarAnimationHelper";
10
+ import Dropdown from "../../pb_dropdown/_dropdown";
11
+ import DropdownContainer from "../../pb_dropdown/subcomponents/DropdownContainer";
12
+ import DropdownTrigger from "../../pb_dropdown/subcomponents/DropdownTrigger";
13
+ import Icon from "../../pb_icon/_icon";
14
+ import Checkbox from "../../pb_checkbox/_checkbox";
15
+ import SectionSeparator from "../../pb_section_separator/_section_separator";
16
+ import Tooltip from "../../pb_tooltip/_tooltip";
17
+
18
+ import {
19
+ showActionBar,
20
+ hideActionBar,
21
+ } from "../Utilities/ActionBarAnimationHelper";
22
+ import { GenericObject } from "../../types";
7
23
 
8
24
  interface TableActionBarProps {
9
- isVisible: boolean;
25
+ isVisible: boolean | GenericObject | undefined;
10
26
  selectedCount: number;
11
27
  actions?: React.ReactNode[] | React.ReactNode;
28
+ type?: string;
29
+ }
30
+
31
+ interface VisibilityNode {
32
+ id?: string | undefined;
33
+ label?: string | undefined;
34
+ children?: VisibilityNode[];
12
35
  }
13
36
 
14
37
  const TableActionBar: React.FC<TableActionBarProps> = ({
15
38
  isVisible,
16
39
  selectedCount,
17
- actions
40
+ actions,
41
+ type = "row-selection",
18
42
  }) => {
19
43
  const cardRef = useRef(null);
44
+ const { table, columnVisibilityControl, columnDefinitions } =
45
+ useContext(AdvancedTableContext);
46
+
47
+ // ----------- Column visibility logic -----------
48
+ const includeIds = columnVisibilityControl?.includeIds;
49
+ const firstLeafId = table.getAllLeafColumns()[0]?.id;
50
+ // Get the first leaf column ID to exclude it from the visibility tree
51
+ // This is to avoid showing the first column in the dropdown
52
+ // as toggling it's visibility breaks the expanded row functionality
53
+ const tree = buildVisibilityTree(columnDefinitions, includeIds).filter(node => node.id !== firstLeafId);
54
+
55
+ const renderLeaf = (id: string, label: string) => {
56
+ const col = table.getColumn(id);
57
+ const show = col.getIsVisible();
58
+
59
+ return (
60
+ <Checkbox
61
+ checked={show}
62
+ key={id}
63
+ onChange={() => col.toggleVisibility()}
64
+ paddingBottom="xs"
65
+ text={label}
66
+ />
67
+ );
68
+ };
69
+
70
+ const gatherLeafIds = (node: VisibilityNode): string[] =>
71
+ node.children && node.children.length
72
+ ? node.children.flatMap(gatherLeafIds)
73
+ : node.id
74
+ ? [node.id]
75
+ : [];
76
+
77
+ const renderGroup = (node: VisibilityNode ) => {
78
+ const leaves = gatherLeafIds(node);
79
+ const visibleArray = leaves.map((id) => table.getColumn(id).getIsVisible());
80
+ const allOn = visibleArray.every(Boolean);
81
+ const someOn = visibleArray.some(Boolean);
82
+
83
+ return (
84
+ <>
85
+ <Checkbox
86
+ checked={allOn}
87
+ indeterminate={!allOn && someOn}
88
+ onChange={() =>
89
+ leaves.forEach((id) =>
90
+ table.getColumn(id).toggleVisibility(!allOn),
91
+ )
92
+ }
93
+ paddingBottom="xs"
94
+ text={node.label}
95
+ />
96
+ <Flex flexDirection="column"
97
+ paddingLeft="lg"
98
+ >
99
+ {node?.children?.map((child) =>
100
+ child.children ? renderGroup(child) : renderLeaf(child.id, child.label),
101
+ )}
102
+ </Flex>
103
+ </>
104
+ );
105
+ };
106
+ // ------------ End of column visibility logic --------
20
107
 
21
108
  useEffect(() => {
22
- if (cardRef.current) {
109
+ if (cardRef.current && type === "row-selection") {
23
110
  if (isVisible) {
24
111
  showActionBar(cardRef.current);
25
112
  } else {
@@ -31,22 +118,68 @@ const TableActionBar: React.FC<TableActionBarProps> = ({
31
118
  return (
32
119
  <Card
33
120
  borderNone={!isVisible}
34
- className={`${isVisible && "show-action-card row-selection-actions-card"}`}
121
+ className={`${
122
+ isVisible && "show-action-card row-selection-actions-card"
123
+ }`}
35
124
  htmlOptions={{ ref: cardRef as any }}
36
125
  padding={`${isVisible ? "xs" : "none"}`}
37
126
  >
38
127
  <Flex
39
128
  alignItems="center"
40
- justify="between"
129
+ justify={type === "row-selection" ? "between" : "end"}
41
130
  >
42
- <Caption
43
- color="light"
44
- paddingLeft="xs"
45
- size="xs"
46
- >
47
- {selectedCount} Selected
48
- </Caption>
49
- <FlexItem>{actions}</FlexItem>
131
+ {type === "row-selection" ? (
132
+ <>
133
+ <Caption color="light"
134
+ paddingLeft="xs"
135
+ size="xs"
136
+ >
137
+ {selectedCount} Selected
138
+ </Caption>
139
+ <FlexItem>{actions}</FlexItem>
140
+ </>
141
+ ) : (
142
+ <Dropdown
143
+ className="column-visibility-dropdown-wrapper"
144
+ options={columnDefinitions}
145
+ >
146
+ <DropdownTrigger>
147
+ <Tooltip
148
+ placement='top'
149
+ text="Column Configuration"
150
+ zIndex={10}
151
+ >
152
+ <Icon
153
+ color="primary"
154
+ cursor="pointer"
155
+ icon="sliders-h"
156
+ />
157
+ </Tooltip>
158
+ </DropdownTrigger>
159
+ <DropdownContainer
160
+ className="column-visibility-dropdown"
161
+ paddingTop="sm"
162
+ >
163
+ <>
164
+ <Caption
165
+ paddingBottom="sm"
166
+ text="Columns Config"
167
+ textAlign="center"
168
+ />
169
+ <SectionSeparator paddingBottom="xs" />
170
+ {tree.map((node: VisibilityNode) => (
171
+ <Flex cursor="pointer"
172
+ flexDirection="column"
173
+ key={node.id}
174
+ paddingX="xs"
175
+ >
176
+ {node.children ? renderGroup(node) : renderLeaf(node.id, node.label)}
177
+ </Flex>
178
+ ))}
179
+ </>
180
+ </DropdownContainer>
181
+ </Dropdown>
182
+ )}
50
183
  </Flex>
51
184
  </Card>
52
185
  );
@@ -79,9 +79,26 @@ export const TableHeaderCell = ({
79
79
  header?.column.getLeafColumns().length === 1 &&
80
80
  header?.column.getLeafColumns()[0].id === header.column.id
81
81
 
82
- const isLastHeaderCell =
83
- header?.column.parent?.columns.at(-1) === header?.column ||
84
- (header?.colSpan > 1 && header?.column.parent !== undefined);
82
+ const columnHasVisibleLeaf = (col: any): boolean =>
83
+ col.getIsVisible?.() ||
84
+ (Array.isArray(col.columns) &&
85
+ col.columns.some((child: any) => columnHasVisibleLeaf(child)));
86
+
87
+ // Check on column position in stack + visibility to add the vertical border
88
+ const isLastHeaderCell = (() => {
89
+ if (!header) return false;
90
+
91
+ if (header.colSpan > 1 && header.column.parent !== undefined) return true;
92
+
93
+ const parent = header.column.parent;
94
+
95
+ if (!parent) {
96
+ const topHeaders = table?.getHeaderGroups()[0].headers.filter((h: any) => columnHasVisibleLeaf(h.column));
97
+ return topHeaders?.at(-1)?.id === header.id;
98
+ }
99
+ const visibleSiblings = parent.columns.filter(columnHasVisibleLeaf);
100
+ return visibleSiblings.at(-1) === header.column;
101
+ })();
85
102
 
86
103
  const cellClassName = classnames(
87
104
  "table-header-cells",
@@ -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
- if (sortControl && selectableRows) {
109
- return { state: { expanded, sorting, rowSelection } };
110
- } else if (sortControl) {
111
- return { state: { expanded, sorting } };
112
- } else if (selectableRows) {
113
- return { state: { expanded, rowSelection } };
114
- } else {
115
- return { state: { expanded } };
116
- }
117
- }, [expanded, rowSelection, sortControl, selectableRows, sorting]);
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);