playbook_ui 16.2.0.pre.alpha.PLAY2828alphafortempo14533 → 16.2.0.pre.alpha.advancedtablecascadingcollapsereact14676
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 +17 -4
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +3 -1
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableActions.ts +21 -9
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/ExpansionControlHelpers.tsx +25 -1
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +5 -1
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +74 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_cascade_collapse.jsx +50 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_cascade_collapse.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_body/_body.scss +1 -1
- data/app/pb_kits/playbook/pb_body/_body_mixins.scss +1 -1
- data/app/pb_kits/playbook/pb_button/_button.scss +3 -2
- data/app/pb_kits/playbook/pb_caption/_caption.scss +1 -1
- data/app/pb_kits/playbook/pb_caption/_caption_mixin.scss +1 -1
- data/app/pb_kits/playbook/pb_checkbox/_checkbox.scss +6 -6
- data/app/pb_kits/playbook/pb_collapsible/index.js +16 -4
- data/app/pb_kits/playbook/pb_date_picker/_date_picker.scss +2 -2
- data/app/pb_kits/playbook/pb_date_picker/_date_picker.tsx +4 -1
- data/app/pb_kits/playbook/pb_date_picker/date_picker.html.erb +2 -2
- data/app/pb_kits/playbook/pb_date_picker/sass_partials/_input_styles.scss +0 -1
- data/app/pb_kits/playbook/pb_detail/_detail.scss +2 -2
- data/app/pb_kits/playbook/pb_detail/_detail_mixins.scss +1 -1
- data/app/pb_kits/playbook/pb_dialog/index.js +45 -5
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +4 -4
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +2 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +2 -2
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +1 -1
- data/app/pb_kits/playbook/pb_dropdown/index.js +68 -13
- data/app/pb_kits/playbook/pb_dropdown/keyboard_accessibility.js +19 -3
- data/app/pb_kits/playbook/pb_enhanced_element/element_observer.ts +1 -1
- data/app/pb_kits/playbook/pb_enhanced_element/index.ts +2 -1
- data/app/pb_kits/playbook/pb_icon/icon.rb +168 -19
- data/app/pb_kits/playbook/pb_kit_registry/index.ts +180 -0
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.scss +2 -2
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +2 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_react_reset_key.jsx +100 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/_multi_level_select_react_reset_key.md +1 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_multi_level_select/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_pagination/_pagination.scss +101 -1
- data/app/pb_kits/playbook/pb_pagination/_pagination.test.jsx +172 -1
- data/app/pb_kits/playbook/pb_pagination/_pagination.tsx +178 -15
- data/app/pb_kits/playbook/pb_pagination/docs/_pagination_default.jsx +1 -1
- data/app/pb_kits/playbook/pb_passphrase/_passphrase.scss +2 -2
- data/app/pb_kits/playbook/pb_passphrase/_passphrase.tsx +4 -0
- data/app/pb_kits/playbook/pb_phone_number_input/_phone_number_input.scss +5 -5
- data/app/pb_kits/playbook/pb_radio/_radio.scss +3 -3
- data/app/pb_kits/playbook/pb_rich_text_editor/_previewer_mixin.scss +2 -2
- data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.scss +4 -4
- data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +2 -0
- data/app/pb_kits/playbook/pb_rich_text_editor/_tiptap_styles.scss +1 -1
- data/app/pb_kits/playbook/pb_select/_select.scss +6 -6
- data/app/pb_kits/playbook/pb_select/_select.tsx +2 -0
- data/app/pb_kits/playbook/pb_select/select.html.erb +2 -2
- data/app/pb_kits/playbook/pb_star_rating/star_rating.html.erb +1 -1
- data/app/pb_kits/playbook/pb_star_rating/subcomponents/_star_rating_interactive.tsx +1 -0
- data/app/pb_kits/playbook/pb_text_input/_text_input.scss +0 -1
- data/app/pb_kits/playbook/pb_text_input/_text_input.tsx +2 -0
- data/app/pb_kits/playbook/pb_text_input/text_input.html.erb +2 -2
- data/app/pb_kits/playbook/pb_textarea/_textarea.scss +1 -2
- data/app/pb_kits/playbook/pb_textarea/_textarea.tsx +43 -21
- data/app/pb_kits/playbook/pb_textarea/docs/_textarea_input_options.jsx +68 -0
- data/app/pb_kits/playbook/pb_textarea/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_textarea/docs/index.js +9 -8
- data/app/pb_kits/playbook/pb_textarea/textarea.html.erb +4 -4
- data/app/pb_kits/playbook/pb_textarea/textarea.rb +6 -2
- data/app/pb_kits/playbook/pb_textarea/textarea.test.js +134 -1
- data/app/pb_kits/playbook/pb_time_picker/_time_picker.scss +4 -4
- data/app/pb_kits/playbook/pb_time_picker/_time_picker.tsx +6 -0
- data/app/pb_kits/playbook/pb_time_picker/time_picker.test.jsx +2 -2
- data/app/pb_kits/playbook/pb_title/_title_mixin.scss +1 -1
- data/app/pb_kits/playbook/pb_tooltip/index.js +60 -15
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +2 -2
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.test.jsx +1 -1
- data/dist/chunks/{_pb_line_graph-BSLb5VXP.js → _pb_line_graph-BGY7jEks.js} +1 -1
- data/dist/chunks/{_typeahead-DXIBDeMj.js → _typeahead-QhswHQnq.js} +1 -1
- data/dist/chunks/{globalProps-DyTB8IdV.js → globalProps-CK2YuA9O.js} +1 -1
- data/dist/chunks/{lib-9wz3x5jl.js → lib-DspaUdlc.js} +1 -1
- data/dist/chunks/vendor.js +5 -5
- data/dist/menu.yml +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/forms/builder/checkbox_field.rb +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +12 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3310889318a881050c07f029fb5257de930342ee8eef612020cab8aae49ad888
|
|
4
|
+
data.tar.gz: b45cc744fe4dfccfab3660baef4909a91278e7551c7de2b6cae8d4abf98849b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 29ba51ada748179cd73e7227ea9981f7fc252cc36e644b2e99447e86092f846ec0ca34c5f633070832c861a58f55b5339c8315757e1db2bacf3a61d5301843d4
|
|
7
|
+
data.tar.gz: d033429369a41a1c3a0785f96b16c45b49378118dfb37d10937a0766803b141ad41e67800d2ba58c1ffd2a2c3927ee7749bacc70062ca5747af694accd8565e6
|
|
@@ -11,6 +11,7 @@ import Icon from "../../pb_icon/_icon"
|
|
|
11
11
|
import Checkbox from "../../pb_checkbox/_checkbox"
|
|
12
12
|
|
|
13
13
|
import AdvancedTableContext from "../Context/AdvancedTableContext"
|
|
14
|
+
import { getDescendantRowIds } from "../Utilities/ExpansionControlHelpers"
|
|
14
15
|
|
|
15
16
|
interface CustomCellProps {
|
|
16
17
|
getValue?: Getter<string>
|
|
@@ -31,13 +32,25 @@ export const CustomCell = ({
|
|
|
31
32
|
selectableRows,
|
|
32
33
|
customStyle = {},
|
|
33
34
|
}: CustomCellProps & GlobalProps) => {
|
|
34
|
-
const { setExpanded, expanded, expandedControl, inlineRowLoading, hasAnySubRows } = useContext(AdvancedTableContext);
|
|
35
|
+
const { setExpanded, expanded, expandedControl, inlineRowLoading, hasAnySubRows, cascadeCollapse } = useContext(AdvancedTableContext);
|
|
35
36
|
|
|
36
37
|
const handleOnExpand = (row: Row<GenericObject>) => {
|
|
37
38
|
onRowToggleClick && onRowToggleClick(row);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
|
|
40
|
+
const willBeExpanded = !row.getIsExpanded();
|
|
41
|
+
if (willBeExpanded) {
|
|
42
|
+
if (!expandedControl) {
|
|
43
|
+
setExpanded({ ...expanded, [row.id]: true });
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
if (cascadeCollapse) {
|
|
47
|
+
const idsToRemove = new Set([row.id, ...getDescendantRowIds(row)]);
|
|
48
|
+
const nextExpanded = { ...expanded };
|
|
49
|
+
idsToRemove.forEach((id) => delete nextExpanded[id]);
|
|
50
|
+
setExpanded(nextExpanded);
|
|
51
|
+
} else if (!expandedControl) {
|
|
52
|
+
setExpanded({ ...expanded, [row.id]: false });
|
|
53
|
+
}
|
|
41
54
|
}
|
|
42
55
|
};
|
|
43
56
|
|
|
@@ -63,6 +63,7 @@ export const TableHeaderCell = ({
|
|
|
63
63
|
stickyLeftColumn,
|
|
64
64
|
inlineRowLoading,
|
|
65
65
|
isActionBarVisible,
|
|
66
|
+
cascadeCollapse,
|
|
66
67
|
} = useContext(AdvancedTableContext);
|
|
67
68
|
|
|
68
69
|
type justifyTypes = "none" | "center" | "start" | "end" | "between" | "around" | "evenly"
|
|
@@ -182,7 +183,8 @@ const isToggleExpansionEnabled =
|
|
|
182
183
|
table.getRowModel(),
|
|
183
184
|
expanded,
|
|
184
185
|
undefined,
|
|
185
|
-
depth
|
|
186
|
+
depth,
|
|
187
|
+
cascadeCollapse
|
|
186
188
|
)
|
|
187
189
|
setExpanded(updated)
|
|
188
190
|
}
|
|
@@ -12,6 +12,7 @@ interface UseTableActionsProps {
|
|
|
12
12
|
inlineRowLoading?: boolean;
|
|
13
13
|
localPagination?: { pageIndex: number; pageSize: number };
|
|
14
14
|
setLocalPagination?: (pagination: { pageIndex: number; pageSize: number }) => void;
|
|
15
|
+
cascadeCollapse?: boolean;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export function useTableActions({
|
|
@@ -22,7 +23,8 @@ export function useTableActions({
|
|
|
22
23
|
onRowSelectionChange,
|
|
23
24
|
inlineRowLoading = false,
|
|
24
25
|
localPagination,
|
|
25
|
-
setLocalPagination
|
|
26
|
+
setLocalPagination,
|
|
27
|
+
cascadeCollapse = false
|
|
26
28
|
}: UseTableActionsProps) {
|
|
27
29
|
|
|
28
30
|
// State to achieve 1 second delay before fetching more rows
|
|
@@ -32,15 +34,25 @@ export function useTableActions({
|
|
|
32
34
|
// Handle expand/collapse
|
|
33
35
|
const handleExpandOrCollapse = useCallback(async (row: Row<GenericObject>) => {
|
|
34
36
|
if (onToggleExpansionClick) onToggleExpansionClick(row)
|
|
35
|
-
const updatedExpandedState = await updateExpandAndCollapseState(
|
|
36
|
-
table.getRowModel(),
|
|
37
|
-
expanded,
|
|
38
|
-
row?.parentId,
|
|
39
|
-
undefined
|
|
40
|
-
)
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
const anyTopLevelExpanded = table.getRowModel().rows.some((r: Row<GenericObject>) => r.getIsExpanded())
|
|
39
|
+
const isHeaderCollapseAll = row == null && anyTopLevelExpanded
|
|
40
|
+
|
|
41
|
+
if (cascadeCollapse && isHeaderCollapseAll) {
|
|
42
|
+
setExpanded({})
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const updatedExpandedState = await updateExpandAndCollapseState(
|
|
47
|
+
table.getRowModel(),
|
|
48
|
+
expanded,
|
|
49
|
+
row?.parentId,
|
|
50
|
+
undefined,
|
|
51
|
+
cascadeCollapse
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
setExpanded(updatedExpandedState)
|
|
55
|
+
}, [expanded, setExpanded, onToggleExpansionClick, table, cascadeCollapse]);
|
|
44
56
|
|
|
45
57
|
// Handle pagination
|
|
46
58
|
const onPageChange = useCallback((page: number) => {
|
|
@@ -11,11 +11,21 @@ const filterExpandableRows = (expandedState: Record<string, boolean>) => {
|
|
|
11
11
|
return expandedState
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
export const getDescendantRowIds = (row: Row<GenericObject>): string[] => {
|
|
15
|
+
const ids: string[] = []
|
|
16
|
+
for (const sub of row.subRows || []) {
|
|
17
|
+
ids.push(sub.id)
|
|
18
|
+
ids.push(...getDescendantRowIds(sub))
|
|
19
|
+
}
|
|
20
|
+
return ids
|
|
21
|
+
}
|
|
22
|
+
|
|
14
23
|
export const updateExpandAndCollapseState = (
|
|
15
24
|
tableRows: RowModel<GenericObject>,
|
|
16
25
|
expanded: Record<string, boolean>,
|
|
17
26
|
targetParent?: string,
|
|
18
27
|
targetDepth?: number,
|
|
28
|
+
cascadeCollapse?: boolean,
|
|
19
29
|
) => {
|
|
20
30
|
const updateExpandedRows: Record<string, boolean> = {};
|
|
21
31
|
const rows = targetDepth !== undefined ? tableRows.flatRows : tableRows.rows;
|
|
@@ -51,8 +61,22 @@ export const updateExpandAndCollapseState = (
|
|
|
51
61
|
}
|
|
52
62
|
}
|
|
53
63
|
|
|
54
|
-
|
|
64
|
+
const updatedExpandedState = filterExpandableRows({
|
|
55
65
|
...(expanded as ExpandedStateObject),
|
|
56
66
|
...updateExpandedRows,
|
|
57
67
|
});
|
|
68
|
+
|
|
69
|
+
if (cascadeCollapse && !isExpandAction) {
|
|
70
|
+
const idsToRemove = new Set<string>();
|
|
71
|
+
for (const row of rowsToToggle) {
|
|
72
|
+
const shouldUpdate =
|
|
73
|
+
targetDepth === undefined ? true : row.depth === targetDepth;
|
|
74
|
+
if (shouldUpdate) {
|
|
75
|
+
getDescendantRowIds(row).forEach((id) => idsToRemove.add(id));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
idsToRemove.forEach((id) => delete updatedExpandedState[id]);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return updatedExpandedState;
|
|
58
82
|
};
|
|
@@ -31,6 +31,7 @@ type FullscreenControls = {
|
|
|
31
31
|
type AdvancedTableProps = {
|
|
32
32
|
aria?: { [key: string]: string }
|
|
33
33
|
actions?: React.ReactNode[] | React.ReactNode
|
|
34
|
+
cascadeCollapse?: boolean
|
|
34
35
|
children?: React.ReactNode | React.ReactNode[]
|
|
35
36
|
className?: string
|
|
36
37
|
columnDefinitions: GenericObject[]
|
|
@@ -80,6 +81,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
|
80
81
|
const {
|
|
81
82
|
aria = {},
|
|
82
83
|
actions,
|
|
84
|
+
cascadeCollapse = false,
|
|
83
85
|
children,
|
|
84
86
|
className,
|
|
85
87
|
columnDefinitions,
|
|
@@ -173,7 +175,8 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
|
173
175
|
onRowSelectionChange,
|
|
174
176
|
inlineRowLoading,
|
|
175
177
|
localPagination,
|
|
176
|
-
setLocalPagination
|
|
178
|
+
setLocalPagination,
|
|
179
|
+
cascadeCollapse
|
|
177
180
|
});
|
|
178
181
|
|
|
179
182
|
// Set table row count for loading state
|
|
@@ -339,6 +342,7 @@ const AdvancedTable = (props: AdvancedTableProps) => {
|
|
|
339
342
|
>
|
|
340
343
|
{renderFullscreenHeader()}
|
|
341
344
|
<AdvancedTableProvider
|
|
345
|
+
cascadeCollapse={cascadeCollapse}
|
|
342
346
|
columnDefinitions={columnDefinitions}
|
|
343
347
|
columnGroupBorderColor={columnGroupBorderColor}
|
|
344
348
|
columnVisibilityControl={columnVisibilityControl}
|
|
@@ -1015,4 +1015,77 @@ test("columnStyling.headerFontColor works as excpected", () => {
|
|
|
1015
1015
|
|
|
1016
1016
|
const firstEnrollmentHeader = screen.getAllByText("New Enrollments")[0].closest("th");
|
|
1017
1017
|
expect(firstEnrollmentHeader).toHaveStyle({ color: colors.white });
|
|
1018
|
-
});
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
test("cascadeCollapse=false (default) preserves existing behavior when parent is re-expanded", () => {
|
|
1021
|
+
render(
|
|
1022
|
+
<AdvancedTable
|
|
1023
|
+
columnDefinitions={columnDefinitions}
|
|
1024
|
+
data={{ testid: testId }}
|
|
1025
|
+
tableData={MOCK_DATA}
|
|
1026
|
+
/>
|
|
1027
|
+
)
|
|
1028
|
+
|
|
1029
|
+
const kit = screen.getByTestId(testId)
|
|
1030
|
+
const getParentExpandButton = () => kit.querySelector("tbody tr .gray-icon.expand-toggle-icon")
|
|
1031
|
+
const parentButton = getParentExpandButton()
|
|
1032
|
+
expect(parentButton).toBeInTheDocument()
|
|
1033
|
+
parentButton.click()
|
|
1034
|
+
let subRow = kit.querySelector(".pb-bg-row-white.depth-sub-row-1")
|
|
1035
|
+
expect(subRow).toBeInTheDocument()
|
|
1036
|
+
getParentExpandButton().click()
|
|
1037
|
+
subRow = kit.querySelector(".pb-bg-row-white.depth-sub-row-1")
|
|
1038
|
+
expect(subRow).not.toBeInTheDocument()
|
|
1039
|
+
getParentExpandButton().click()
|
|
1040
|
+
subRow = kit.querySelector(".pb-bg-row-white.depth-sub-row-1")
|
|
1041
|
+
expect(subRow).toBeInTheDocument()
|
|
1042
|
+
})
|
|
1043
|
+
|
|
1044
|
+
test("cascadeCollapse=true collapses all descendants when parent is collapsed", () => {
|
|
1045
|
+
render(
|
|
1046
|
+
<AdvancedTable
|
|
1047
|
+
cascadeCollapse
|
|
1048
|
+
columnDefinitions={columnDefinitions}
|
|
1049
|
+
data={{ testid: testId }}
|
|
1050
|
+
tableData={MOCK_DATA}
|
|
1051
|
+
/>
|
|
1052
|
+
)
|
|
1053
|
+
|
|
1054
|
+
const kit = screen.getByTestId(testId)
|
|
1055
|
+
const getParentExpandButton = () => kit.querySelector("tbody tr .gray-icon.expand-toggle-icon")
|
|
1056
|
+
const parentButton = getParentExpandButton()
|
|
1057
|
+
expect(parentButton).toBeInTheDocument()
|
|
1058
|
+
parentButton.click()
|
|
1059
|
+
expect(kit.querySelector(".depth-sub-row-1")).toBeInTheDocument()
|
|
1060
|
+
getParentExpandButton().click()
|
|
1061
|
+
expect(kit.querySelector(".depth-sub-row-1")).not.toBeInTheDocument()
|
|
1062
|
+
getParentExpandButton().click()
|
|
1063
|
+
expect(kit.querySelector(".depth-sub-row-1")).toBeInTheDocument()
|
|
1064
|
+
})
|
|
1065
|
+
|
|
1066
|
+
test("cascadeCollapse=true with header toggle all: collapse all then expand all shows only direct children", async () => {
|
|
1067
|
+
render(
|
|
1068
|
+
<AdvancedTable
|
|
1069
|
+
cascadeCollapse
|
|
1070
|
+
columnDefinitions={columnDefinitions}
|
|
1071
|
+
data={{ testid: testId }}
|
|
1072
|
+
tableData={MOCK_DATA}
|
|
1073
|
+
/>
|
|
1074
|
+
)
|
|
1075
|
+
|
|
1076
|
+
const kit = screen.getByTestId(testId)
|
|
1077
|
+
const toggleAllButton = kit.querySelector(".gray-icon.toggle-all-icon")
|
|
1078
|
+
expect(toggleAllButton).toBeInTheDocument()
|
|
1079
|
+
toggleAllButton.click()
|
|
1080
|
+
await waitFor(() => {
|
|
1081
|
+
expect(kit.querySelector(".depth-sub-row-1")).toBeInTheDocument()
|
|
1082
|
+
})
|
|
1083
|
+
toggleAllButton.click()
|
|
1084
|
+
await waitFor(() => {
|
|
1085
|
+
expect(kit.querySelector(".depth-sub-row-1")).not.toBeInTheDocument()
|
|
1086
|
+
})
|
|
1087
|
+
toggleAllButton.click()
|
|
1088
|
+
await waitFor(() => {
|
|
1089
|
+
expect(kit.querySelector(".depth-sub-row-1")).toBeInTheDocument()
|
|
1090
|
+
})
|
|
1091
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
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 AdvancedTableCascadeCollapse = (props) => {
|
|
6
|
+
const columnDefinitions = [
|
|
7
|
+
{
|
|
8
|
+
accessor: "year",
|
|
9
|
+
label: "Year",
|
|
10
|
+
cellAccessors: ["quarter", "month", "day"],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
accessor: "newEnrollments",
|
|
14
|
+
label: "New Enrollments",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
accessor: "scheduledMeetings",
|
|
18
|
+
label: "Scheduled Meetings",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
accessor: "attendanceRate",
|
|
22
|
+
label: "Attendance Rate",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
accessor: "completedClasses",
|
|
26
|
+
label: "Completed Classes",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
accessor: "classCompletionRate",
|
|
30
|
+
label: "Class Completion Rate",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
accessor: "graduatedStudents",
|
|
34
|
+
label: "Graduated Students",
|
|
35
|
+
},
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div>
|
|
40
|
+
<AdvancedTable
|
|
41
|
+
cascadeCollapse
|
|
42
|
+
columnDefinitions={columnDefinitions}
|
|
43
|
+
tableData={MOCK_DATA}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default AdvancedTableCascadeCollapse
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
`cascadeCollapse` is an optional prop that is set to 'false' by default. If set to 'true', collapsing any parent row itself or by using the toggle exapansion buttons in any header or subheader row also collapses all descendants and clears their expansion state. Re-expanding then shows only direct children until the user expands deeper levels again.
|
|
@@ -42,6 +42,7 @@ examples:
|
|
|
42
42
|
- advanced_table_expanded_control: Expanded Control
|
|
43
43
|
- advanced_table_expand_by_depth: Expand by Depth
|
|
44
44
|
- advanced_table_subrow_headers: SubRow Headers
|
|
45
|
+
- advanced_table_cascade_collapse: Cascade Collapse
|
|
45
46
|
- advanced_table_collapsible_trail: Collapsible Trail
|
|
46
47
|
- advanced_table_table_options: Table Options
|
|
47
48
|
- advanced_table_table_props: Table Props
|
|
@@ -48,4 +48,5 @@ export { default as AdvancedTablePaddingControl } from './_advanced_table_paddin
|
|
|
48
48
|
export { default as AdvancedTablePaddingControlPerRow } from './_advanced_table_padding_control_per_row.jsx'
|
|
49
49
|
export { default as AdvancedTableColumnStylingBackground } from './_advanced_table_column_styling_background.jsx'
|
|
50
50
|
export { default as AdvancedTableColumnStylingBackgroundMulti } from './_advanced_table_column_styling_background_multi.jsx'
|
|
51
|
-
export { default as AdvancedTableColumnStylingBackgroundCustom } from './_advanced_table_column_styling_background_custom.jsx'
|
|
51
|
+
export { default as AdvancedTableColumnStylingBackgroundCustom } from './_advanced_table_column_styling_background_custom.jsx'
|
|
52
|
+
export { default as AdvancedTableCascadeCollapse } from './_advanced_table_cascade_collapse.jsx'
|
|
@@ -115,9 +115,10 @@ $pb_button_sizes: (
|
|
|
115
115
|
|
|
116
116
|
// Icon-only button (icon prop set, no text) - square with equal padding
|
|
117
117
|
// Rails: uses .pb_button_icon_only class
|
|
118
|
-
// React:
|
|
118
|
+
// React: when pb_button_content is empty (no text). Do not match when content has
|
|
119
|
+
// text + icon (e.g. "Exit Fullscreen" + FA icon) which can include empty spans.
|
|
119
120
|
&.pb_button_icon_only,
|
|
120
|
-
&:has(.pb_button_content
|
|
121
|
+
&:has(.pb_button_content:empty) {
|
|
121
122
|
aspect-ratio: 1;
|
|
122
123
|
min-width: auto;
|
|
123
124
|
width: auto;
|
|
@@ -62,16 +62,16 @@ $transition: $transition_cubic;
|
|
|
62
62
|
left: $offscreen;
|
|
63
63
|
|
|
64
64
|
&:focus ~ .pb_checkbox_checkmark {
|
|
65
|
-
box-shadow: 0px 0px 0px 2px $white, 0px 0px 0px 4px $
|
|
65
|
+
box-shadow: 0px 0px 0px 2px $white, 0px 0px 0px 4px $input_border_state;
|
|
66
66
|
}
|
|
67
67
|
&:checked ~ .pb_checkbox_checkmark,
|
|
68
68
|
& ~ .pb_checkbox_indeterminate {
|
|
69
69
|
background-color: $primary_action;
|
|
70
|
-
border-color: $
|
|
70
|
+
border-color: $input_border_state;
|
|
71
71
|
|
|
72
72
|
&:hover {
|
|
73
73
|
background-color: $primary_action;
|
|
74
|
-
border-color: $
|
|
74
|
+
border-color: $input_border_state;
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
&:checked ~ .pb_checkbox_checkmark,
|
|
@@ -112,7 +112,7 @@ $transition: $transition_cubic;
|
|
|
112
112
|
&.dark {
|
|
113
113
|
input {
|
|
114
114
|
&:focus ~ .pb_checkbox_checkmark {
|
|
115
|
-
box-shadow: 0px 0px 0px 2px $bg_dark_card, 0px 0px 0px 4px $
|
|
115
|
+
box-shadow: 0px 0px 0px 2px $bg_dark_card, 0px 0px 0px 4px $input_border_state_dark;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
&:disabled ~ .pb_checkbox_checkmark {
|
|
@@ -154,9 +154,9 @@ $transition: $transition_cubic;
|
|
|
154
154
|
input {
|
|
155
155
|
&:checked ~ .pb_checkbox_checkmark,
|
|
156
156
|
& ~ .pb_checkbox_indeterminate {
|
|
157
|
-
border-color: $
|
|
157
|
+
border-color: $input_border_state_dark;
|
|
158
158
|
&:hover {
|
|
159
|
-
border-color: $
|
|
159
|
+
border-color: $input_border_state_dark;
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
}
|
|
@@ -11,9 +11,11 @@ export default class PbCollapsible extends PbEnhancedElement {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
connect() {
|
|
14
|
-
this.
|
|
14
|
+
this.clickHandler = () => {
|
|
15
15
|
this.toggleElement(this.target)
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
|
+
this.element.addEventListener('click', this.clickHandler)
|
|
18
|
+
|
|
17
19
|
// Check the initial state of the collapsible content and set the arrow accordingly
|
|
18
20
|
if (this.target.classList.contains('is-visible')) {
|
|
19
21
|
this.displayUpArrow()
|
|
@@ -21,9 +23,19 @@ export default class PbCollapsible extends PbEnhancedElement {
|
|
|
21
23
|
this.displayDownArrow()
|
|
22
24
|
}
|
|
23
25
|
// Listen for a custom event to toggle the collapsible
|
|
24
|
-
|
|
26
|
+
this.customEventHandler = () => {
|
|
25
27
|
this.toggleElement(this.target)
|
|
26
|
-
}
|
|
28
|
+
}
|
|
29
|
+
document.addEventListener(`${this.target.id}`, this.customEventHandler)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
disconnect() {
|
|
33
|
+
if (this.clickHandler) {
|
|
34
|
+
this.element.removeEventListener('click', this.clickHandler)
|
|
35
|
+
}
|
|
36
|
+
if (this.customEventHandler && this.target) {
|
|
37
|
+
document.removeEventListener(`${this.target.id}`, this.customEventHandler)
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
get target() {
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
div.cal_icon_wrapper,
|
|
29
29
|
input.date_picker_input {
|
|
30
30
|
@include transition_default;
|
|
31
|
-
border-color: $
|
|
31
|
+
border-color: $status_border_primary;
|
|
32
32
|
}
|
|
33
33
|
.add-on-card {
|
|
34
|
-
border-color: $
|
|
34
|
+
border-color: $status_border_primary;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -221,11 +221,14 @@ const DatePicker = (props: DatePickerProps): React.ReactElement => {
|
|
|
221
221
|
{!hideLabel && (
|
|
222
222
|
<label htmlFor={pickerId}>
|
|
223
223
|
{requiredIndicator ? (
|
|
224
|
-
<Caption className="pb_date_picker_kit_label"
|
|
224
|
+
<Caption className="pb_date_picker_kit_label"
|
|
225
|
+
color="lighter"
|
|
226
|
+
>
|
|
225
227
|
{label} <span style={{ color: `${colors.error}` }}>*</span>
|
|
226
228
|
</Caption>
|
|
227
229
|
) : (
|
|
228
230
|
<Caption className="pb_date_picker_kit_label"
|
|
231
|
+
color="lighter"
|
|
229
232
|
text={label}
|
|
230
233
|
/>
|
|
231
234
|
)}
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
<% if !object.hide_label && object.label %>
|
|
8
8
|
<label for="<%= object.picker_id %>">
|
|
9
9
|
<% if object.required_indicator %>
|
|
10
|
-
<%= pb_rails("caption", props: { dark: object.dark, classname: "pb_date_picker_kit_label" }) do %>
|
|
10
|
+
<%= pb_rails("caption", props: { dark: object.dark, classname: "pb_date_picker_kit_label", color: "lighter" }) do %>
|
|
11
11
|
<%= object.label %><span style="color: #DA0014;"> *</span>
|
|
12
12
|
<% end %>
|
|
13
13
|
<% else %>
|
|
14
|
-
<%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_date_picker_kit_label" }) %>
|
|
14
|
+
<%= pb_rails("caption", props: { text: object.label, dark: object.dark, classname: "pb_date_picker_kit_label", color: "lighter" }) %>
|
|
15
15
|
<% end %>
|
|
16
16
|
</label>
|
|
17
17
|
<% end %>
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
// Base styles
|
|
15
15
|
a {
|
|
16
|
-
color: $
|
|
16
|
+
color: $text_link;
|
|
17
17
|
&:hover {
|
|
18
18
|
cursor: pointer;
|
|
19
19
|
color: $text_default_color;
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
.pb_detail_kit_color_link {
|
|
47
|
-
@include pb_detail($
|
|
47
|
+
@include pb_detail($text_link);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
.pb_detail_kit_color_error {
|
|
@@ -8,8 +8,16 @@ export default class PbDialog extends PbEnhancedElement {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
connect() {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
// Store references to this instance's specific elements
|
|
12
|
+
this.dialogElement = this.element.querySelector(".pb_dialog_rails")
|
|
13
|
+
this.dialogId = this.dialogElement?.id
|
|
14
|
+
this.managedTriggers = new Set()
|
|
15
|
+
|
|
16
|
+
this.domContentLoadedHandler = () => this.setupDialog()
|
|
17
|
+
this.turboFrameLoadHandler = () => this.setupDialog()
|
|
18
|
+
|
|
19
|
+
window.addEventListener("DOMContentLoaded", this.domContentLoadedHandler)
|
|
20
|
+
window.addEventListener("turbo:frame-load", this.turboFrameLoadHandler)
|
|
13
21
|
|
|
14
22
|
// Code for custom_event_type setup (can take multiple events in a string separated by commas)
|
|
15
23
|
const customEventTypeString = this.element.dataset.customEventType
|
|
@@ -24,11 +32,38 @@ export default class PbDialog extends PbEnhancedElement {
|
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
disconnect() {
|
|
35
|
+
// Clean up window event listeners
|
|
36
|
+
if (this.domContentLoadedHandler) {
|
|
37
|
+
window.removeEventListener("DOMContentLoaded", this.domContentLoadedHandler)
|
|
38
|
+
}
|
|
39
|
+
if (this.turboFrameLoadHandler) {
|
|
40
|
+
window.removeEventListener("turbo:frame-load", this.turboFrameLoadHandler)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Clean up custom event listeners
|
|
27
44
|
if (this.customEventTypes && Array.isArray(this.customEventTypes)) {
|
|
28
45
|
this.customEventTypes.forEach(eventType => {
|
|
29
46
|
window.removeEventListener(eventType, this.handleCustomEvent)
|
|
30
47
|
})
|
|
31
48
|
}
|
|
49
|
+
|
|
50
|
+
// Clean up only the triggers that this instance managed
|
|
51
|
+
this.managedTriggers.forEach((trigger) => {
|
|
52
|
+
if (trigger._openDialogClickHandler) {
|
|
53
|
+
trigger.removeEventListener("click", trigger._openDialogClickHandler)
|
|
54
|
+
delete trigger._openDialogClickHandler
|
|
55
|
+
}
|
|
56
|
+
if (trigger._closeDialogClickHandler) {
|
|
57
|
+
trigger.removeEventListener("click", trigger._closeDialogClickHandler)
|
|
58
|
+
delete trigger._closeDialogClickHandler
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Clean up this dialog's outside click handler
|
|
63
|
+
if (this.dialogElement && this.dialogElement._outsideClickHandler) {
|
|
64
|
+
this.dialogElement.removeEventListener("mousedown", this.dialogElement._outsideClickHandler)
|
|
65
|
+
delete this.dialogElement._outsideClickHandler
|
|
66
|
+
}
|
|
32
67
|
}
|
|
33
68
|
|
|
34
69
|
handleCustomEvent = (event) => {
|
|
@@ -88,9 +123,12 @@ export default class PbDialog extends PbEnhancedElement {
|
|
|
88
123
|
}
|
|
89
124
|
|
|
90
125
|
setupDialog() {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
126
|
+
// Only set up triggers and dialogs that belong to this instance
|
|
127
|
+
if (!this.dialogId) return
|
|
128
|
+
|
|
129
|
+
const openTrigger = document.querySelectorAll(`[data-open-dialog="${this.dialogId}"]`);
|
|
130
|
+
const closeTrigger = document.querySelectorAll(`[data-close-dialog="${this.dialogId}"]`);
|
|
131
|
+
const dialogs = this.dialogElement ? [this.dialogElement] : []
|
|
94
132
|
|
|
95
133
|
const loadingButton = document.querySelector('[data-disable-with="Loading"]');
|
|
96
134
|
if (loadingButton && !loadingButton.dataset.listenerAttached) {
|
|
@@ -126,6 +164,7 @@ export default class PbDialog extends PbEnhancedElement {
|
|
|
126
164
|
};
|
|
127
165
|
|
|
128
166
|
open.addEventListener("click", open._openDialogClickHandler)
|
|
167
|
+
this.managedTriggers.add(open)
|
|
129
168
|
});
|
|
130
169
|
|
|
131
170
|
closeTrigger.forEach((close) => {
|
|
@@ -139,6 +178,7 @@ export default class PbDialog extends PbEnhancedElement {
|
|
|
139
178
|
};
|
|
140
179
|
|
|
141
180
|
close.addEventListener("click", close._closeDialogClickHandler)
|
|
181
|
+
this.managedTriggers.add(close)
|
|
142
182
|
});
|
|
143
183
|
|
|
144
184
|
// Close dialog box on outside click
|