playbook_ui 16.3.0.pre.alpha.PLAY2806emailcampaignmlsfix14704 → 16.3.0.pre.alpha.PLAY2810toastaddmargin14797
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_button/_button_mixins.scss +6 -1
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_default.html.erb +18 -9
- data/app/pb_kits/playbook/pb_dialog/docs/_dialog_default.jsx +24 -5
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +3 -0
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_closing_options_rails.html.erb +16 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_closing_options_rails.md +1 -0
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +4 -0
- data/app/pb_kits/playbook/pb_dropdown/index.js +27 -9
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +19 -14
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.scss +4 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/_fixed_confirmation_toast.tsx +3 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin.html.erb +46 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin.jsx +42 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin_rails.md +1 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/_fixed_confirmation_toast_nav_margin_react.md +1 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/docs/index.js +2 -1
- data/app/pb_kits/playbook/pb_fixed_confirmation_toast/fixed_confirmation_toast.rb +7 -1
- data/app/pb_kits/playbook/pb_multi_level_select/_helper_functions.tsx +1 -22
- data/app/pb_kits/playbook/pb_multi_level_select/_multi_level_select.tsx +36 -100
- data/app/pb_kits/playbook/pb_rich_text_editor/rich_text_editor.html.erb +1 -0
- data/app/pb_kits/playbook/pb_table/_table.tsx +24 -21
- data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props.jsx +152 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props.md +17 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props_rails.html.erb +121 -0
- data/app/pb_kits/playbook/pb_table/docs/_table_with_filter_with_card_title_props_rails.md +17 -0
- data/app/pb_kits/playbook/pb_table/docs/example.yml +2 -0
- data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
- data/app/pb_kits/playbook/pb_table/table.html.erb +12 -11
- data/app/pb_kits/playbook/pb_table/table.rb +4 -0
- data/app/pb_kits/playbook/pb_table/table.test.js +33 -0
- data/app/pb_kits/playbook/pb_textarea/_textarea.scss +4 -1
- data/app/pb_kits/playbook/pb_typeahead/_typeahead.tsx +105 -3
- data/dist/chunks/_typeahead-DdGKR1rQ.js +1 -0
- data/dist/chunks/componentRegistry-DRSp5D_e.js +1 -0
- data/dist/chunks/vendor.js +3 -3
- data/dist/menu.yml +2 -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/pb_forms_helper.rb +3 -0
- data/lib/playbook/version.rb +1 -1
- metadata +16 -4
- data/dist/chunks/_typeahead-DTLY_FOh.js +0 -1
- data/dist/chunks/componentRegistry-DzmmLR2x.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: 92ffb892cecf1e7e9873fa6950e907f9829962c52f8fca4bb3e5a35c5a4e40d8
|
|
4
|
+
data.tar.gz: c2e2c9822a171abe38ed7007c503ae94a06b21e110e4f4a2caf35a08c03a8506
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: abe894c96f125a3501d169f44b75bebcc34d6abc8061f7f7acf16c18ecf116617c4a8274d26866a7b34fff03b13d3c35b2863c313c0b44e31a0bac360fa53ab6
|
|
7
|
+
data.tar.gz: 7047570ca08af14817e4ae7229eb47dc281e53fbe7eafb10a526d2ec5e9df4b9a2a397b40f367742b1d77869411dce8c151751711ff7212a6cb38d3f3f476977
|
|
@@ -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'
|
|
@@ -57,7 +57,7 @@ $pb_button_border_width: 0px;
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
.loading-icon {
|
|
60
|
-
position:
|
|
60
|
+
position: static;
|
|
61
61
|
display: none;
|
|
62
62
|
}
|
|
63
63
|
.pb_button_content {
|
|
@@ -158,10 +158,15 @@ $pb_button_border_width: 0px;
|
|
|
158
158
|
// Loading =====================
|
|
159
159
|
@mixin pb_button_loading($loading: false) {
|
|
160
160
|
@if $loading == true {
|
|
161
|
+
display: inline-grid;
|
|
162
|
+
place-items: center;
|
|
163
|
+
|
|
161
164
|
.loading-icon {
|
|
165
|
+
grid-area: 1 / 1;
|
|
162
166
|
display: block;
|
|
163
167
|
}
|
|
164
168
|
.pb_button_content {
|
|
169
|
+
grid-area: 1 / 1;
|
|
165
170
|
visibility: hidden;
|
|
166
171
|
}
|
|
167
172
|
}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
<%= pb_rails("button", props: { text: "Open Dialog", data: {"open-dialog": "dialog-1"} }) %>
|
|
2
2
|
|
|
3
|
-
<%= pb_rails("dialog", props: {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}) %>
|
|
3
|
+
<%= pb_rails("dialog", props: {
|
|
4
|
+
id:"dialog-1",
|
|
5
|
+
size: "md",
|
|
6
|
+
title: "Header Title is the Title Prop"
|
|
7
|
+
}) do %>
|
|
8
|
+
<%= pb_rails("dialog/dialog_body") do %>
|
|
9
|
+
<%= pb_rails("button", props: { aria: { label: "Loading" }, loading: true, margin_right: "lg", text: "Button Primary" }) %>
|
|
10
|
+
<div style="height: 800px; background-color: lightgray;"></div>
|
|
11
|
+
<%= pb_rails("button", props: { loading: true, text: "Loading..." }) %>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<%= pb_rails("dialog/dialog_footer") do %>
|
|
15
|
+
<%= pb_rails("flex", props: { spacing: "between", padding_x: "md", padding_bottom: "md", padding: "sm" }) do %>
|
|
16
|
+
<%= pb_rails("button", props: { loading: true, text: "Send My Issue" }) %>
|
|
17
|
+
<%= pb_rails("button", props: { text: "Back", variant: "link", data: {"close-dialog": "dialog-1"} }) %>
|
|
18
|
+
<% end %>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% end %>
|
|
@@ -12,16 +12,35 @@ const DialogDefault = () => {
|
|
|
12
12
|
<>
|
|
13
13
|
<Button onClick={open}>{'Open Dialog'}</Button>
|
|
14
14
|
<Dialog
|
|
15
|
-
cancelButton="Cancel Button"
|
|
16
|
-
confirmButton="Okay"
|
|
17
15
|
onCancel={close}
|
|
18
16
|
onClose={close}
|
|
19
17
|
onConfirm={close}
|
|
20
18
|
opened={isOpen}
|
|
21
|
-
size="
|
|
22
|
-
text="Hello Body Text, Nice to meet ya."
|
|
19
|
+
size="md"
|
|
23
20
|
title="Header Title is the Title Prop"
|
|
24
|
-
|
|
21
|
+
>
|
|
22
|
+
<Dialog.Body>
|
|
23
|
+
<Button
|
|
24
|
+
aria={{ label: 'Loading' }}
|
|
25
|
+
loading
|
|
26
|
+
text="Button Primary"
|
|
27
|
+
/>
|
|
28
|
+
<div style={{height: '800px', backgroundColor: 'lightgray'}} />
|
|
29
|
+
<Button
|
|
30
|
+
loading
|
|
31
|
+
text="Loading..."
|
|
32
|
+
/>
|
|
33
|
+
</Dialog.Body>
|
|
34
|
+
<Dialog.Footer>
|
|
35
|
+
<Button
|
|
36
|
+
loading
|
|
37
|
+
text="Send My Issue"
|
|
38
|
+
/>
|
|
39
|
+
<Button variant="link">
|
|
40
|
+
{"Back"}
|
|
41
|
+
</Button>
|
|
42
|
+
</Dialog.Footer>
|
|
43
|
+
</Dialog>
|
|
25
44
|
</>
|
|
26
45
|
)
|
|
27
46
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<%
|
|
2
|
+
options = [
|
|
3
|
+
{ label: "United States", value: "unitedStates", id: "us" },
|
|
4
|
+
{ label: "Canada", value: "canada", id: "ca" },
|
|
5
|
+
{ label: "Pakistan", value: "pakistan", id: "pk" },
|
|
6
|
+
]
|
|
7
|
+
%>
|
|
8
|
+
|
|
9
|
+
<%= pb_rails("caption", props: { margin_bottom: "xs", text: "Any" }) %>
|
|
10
|
+
<%= pb_rails("dropdown", props: { options: options, close_on_click: "any", margin_bottom: "md" }) %>
|
|
11
|
+
|
|
12
|
+
<%= pb_rails("caption", props: { margin_bottom: "xs", text: "Outside" }) %>
|
|
13
|
+
<%= pb_rails("dropdown", props: { options: options, close_on_click: "outside", margin_bottom: "md" }) %>
|
|
14
|
+
|
|
15
|
+
<%= pb_rails("caption", props: { margin_bottom: "xs", text: "Inside" }) %>
|
|
16
|
+
<%= pb_rails("dropdown", props: { options: options, close_on_click: "inside" }) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
The `close_on_click` prop allows you to control when the Dropdown closes in response to click interactions. The value `any` reflects the default behavior, where the dropdown will close after any click. Set it to `outside` to ensure interactive elements as dropdown options are able to be interacted with or modified. Set it to `inside` for a dropdown that only closes when the input or dropdown menu is clicked.
|
|
@@ -25,6 +25,7 @@ examples:
|
|
|
25
25
|
- dropdown_separators_hidden: Separators Hidden
|
|
26
26
|
- dropdown_with_clearable: Clearable
|
|
27
27
|
- dropdown_with_constrain_height_rails: Constrain Height
|
|
28
|
+
- dropdown_closing_options_rails: Closing Options
|
|
28
29
|
- dropdown_quickpick_rails: Quick Pick Variant
|
|
29
30
|
- dropdown_quickpick_range_end_rails: Quick Pick Variant (Range Ends Today)
|
|
30
31
|
- dropdown_quickpick_default_dates: Quick Pick Variant (Default Dates)
|
|
@@ -39,6 +39,9 @@ module Playbook
|
|
|
39
39
|
default: ""
|
|
40
40
|
prop :clearable, type: Playbook::Props::Boolean,
|
|
41
41
|
default: true
|
|
42
|
+
prop :close_on_click, type: Playbook::Props::Enum,
|
|
43
|
+
values: %w[outside inside any],
|
|
44
|
+
default: "any"
|
|
42
45
|
prop :start_date_id, type: Playbook::Props::String,
|
|
43
46
|
default: "start_date_id"
|
|
44
47
|
prop :start_date_name, type: Playbook::Props::String,
|
|
@@ -59,6 +62,7 @@ module Playbook
|
|
|
59
62
|
pb_dropdown_multi_select: multi_select,
|
|
60
63
|
pb_dropdown_variant: variant,
|
|
61
64
|
pb_dropdown_clearable: clearable,
|
|
65
|
+
pb_dropdown_close_on_click: close_on_click,
|
|
62
66
|
form_pill_props: form_pill_props.to_json,
|
|
63
67
|
start_date_id: variant == "quickpick" ? start_date_id : nil,
|
|
64
68
|
end_date_id: variant == "quickpick" ? end_date_id : nil,
|
|
@@ -35,6 +35,7 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
35
35
|
|
|
36
36
|
this.keyboardHandler = new PbDropdownKeyboard(this);
|
|
37
37
|
this.isMultiSelect = this.element.dataset.pbDropdownMultiSelect === "true";
|
|
38
|
+
this.closeOnClick = this.element.dataset.pbDropdownCloseOnClick || "any";
|
|
38
39
|
this.formPillProps = this.element.dataset.formPillProps
|
|
39
40
|
? JSON.parse(this.element.dataset.formPillProps)
|
|
40
41
|
: {};
|
|
@@ -140,6 +141,12 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
140
141
|
trigger.focus();
|
|
141
142
|
}
|
|
142
143
|
}
|
|
144
|
+
if (
|
|
145
|
+
this.closeOnClick === "outside" &&
|
|
146
|
+
this.target?.contains(e.target)
|
|
147
|
+
) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
143
150
|
this.toggleElement(this.target);
|
|
144
151
|
}
|
|
145
152
|
customTrigger.addEventListener("click", this.customTriggerClickHandler);
|
|
@@ -305,7 +312,13 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
305
312
|
|
|
306
313
|
handleDocumentClick(event) {
|
|
307
314
|
if (event.target.closest(SEARCH_BAR_SELECTOR)) return;
|
|
308
|
-
|
|
315
|
+
const shouldCloseOnOutsideClick =
|
|
316
|
+
this.closeOnClick === "outside" || this.closeOnClick === "any";
|
|
317
|
+
if (
|
|
318
|
+
shouldCloseOnOutsideClick &&
|
|
319
|
+
this.isClickOutside(event) &&
|
|
320
|
+
this.target.classList.contains("open")
|
|
321
|
+
) {
|
|
309
322
|
this.hideElement(this.target);
|
|
310
323
|
this.updateArrowDisplay(false);
|
|
311
324
|
}
|
|
@@ -316,11 +329,12 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
316
329
|
if (label && this.element.contains(label)) return false;
|
|
317
330
|
const customTrigger = this.element.querySelector(CUSTOM_DISPLAY_SELECTOR);
|
|
318
331
|
if (customTrigger) {
|
|
319
|
-
|
|
332
|
+
const clickInTrigger = customTrigger.contains(event.target);
|
|
333
|
+
const clickInContainer = this.target?.contains(event.target);
|
|
334
|
+
return !clickInTrigger && !clickInContainer;
|
|
320
335
|
} else {
|
|
321
336
|
const triggerElement = this.element.querySelector(TRIGGER_SELECTOR);
|
|
322
|
-
const containerElement =
|
|
323
|
-
this.element.parentNode.querySelector(CONTAINER_SELECTOR);
|
|
337
|
+
const containerElement = this.element.querySelector(CONTAINER_SELECTOR);
|
|
324
338
|
|
|
325
339
|
const isOutsideTrigger = triggerElement
|
|
326
340
|
? !triggerElement.contains(event.target)
|
|
@@ -459,11 +473,15 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
459
473
|
}
|
|
460
474
|
|
|
461
475
|
const customTrigger = this.element.querySelector(CUSTOM_DISPLAY_SELECTOR);
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
476
|
+
const shouldCloseOnOptionSelect =
|
|
477
|
+
this.closeOnClick === "any" || this.closeOnClick === "inside";
|
|
478
|
+
if (
|
|
479
|
+
customTrigger &&
|
|
480
|
+
shouldCloseOnOptionSelect &&
|
|
481
|
+
this.target.classList.contains("open")
|
|
482
|
+
) {
|
|
483
|
+
this.hideElement(this.target);
|
|
484
|
+
this.updateArrowDisplay(false);
|
|
467
485
|
}
|
|
468
486
|
|
|
469
487
|
const options = this.element.querySelectorAll(OPTION_SELECTOR);
|
|
@@ -44,6 +44,7 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
44
44
|
|
|
45
45
|
const {
|
|
46
46
|
autocomplete,
|
|
47
|
+
blankSelection,
|
|
47
48
|
clearable,
|
|
48
49
|
error,
|
|
49
50
|
errorId,
|
|
@@ -57,6 +58,7 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
57
58
|
isInputFocused,
|
|
58
59
|
label: contextLabel,
|
|
59
60
|
multiSelect,
|
|
61
|
+
optionsWithBlankSelection,
|
|
60
62
|
selected,
|
|
61
63
|
selectId,
|
|
62
64
|
setIsInputFocused,
|
|
@@ -240,20 +242,22 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
240
242
|
onClick: (e: Event) => {e.stopPropagation();handleWrapperClick()}
|
|
241
243
|
}}
|
|
242
244
|
key={`${isDropDownClosed ? "chevron-down" : "chevron-up"}`}
|
|
243
|
-
>
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
245
|
+
>
|
|
246
|
+
{(!blankSelection || selected?.value !== optionsWithBlankSelection?.[0]?.value) && (
|
|
247
|
+
<>
|
|
248
|
+
{clearable !== false && selectedArray.length > 0 && (
|
|
249
|
+
<div onClick={(e)=>{e.stopPropagation();handleBackspace()}}>
|
|
250
|
+
<Icon
|
|
251
|
+
cursor="pointer"
|
|
252
|
+
dark={dark}
|
|
253
|
+
icon="times"
|
|
254
|
+
paddingRight="xs"
|
|
255
|
+
size="sm"
|
|
256
|
+
/>
|
|
257
|
+
</div>
|
|
258
|
+
)}
|
|
259
|
+
</>
|
|
260
|
+
)}
|
|
257
261
|
<Icon
|
|
258
262
|
cursor="pointer"
|
|
259
263
|
dark={dark}
|
|
@@ -261,6 +265,7 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
261
265
|
size="sm"
|
|
262
266
|
/>
|
|
263
267
|
</Body>
|
|
268
|
+
|
|
264
269
|
</FlexItem>
|
|
265
270
|
</Flex>
|
|
266
271
|
</>
|