@okta/odyssey-react-mui 1.14.3 → 1.14.4
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.
- package/CHANGELOG.md +4 -0
- package/dist/DataTable/DataTable.js +330 -0
- package/dist/DataTable/DataTable.js.map +1 -0
- package/dist/DataTable/DataTableRowActions.js +89 -0
- package/dist/DataTable/DataTableRowActions.js.map +1 -0
- package/dist/DataTable/DataTableSettings.js +72 -0
- package/dist/DataTable/DataTableSettings.js.map +1 -0
- package/dist/DataTable/constants.js +14 -0
- package/dist/DataTable/constants.js.map +1 -0
- package/dist/DataTable/index.js +14 -0
- package/dist/DataTable/index.js.map +1 -0
- package/dist/DataTable/reorderDataRowsLocally.js +26 -0
- package/dist/DataTable/reorderDataRowsLocally.js.map +1 -0
- package/dist/DataTable/useRowReordering.js +179 -0
- package/dist/DataTable/useRowReordering.js.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/labs/DataFilters.js +42 -14
- package/dist/labs/DataFilters.js.map +1 -1
- package/dist/labs/DataTable.js +16 -11
- package/dist/labs/DataTable.js.map +1 -1
- package/dist/labs/index.js +0 -1
- package/dist/labs/index.js.map +1 -1
- package/dist/properties/ts/odyssey-react-mui.js +18 -1
- package/dist/properties/ts/odyssey-react-mui.js.map +1 -1
- package/dist/src/DataTable/DataTable.d.ts +133 -0
- package/dist/src/DataTable/DataTable.d.ts.map +1 -0
- package/dist/src/DataTable/DataTableRowActions.d.ts +30 -0
- package/dist/src/DataTable/DataTableRowActions.d.ts.map +1 -0
- package/dist/src/DataTable/DataTableSettings.d.ts +27 -0
- package/dist/src/DataTable/DataTableSettings.d.ts.map +1 -0
- package/dist/src/DataTable/constants.d.ts +13 -0
- package/dist/src/DataTable/constants.d.ts.map +1 -0
- package/dist/src/DataTable/index.d.ts +15 -0
- package/dist/src/DataTable/index.d.ts.map +1 -0
- package/dist/src/DataTable/reorderDataRowsLocally.d.ts +26 -0
- package/dist/src/DataTable/reorderDataRowsLocally.d.ts.map +1 -0
- package/dist/src/DataTable/useRowReordering.d.ts +56 -0
- package/dist/src/DataTable/useRowReordering.d.ts.map +1 -0
- package/dist/src/OdysseyTranslationProvider.d.ts +1 -1
- package/dist/src/OdysseyTranslationProvider.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/labs/DataFilters.d.ts.map +1 -1
- package/dist/src/labs/DataTable.d.ts +2 -2
- package/dist/src/labs/DataTable.d.ts.map +1 -1
- package/dist/src/labs/index.d.ts +0 -1
- package/dist/src/labs/index.d.ts.map +1 -1
- package/dist/src/properties/ts/odyssey-react-mui.d.ts +18 -1
- package/dist/src/properties/ts/odyssey-react-mui.d.ts.map +1 -1
- package/dist/src/theme/components.d.ts.map +1 -1
- package/dist/theme/components.js +37 -18
- package/dist/theme/components.js.map +1 -1
- package/dist/tsconfig.production.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/DataTable/DataTable.tsx +538 -0
- package/src/DataTable/DataTableRowActions.tsx +124 -0
- package/src/DataTable/DataTableSettings.tsx +109 -0
- package/src/DataTable/constants.ts +13 -0
- package/src/DataTable/index.tsx +22 -0
- package/src/DataTable/reorderDataRowsLocally.tsx +48 -0
- package/src/DataTable/useRowReordering.tsx +233 -0
- package/src/index.ts +1 -0
- package/src/labs/DataFilters.tsx +60 -17
- package/src/labs/DataTable.tsx +24 -11
- package/src/labs/index.ts +0 -1
- package/src/properties/odyssey-react-mui.properties +19 -2
- package/src/properties/ts/odyssey-react-mui.ts +1 -1
- package/src/theme/components.tsx +43 -16
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
|
|
3
|
+
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
|
|
4
|
+
*
|
|
5
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
8
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
*
|
|
10
|
+
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Dispatch, SetStateAction, memo } from "react";
|
|
14
|
+
import { Checkbox as MuiCheckbox } from "@mui/material";
|
|
15
|
+
import { MenuButton } from "../MenuButton";
|
|
16
|
+
import { MenuItem } from "../MenuItem";
|
|
17
|
+
import { ListIcon, ShowIcon } from "../icons.generated";
|
|
18
|
+
import { densityValues } from "./constants";
|
|
19
|
+
import { DataTableProps } from "./DataTable";
|
|
20
|
+
import { MRT_VisibilityState } from "material-react-table";
|
|
21
|
+
import { useTranslation } from "react-i18next";
|
|
22
|
+
|
|
23
|
+
export type DataTableSettingsProps = {
|
|
24
|
+
hasChangeableDensity: DataTableProps["hasChangeableDensity"];
|
|
25
|
+
rowDensity: (typeof densityValues)[number];
|
|
26
|
+
setRowDensity: Dispatch<SetStateAction<(typeof densityValues)[number]>>;
|
|
27
|
+
hasColumnVisibility: DataTableProps["hasColumnVisibility"];
|
|
28
|
+
columns: DataTableProps["columns"];
|
|
29
|
+
columnVisibility?: MRT_VisibilityState;
|
|
30
|
+
setColumnVisibility: Dispatch<
|
|
31
|
+
SetStateAction<MRT_VisibilityState | undefined>
|
|
32
|
+
>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const DataTableSettings = ({
|
|
36
|
+
hasChangeableDensity,
|
|
37
|
+
rowDensity,
|
|
38
|
+
setRowDensity,
|
|
39
|
+
hasColumnVisibility,
|
|
40
|
+
columns,
|
|
41
|
+
columnVisibility,
|
|
42
|
+
setColumnVisibility,
|
|
43
|
+
}: DataTableSettingsProps) => {
|
|
44
|
+
const { t } = useTranslation();
|
|
45
|
+
return (
|
|
46
|
+
<>
|
|
47
|
+
{hasChangeableDensity && (
|
|
48
|
+
<MenuButton
|
|
49
|
+
endIcon={<ListIcon />}
|
|
50
|
+
ariaLabel={t("table.density.arialabel")}
|
|
51
|
+
menuAlignment="right"
|
|
52
|
+
shouldCloseOnSelect={false}
|
|
53
|
+
>
|
|
54
|
+
<>
|
|
55
|
+
{densityValues.map((value: (typeof densityValues)[number]) => (
|
|
56
|
+
<MenuItem
|
|
57
|
+
key={value}
|
|
58
|
+
isSelected={rowDensity === value}
|
|
59
|
+
onClick={() => setRowDensity(value)}
|
|
60
|
+
>
|
|
61
|
+
{`${value.charAt(0).toUpperCase()}${value.slice(1)}`}
|
|
62
|
+
</MenuItem>
|
|
63
|
+
))}
|
|
64
|
+
</>
|
|
65
|
+
</MenuButton>
|
|
66
|
+
)}
|
|
67
|
+
|
|
68
|
+
{hasColumnVisibility && (
|
|
69
|
+
<MenuButton
|
|
70
|
+
endIcon={<ShowIcon />}
|
|
71
|
+
ariaLabel={t("table.columnvisibility.arialabel")}
|
|
72
|
+
menuAlignment="right"
|
|
73
|
+
shouldCloseOnSelect={false}
|
|
74
|
+
>
|
|
75
|
+
<>
|
|
76
|
+
{columns
|
|
77
|
+
.filter((column) => column.enableHiding !== false)
|
|
78
|
+
.map((column) => (
|
|
79
|
+
<MenuItem
|
|
80
|
+
key={column.accessorKey}
|
|
81
|
+
onClick={() => {
|
|
82
|
+
const columnId = column.id as string;
|
|
83
|
+
setColumnVisibility((prevVisibility) => ({
|
|
84
|
+
...prevVisibility,
|
|
85
|
+
[columnId]: prevVisibility
|
|
86
|
+
? prevVisibility[columnId] === false
|
|
87
|
+
: false,
|
|
88
|
+
}));
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
<MuiCheckbox
|
|
92
|
+
checked={
|
|
93
|
+
columnVisibility
|
|
94
|
+
? columnVisibility[column.accessorKey as string] !==
|
|
95
|
+
false
|
|
96
|
+
: true
|
|
97
|
+
}
|
|
98
|
+
/>
|
|
99
|
+
{column.header}
|
|
100
|
+
</MenuItem>
|
|
101
|
+
))}
|
|
102
|
+
</>
|
|
103
|
+
</MenuButton>
|
|
104
|
+
)}
|
|
105
|
+
</>
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
const MemoizedDataTableSettings = memo(DataTableSettings);
|
|
109
|
+
export { MemoizedDataTableSettings as DataTableSettings };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
|
|
3
|
+
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
|
|
4
|
+
*
|
|
5
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
8
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
*
|
|
10
|
+
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const densityValues = ["comfortable", "spacious", "compact"] as const;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
|
|
3
|
+
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
|
|
4
|
+
*
|
|
5
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
8
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
*
|
|
10
|
+
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export { DataTable, type DataTableProps } from "./DataTable";
|
|
14
|
+
export { densityValues } from "./constants";
|
|
15
|
+
export type {
|
|
16
|
+
MRT_ColumnFiltersState as DataTableFiltersState,
|
|
17
|
+
MRT_SortingState as DataTableSortingState,
|
|
18
|
+
MRT_RowSelectionState as DataTableRowSelectionState,
|
|
19
|
+
MRT_ColumnDef as DataTableColumn,
|
|
20
|
+
MRT_RowData as DataTableRowData,
|
|
21
|
+
MRT_Row as DataTableRow,
|
|
22
|
+
} from "material-react-table";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
|
|
3
|
+
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
|
|
4
|
+
*
|
|
5
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
8
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
*
|
|
10
|
+
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { MRT_RowData } from "material-react-table";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Reorders data rows locally.
|
|
17
|
+
*
|
|
18
|
+
* @param currentData - The current array of data rows.
|
|
19
|
+
* @param rowId - The ID of the row to move.
|
|
20
|
+
* @param newIndex - The new index to move the row to.
|
|
21
|
+
* @returns A new array of data with the row moved to the specified index.
|
|
22
|
+
*/
|
|
23
|
+
export const reorderDataRowsLocally = ({
|
|
24
|
+
currentData,
|
|
25
|
+
rowId,
|
|
26
|
+
newRowIndex,
|
|
27
|
+
}: {
|
|
28
|
+
currentData: MRT_RowData[];
|
|
29
|
+
rowId: string;
|
|
30
|
+
newRowIndex: number;
|
|
31
|
+
}): MRT_RowData[] => {
|
|
32
|
+
const updatedData = [...currentData];
|
|
33
|
+
const rowIndex = updatedData.findIndex((row) => row.id === rowId);
|
|
34
|
+
|
|
35
|
+
// Ensure the row exists and the new index is within bounds
|
|
36
|
+
if (rowIndex === -1 || newRowIndex < 0 || newRowIndex >= updatedData.length) {
|
|
37
|
+
console.warn("Invalid row ID or newIndex; cannot reorder rows.");
|
|
38
|
+
return updatedData; // Return the original data if conditions aren't met
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Remove the row from its current position
|
|
42
|
+
const [removedRow] = updatedData.splice(rowIndex, 1);
|
|
43
|
+
|
|
44
|
+
// Insert the row at the new index
|
|
45
|
+
updatedData.splice(newRowIndex, 0, removedRow);
|
|
46
|
+
|
|
47
|
+
return updatedData;
|
|
48
|
+
};
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
|
|
3
|
+
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
|
|
4
|
+
*
|
|
5
|
+
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
7
|
+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
8
|
+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
+
*
|
|
10
|
+
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Dispatch, SetStateAction, KeyboardEvent } from "react";
|
|
14
|
+
import { DataTableProps } from "./DataTable";
|
|
15
|
+
import { reorderDataRowsLocally } from "./reorderDataRowsLocally";
|
|
16
|
+
import { useOdysseyDesignTokens } from "../OdysseyDesignTokensContext";
|
|
17
|
+
import { MRT_Row, MRT_RowData, MRT_TableInstance } from "material-react-table";
|
|
18
|
+
|
|
19
|
+
export const useRowReordering = ({
|
|
20
|
+
totalRows,
|
|
21
|
+
onReorderRows,
|
|
22
|
+
data,
|
|
23
|
+
setData,
|
|
24
|
+
draggingRow,
|
|
25
|
+
setDraggingRow,
|
|
26
|
+
resultsPerPage,
|
|
27
|
+
page,
|
|
28
|
+
}: {
|
|
29
|
+
totalRows: DataTableProps["totalRows"];
|
|
30
|
+
onReorderRows: DataTableProps["onReorderRows"];
|
|
31
|
+
data: MRT_RowData[];
|
|
32
|
+
setData: Dispatch<SetStateAction<MRT_RowData[]>>;
|
|
33
|
+
draggingRow?: MRT_Row<MRT_RowData> | null;
|
|
34
|
+
setDraggingRow: Dispatch<
|
|
35
|
+
SetStateAction<MRT_Row<MRT_RowData> | null | undefined>
|
|
36
|
+
>;
|
|
37
|
+
resultsPerPage: number;
|
|
38
|
+
page: number;
|
|
39
|
+
}) => {
|
|
40
|
+
const updateRowOrder = ({
|
|
41
|
+
rowId,
|
|
42
|
+
newRowIndex,
|
|
43
|
+
}: {
|
|
44
|
+
rowId: string;
|
|
45
|
+
newRowIndex: number;
|
|
46
|
+
}) => {
|
|
47
|
+
if (newRowIndex < 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (totalRows && newRowIndex > totalRows) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const newData = reorderDataRowsLocally({
|
|
56
|
+
currentData: data,
|
|
57
|
+
rowId,
|
|
58
|
+
newRowIndex,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
setData(newData);
|
|
62
|
+
onReorderRows?.({ rowId, newRowIndex });
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const odysseyDesignTokens = useOdysseyDesignTokens();
|
|
66
|
+
const dragHandleStyles = {
|
|
67
|
+
padding: odysseyDesignTokens.Spacing1,
|
|
68
|
+
borderRadius: odysseyDesignTokens.BorderRadiusMain,
|
|
69
|
+
|
|
70
|
+
"&:focus-visible": {
|
|
71
|
+
boxShadow: `0 0 0 2px ${odysseyDesignTokens.HueNeutralWhite}, 0 0 0 4px ${odysseyDesignTokens.PalettePrimaryMain}`,
|
|
72
|
+
outline: "2px solid transparent",
|
|
73
|
+
outlineOffset: "1px",
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const dragHandleText = {
|
|
78
|
+
title: "Drag row or press space/enter key to start and stop reordering",
|
|
79
|
+
"aria-label":
|
|
80
|
+
"Drag row to reorder. Or, press space or enter to start and stop reordering and esc to cancel.",
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const draggableTableBodyRowClassName = ({
|
|
84
|
+
currentRowId,
|
|
85
|
+
draggingRowId,
|
|
86
|
+
hoveredRowId,
|
|
87
|
+
}: {
|
|
88
|
+
currentRowId: string;
|
|
89
|
+
draggingRowId?: string;
|
|
90
|
+
hoveredRowId?: string;
|
|
91
|
+
}) => {
|
|
92
|
+
if (draggingRowId === currentRowId && hoveredRowId !== currentRowId) {
|
|
93
|
+
return "isDragging";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (hoveredRowId === currentRowId && draggingRowId !== currentRowId) {
|
|
97
|
+
return "isDragTarget";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (draggingRowId === currentRowId && hoveredRowId === currentRowId) {
|
|
101
|
+
return "isDragging isDragTarget";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return undefined;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const getRowFromTableAndSetHovered = (
|
|
108
|
+
table: MRT_TableInstance<MRT_RowData>,
|
|
109
|
+
id: MRT_RowData["id"],
|
|
110
|
+
) => {
|
|
111
|
+
if (id) {
|
|
112
|
+
const nextRow: MRT_RowData = table.getRow(id);
|
|
113
|
+
|
|
114
|
+
if (nextRow) {
|
|
115
|
+
table.setHoveredRow(nextRow);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
type HandleDragHandleKeyDownArgs = {
|
|
121
|
+
table: MRT_TableInstance<MRT_RowData>;
|
|
122
|
+
row: MRT_Row<MRT_RowData>;
|
|
123
|
+
event: KeyboardEvent<HTMLButtonElement>;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const handleDragHandleKeyDown = ({
|
|
127
|
+
table,
|
|
128
|
+
row,
|
|
129
|
+
event,
|
|
130
|
+
}: HandleDragHandleKeyDownArgs) => {
|
|
131
|
+
const { hoveredRow } = table.getState();
|
|
132
|
+
|
|
133
|
+
const { key } = event;
|
|
134
|
+
|
|
135
|
+
const isSpaceKey = key === " ";
|
|
136
|
+
const isEnterKey = key === "Enter";
|
|
137
|
+
const isEscapeKey = key === "Escape";
|
|
138
|
+
const isArrowDown = key === "ArrowDown";
|
|
139
|
+
const isArrowUp = key === "ArrowUp";
|
|
140
|
+
const isSpaceOrEnter = isSpaceKey || isEnterKey;
|
|
141
|
+
const zeroIndexedPageNumber = page - 1;
|
|
142
|
+
const currentIndex = row.index + zeroIndexedPageNumber * resultsPerPage;
|
|
143
|
+
|
|
144
|
+
if (isEscapeKey) {
|
|
145
|
+
resetDraggingAndHoveredRow(table);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (isSpaceOrEnter) {
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
event.stopPropagation();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (draggingRow) {
|
|
155
|
+
if (typeof hoveredRow?.index === "number") {
|
|
156
|
+
const { index } = hoveredRow;
|
|
157
|
+
|
|
158
|
+
if (isSpaceOrEnter) {
|
|
159
|
+
const pageRelativeIndex =
|
|
160
|
+
index + zeroIndexedPageNumber * resultsPerPage;
|
|
161
|
+
|
|
162
|
+
if (pageRelativeIndex !== currentIndex) {
|
|
163
|
+
updateRowOrder({
|
|
164
|
+
rowId: row.id,
|
|
165
|
+
newRowIndex: pageRelativeIndex,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Can't transition CSS hover effect. Use timeout to delay hovered row effect removal
|
|
169
|
+
setTimeout(() => {
|
|
170
|
+
resetDraggingAndHoveredRow(table);
|
|
171
|
+
}, odysseyDesignTokens.TransitionDurationMainAsNumber);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (isArrowDown || isArrowUp) {
|
|
177
|
+
const nextIndex = isArrowDown ? index + 1 : index - 1;
|
|
178
|
+
getRowFromTableAndSetHovered(table, data[nextIndex]?.id);
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
if (isArrowDown || isArrowUp) {
|
|
182
|
+
const nextIndex = isArrowDown ? row.index + 1 : row.index - 1;
|
|
183
|
+
getRowFromTableAndSetHovered(table, data[nextIndex]?.id);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
if (isSpaceOrEnter) {
|
|
188
|
+
setDraggingRow(row);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const handleDragHandleOnDragEnd = (table: MRT_TableInstance<MRT_RowData>) => {
|
|
194
|
+
const cols = table.getAllColumns();
|
|
195
|
+
cols[0].toggleVisibility();
|
|
196
|
+
|
|
197
|
+
const { draggingRow, hoveredRow } = table.getState();
|
|
198
|
+
if (draggingRow) {
|
|
199
|
+
updateRowOrder({
|
|
200
|
+
rowId: draggingRow.id,
|
|
201
|
+
newRowIndex: (hoveredRow as MRT_RowData).index,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
setDraggingRow(null);
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const handleDragHandleOnDragCapture = (
|
|
209
|
+
table: MRT_TableInstance<MRT_RowData>,
|
|
210
|
+
) => {
|
|
211
|
+
if (!draggingRow && table.getState().draggingRow?.id) {
|
|
212
|
+
setDraggingRow(table.getState().draggingRow);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const resetDraggingAndHoveredRow = (
|
|
217
|
+
table: MRT_TableInstance<MRT_RowData>,
|
|
218
|
+
) => {
|
|
219
|
+
setDraggingRow(null);
|
|
220
|
+
table.setHoveredRow(null);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
dragHandleStyles,
|
|
225
|
+
dragHandleText,
|
|
226
|
+
draggableTableBodyRowClassName,
|
|
227
|
+
handleDragHandleKeyDown,
|
|
228
|
+
handleDragHandleOnDragCapture,
|
|
229
|
+
handleDragHandleOnDragEnd,
|
|
230
|
+
resetDraggingAndHoveredRow,
|
|
231
|
+
updateRowOrder,
|
|
232
|
+
};
|
|
233
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -69,6 +69,7 @@ export * from "./CircularProgress";
|
|
|
69
69
|
export * from "./CssBaseline";
|
|
70
70
|
export * from "./createShadowRootElement";
|
|
71
71
|
export * from "./createUniqueId";
|
|
72
|
+
export * from "./DataTable";
|
|
72
73
|
export * from "./Dialog";
|
|
73
74
|
export * from "./Fieldset";
|
|
74
75
|
export * from "./FieldComponentProps";
|
package/src/labs/DataFilters.tsx
CHANGED
|
@@ -30,7 +30,9 @@ import { Button } from "../Button";
|
|
|
30
30
|
import {
|
|
31
31
|
IconButton as MuiIconButton,
|
|
32
32
|
Menu as MuiMenu,
|
|
33
|
+
MenuItem as MuiMenuItem,
|
|
33
34
|
Popover as MuiPopover,
|
|
35
|
+
Typography as MuiTypography,
|
|
34
36
|
} from "@mui/material";
|
|
35
37
|
import {
|
|
36
38
|
CheckIcon,
|
|
@@ -38,14 +40,14 @@ import {
|
|
|
38
40
|
CloseCircleFilledIcon,
|
|
39
41
|
FilterIcon,
|
|
40
42
|
} from "../icons.generated";
|
|
41
|
-
import {
|
|
42
|
-
import { Paragraph, Subordinate } from "../Typography";
|
|
43
|
+
import { Subordinate } from "../Typography";
|
|
43
44
|
import { TextField } from "../TextField";
|
|
44
45
|
import { CheckboxGroup } from "../CheckboxGroup";
|
|
45
46
|
import { Checkbox } from "../Checkbox";
|
|
46
47
|
import { RadioGroup } from "../RadioGroup";
|
|
47
48
|
import { Radio } from "../Radio";
|
|
48
49
|
import { MRT_ColumnDef, MRT_RowData } from "material-react-table";
|
|
50
|
+
import { Trans, useTranslation } from "react-i18next";
|
|
49
51
|
|
|
50
52
|
export type DataFilterValue = string | string[] | undefined;
|
|
51
53
|
|
|
@@ -128,6 +130,7 @@ const DataFilters = ({
|
|
|
128
130
|
filters: filtersProp = [],
|
|
129
131
|
}: DataFiltersProps) => {
|
|
130
132
|
const [filters, setFilters] = useState<DataFilter[]>(filtersProp);
|
|
133
|
+
const { t } = useTranslation();
|
|
131
134
|
|
|
132
135
|
const initialInputValues = useMemo(() => {
|
|
133
136
|
return filtersProp.reduce(
|
|
@@ -307,7 +310,7 @@ const DataFilters = ({
|
|
|
307
310
|
aria-controls={isFiltersMenuOpen ? "filters-menu" : undefined}
|
|
308
311
|
aria-expanded={isFiltersMenuOpen ? "true" : undefined}
|
|
309
312
|
aria-haspopup="true"
|
|
310
|
-
ariaLabel="
|
|
313
|
+
ariaLabel={t("filters.filters.arialabel")}
|
|
311
314
|
endIcon={<FilterIcon />}
|
|
312
315
|
onClick={(event) => {
|
|
313
316
|
setFiltersMenuAnchorElement(event.currentTarget);
|
|
@@ -337,13 +340,23 @@ const DataFilters = ({
|
|
|
337
340
|
)?.value;
|
|
338
341
|
|
|
339
342
|
return (
|
|
340
|
-
<
|
|
343
|
+
<MuiMenuItem
|
|
341
344
|
key={filter.id}
|
|
342
345
|
onClick={(event) => {
|
|
343
346
|
setIsFilterPopoverOpen(true);
|
|
344
347
|
setFilterPopoverAnchorElement(event.currentTarget);
|
|
345
348
|
setFilterPopoverCurrentFilter(filter);
|
|
346
349
|
}}
|
|
350
|
+
selected={
|
|
351
|
+
filterPopoverCurrentFilter === filter &&
|
|
352
|
+
isFilterPopoverOpen === true
|
|
353
|
+
}
|
|
354
|
+
className={
|
|
355
|
+
filterPopoverCurrentFilter === filter &&
|
|
356
|
+
isFilterPopoverOpen === true
|
|
357
|
+
? "isVisiblySelected"
|
|
358
|
+
: undefined
|
|
359
|
+
}
|
|
347
360
|
>
|
|
348
361
|
<Box
|
|
349
362
|
sx={{
|
|
@@ -352,29 +365,54 @@ const DataFilters = ({
|
|
|
352
365
|
justifyContent: "space-between",
|
|
353
366
|
width: "100%",
|
|
354
367
|
minWidth: 180,
|
|
368
|
+
paddingBlock: 1,
|
|
369
|
+
paddingInlineStart: 2,
|
|
355
370
|
}}
|
|
356
371
|
>
|
|
357
372
|
<Box sx={{ marginRight: 2 }}>
|
|
358
|
-
<
|
|
373
|
+
<MuiTypography fontWeight="500" sx={{ marginBlockEnd: 2 }}>
|
|
374
|
+
{filter.label}
|
|
375
|
+
</MuiTypography>
|
|
359
376
|
<Subordinate component="div">
|
|
360
377
|
{!latestFilterValue ||
|
|
361
378
|
(Array.isArray(latestFilterValue) &&
|
|
362
|
-
latestFilterValue.length === 0)
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
379
|
+
latestFilterValue.length === 0) ? (
|
|
380
|
+
<Trans
|
|
381
|
+
i18nKey="filters.menuitem.any"
|
|
382
|
+
values={{
|
|
383
|
+
label: filter.label.toLowerCase(),
|
|
384
|
+
}}
|
|
385
|
+
/>
|
|
386
|
+
) : Array.isArray(latestFilterValue) ? (
|
|
387
|
+
<Trans
|
|
388
|
+
count={latestFilterValue.length}
|
|
389
|
+
i18nKey="filters.menuitem.selected"
|
|
390
|
+
values={{
|
|
391
|
+
selected: latestFilterValue.length,
|
|
392
|
+
}}
|
|
393
|
+
/>
|
|
394
|
+
) : (
|
|
395
|
+
latestFilterValue
|
|
396
|
+
)}
|
|
367
397
|
</Subordinate>
|
|
368
398
|
</Box>
|
|
369
399
|
<ChevronRightIcon />
|
|
370
400
|
</Box>
|
|
371
|
-
</
|
|
401
|
+
</MuiMenuItem>
|
|
372
402
|
);
|
|
373
403
|
})}
|
|
374
404
|
</MuiMenu>
|
|
375
405
|
</>
|
|
376
406
|
),
|
|
377
|
-
[
|
|
407
|
+
[
|
|
408
|
+
isFiltersMenuOpen,
|
|
409
|
+
filterPopoverCurrentFilter,
|
|
410
|
+
isFilterPopoverOpen,
|
|
411
|
+
filtersMenuAnchorElement,
|
|
412
|
+
filtersProp,
|
|
413
|
+
filters,
|
|
414
|
+
t,
|
|
415
|
+
],
|
|
378
416
|
);
|
|
379
417
|
|
|
380
418
|
return (
|
|
@@ -390,6 +428,11 @@ const DataFilters = ({
|
|
|
390
428
|
{/* Filter popover */}
|
|
391
429
|
<MuiPopover
|
|
392
430
|
anchorEl={filterPopoverAnchorElement}
|
|
431
|
+
// Positions the popover flush with the edge of the parent menu
|
|
432
|
+
// and at the right shadow elevation. These magic values are simply
|
|
433
|
+
// to match the default popover offset.
|
|
434
|
+
elevation={2}
|
|
435
|
+
sx={{ marginLeft: 2, marginTop: -1 }}
|
|
393
436
|
open={isFilterPopoverOpen}
|
|
394
437
|
anchorOrigin={{ vertical: "top", horizontal: "right" }}
|
|
395
438
|
onClose={(ev: MouseEvent) => {
|
|
@@ -493,7 +536,7 @@ const DataFilters = ({
|
|
|
493
536
|
inputValues[filterPopoverCurrentFilter.id] && (
|
|
494
537
|
<MuiIconButton
|
|
495
538
|
size="small"
|
|
496
|
-
aria-label="
|
|
539
|
+
aria-label={t("filters.filter.clear")}
|
|
497
540
|
onClick={() => {
|
|
498
541
|
updateInputValue({
|
|
499
542
|
filterId: filterPopoverCurrentFilter.id,
|
|
@@ -571,7 +614,7 @@ const DataFilters = ({
|
|
|
571
614
|
}}
|
|
572
615
|
>
|
|
573
616
|
<Radio
|
|
574
|
-
label="
|
|
617
|
+
label={t("filters.filter.any")}
|
|
575
618
|
value={""}
|
|
576
619
|
isChecked={
|
|
577
620
|
!inputValues[filterPopoverCurrentFilter.id]
|
|
@@ -615,7 +658,7 @@ const DataFilters = ({
|
|
|
615
658
|
<Box sx={{ display: "flex", gap: 2, width: "100%" }}>
|
|
616
659
|
<SearchField
|
|
617
660
|
value={searchValue}
|
|
618
|
-
label="
|
|
661
|
+
label={t("filters.search.label")}
|
|
619
662
|
onClear={() => {
|
|
620
663
|
setSearchValue("");
|
|
621
664
|
onChangeSearch("");
|
|
@@ -626,7 +669,7 @@ const DataFilters = ({
|
|
|
626
669
|
<Box>
|
|
627
670
|
<Button
|
|
628
671
|
variant="primary"
|
|
629
|
-
label="
|
|
672
|
+
label={t("filters.search.label")}
|
|
630
673
|
onClick={() => onChangeSearch(searchValue)}
|
|
631
674
|
/>
|
|
632
675
|
</Box>
|
|
@@ -642,7 +685,7 @@ const DataFilters = ({
|
|
|
642
685
|
<Box>
|
|
643
686
|
<Button
|
|
644
687
|
variant="secondary"
|
|
645
|
-
label="
|
|
688
|
+
label={t("filters.clear.label")}
|
|
646
689
|
onClick={clearAllFilters}
|
|
647
690
|
/>
|
|
648
691
|
</Box>
|