@okta/odyssey-react-mui 1.9.13 → 1.9.15
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 +8 -0
- package/dist/OdysseyTranslationProvider.js +1 -1
- package/dist/OdysseyTranslationProvider.js.map +1 -1
- package/dist/labs/DataTable.js +169 -48
- package/dist/labs/DataTable.js.map +1 -1
- package/dist/src/labs/DataTable.d.ts.map +1 -1
- package/dist/tsconfig.production.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/OdysseyTranslationProvider.tsx +1 -1
- package/src/labs/DataTable.tsx +199 -41
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okta/odyssey-react-mui",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.15",
|
|
4
4
|
"description": "React MUI components for Odyssey, Okta's design system",
|
|
5
5
|
"author": "Okta, Inc.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@mui/system": "^5.14.9",
|
|
52
52
|
"@mui/utils": "^5.11.2",
|
|
53
53
|
"@mui/x-date-pickers": "^5.0.15",
|
|
54
|
-
"@okta/odyssey-design-tokens": "1.9.
|
|
54
|
+
"@okta/odyssey-design-tokens": "1.9.15",
|
|
55
55
|
"date-fns": "^2.30.0",
|
|
56
56
|
"i18next": "^23.5.1",
|
|
57
57
|
"material-react-table": "^2.0.2",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"react": ">=17 <19",
|
|
64
64
|
"react-dom": ">=17 <19"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "6c4dcd20f0d97c07740c0f6132fe76347a6e7f18"
|
|
67
67
|
}
|
|
@@ -66,7 +66,7 @@ export const OdysseyTranslationProvider = <SupportedLanguages extends string>({
|
|
|
66
66
|
};
|
|
67
67
|
// Defaults to the browser's language if available otherwise `en` will be used
|
|
68
68
|
i18n.changeLanguage(
|
|
69
|
-
|
|
69
|
+
languageCode || window.navigator.language,
|
|
70
70
|
changeHtmlElementLanguageAttribute
|
|
71
71
|
);
|
|
72
72
|
}, [languageCode]);
|
package/src/labs/DataTable.tsx
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
MRT_RowSelectionState,
|
|
24
24
|
MRT_Row,
|
|
25
25
|
MRT_ColumnDef,
|
|
26
|
+
MRT_TableInstance,
|
|
26
27
|
} from "material-react-table";
|
|
27
28
|
import {
|
|
28
29
|
Fragment,
|
|
@@ -33,6 +34,7 @@ import {
|
|
|
33
34
|
useMemo,
|
|
34
35
|
useRef,
|
|
35
36
|
useState,
|
|
37
|
+
KeyboardEvent,
|
|
36
38
|
} from "react";
|
|
37
39
|
import {
|
|
38
40
|
ArrowTopIcon,
|
|
@@ -45,6 +47,7 @@ import {
|
|
|
45
47
|
MoreIcon,
|
|
46
48
|
} from "../icons.generated";
|
|
47
49
|
import { Checkbox as MuiCheckbox } from "@mui/material";
|
|
50
|
+
import { useOdysseyDesignTokens } from "../OdysseyDesignTokensContext";
|
|
48
51
|
import {
|
|
49
52
|
DataTablePagination,
|
|
50
53
|
paginationTypeValues,
|
|
@@ -254,6 +257,32 @@ export type DataTableProps = {
|
|
|
254
257
|
) => ReactElement<typeof MenuItem | typeof Fragment>;
|
|
255
258
|
};
|
|
256
259
|
|
|
260
|
+
type TableType = MRT_TableInstance<MRT_RowData>;
|
|
261
|
+
|
|
262
|
+
const reorderDataRowsLocally = ({
|
|
263
|
+
currentData,
|
|
264
|
+
rowId,
|
|
265
|
+
newIndex,
|
|
266
|
+
}: {
|
|
267
|
+
currentData: MRT_TableOptions<MRT_RowData>["data"];
|
|
268
|
+
rowId: string;
|
|
269
|
+
newIndex: number;
|
|
270
|
+
}) => {
|
|
271
|
+
const updatedData = [...currentData];
|
|
272
|
+
|
|
273
|
+
const rowIndex = updatedData.findIndex((row) => row.id === rowId);
|
|
274
|
+
|
|
275
|
+
if (rowIndex !== -1) {
|
|
276
|
+
// Remove the row from its current position
|
|
277
|
+
const [removedRow] = updatedData.splice(rowIndex, 1);
|
|
278
|
+
|
|
279
|
+
// Insert the row at the new index
|
|
280
|
+
updatedData.splice(newIndex, 0, removedRow);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return updatedData;
|
|
284
|
+
};
|
|
285
|
+
|
|
257
286
|
const DataTable = ({
|
|
258
287
|
columns,
|
|
259
288
|
data: dataProp,
|
|
@@ -280,6 +309,7 @@ const DataTable = ({
|
|
|
280
309
|
hasSearch,
|
|
281
310
|
hasSorting,
|
|
282
311
|
}: DataTableProps) => {
|
|
312
|
+
const odysseyDesignTokens = useOdysseyDesignTokens();
|
|
283
313
|
const [draggingRow, setDraggingRow] = useState<MRT_Row<MRT_RowData> | null>();
|
|
284
314
|
const [showSkeletons, setShowSkeletons] = useState<boolean>(true);
|
|
285
315
|
const [data, setData] =
|
|
@@ -305,6 +335,14 @@ const DataTable = ({
|
|
|
305
335
|
const [globalFilter, setGlobalFilter] = useState<string>("");
|
|
306
336
|
const [filters, setFilters] = useState<Array<DataFilter>>();
|
|
307
337
|
|
|
338
|
+
useEffect(() => {
|
|
339
|
+
setShowSkeletons(false);
|
|
340
|
+
}, [data]);
|
|
341
|
+
|
|
342
|
+
useEffect(() => {
|
|
343
|
+
onRowSelectionChange?.(rowSelection);
|
|
344
|
+
}, [rowSelection, onRowSelectionChange]);
|
|
345
|
+
|
|
308
346
|
const refreshData = useCallback(async () => {
|
|
309
347
|
setShowSkeletons(true);
|
|
310
348
|
try {
|
|
@@ -318,11 +356,14 @@ const DataTable = ({
|
|
|
318
356
|
setData(newData);
|
|
319
357
|
setShowSkeletons(false);
|
|
320
358
|
} catch (error) {
|
|
321
|
-
console.log(error);
|
|
322
359
|
setShowSkeletons(false);
|
|
323
360
|
}
|
|
324
361
|
}, [page, resultsPerPage, sorting, globalFilter, filters, fetchDataFn]);
|
|
325
362
|
|
|
363
|
+
useEffect(() => {
|
|
364
|
+
refreshData();
|
|
365
|
+
}, [refreshData, page, resultsPerPage, sorting, globalFilter, filters]);
|
|
366
|
+
|
|
326
367
|
const handleSortingChange = useCallback(
|
|
327
368
|
(updater: MRT_Updater<MRT_SortingState>) => {
|
|
328
369
|
setSorting((prevSorting) =>
|
|
@@ -359,7 +400,7 @@ const DataTable = ({
|
|
|
359
400
|
[rowSelection]
|
|
360
401
|
);
|
|
361
402
|
|
|
362
|
-
const
|
|
403
|
+
const updateRowOrder = useCallback(
|
|
363
404
|
({ rowId, newIndex }: { rowId: string; newIndex: number }) => {
|
|
364
405
|
if (newIndex < 0) {
|
|
365
406
|
return;
|
|
@@ -369,26 +410,145 @@ const DataTable = ({
|
|
|
369
410
|
return;
|
|
370
411
|
}
|
|
371
412
|
|
|
413
|
+
const newData = reorderDataRowsLocally({
|
|
414
|
+
currentData: data,
|
|
415
|
+
rowId,
|
|
416
|
+
newIndex,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
setData(newData);
|
|
372
420
|
reorderDataFn?.({ rowId, newIndex });
|
|
373
421
|
refreshData();
|
|
374
422
|
},
|
|
375
|
-
[totalRows, reorderDataFn, refreshData]
|
|
423
|
+
[data, totalRows, reorderDataFn, refreshData]
|
|
376
424
|
);
|
|
377
425
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}, [data]);
|
|
426
|
+
const rowVirtualizerInstanceRef =
|
|
427
|
+
useRef<MRT_Virtualizer<HTMLDivElement, HTMLTableRowElement>>(null);
|
|
381
428
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
429
|
+
const getRowFromTableAndSetHovered = (
|
|
430
|
+
table: TableType,
|
|
431
|
+
id: MRT_RowData["id"]
|
|
432
|
+
) => {
|
|
433
|
+
if (id) {
|
|
434
|
+
const nextRow: MRT_RowData = table.getRow(id);
|
|
385
435
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
436
|
+
if (nextRow) {
|
|
437
|
+
table.setHoveredRow(nextRow);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
const resetDraggingAndHoveredRow = (table: TableType) => {
|
|
443
|
+
setDraggingRow(null);
|
|
444
|
+
table.setHoveredRow(null);
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
type HandleDragHandleKeyDownArgs = {
|
|
448
|
+
table: TableType;
|
|
449
|
+
row: MRT_Row<MRT_RowData>;
|
|
450
|
+
event: KeyboardEvent<HTMLButtonElement>;
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
const handleDragHandleKeyDown = useCallback(
|
|
454
|
+
({ table, row, event }: HandleDragHandleKeyDownArgs) => {
|
|
455
|
+
const { hoveredRow } = table.getState();
|
|
456
|
+
|
|
457
|
+
const { key } = event;
|
|
458
|
+
|
|
459
|
+
const isSpaceKey = key === " ";
|
|
460
|
+
const isEnterKey = key === "Enter";
|
|
461
|
+
const isEscapeKey = key === "Escape";
|
|
462
|
+
const isArrowDown = key === "ArrowDown";
|
|
463
|
+
const isArrowUp = key === "ArrowUp";
|
|
464
|
+
const isSpaceOrEnter = isSpaceKey || isEnterKey;
|
|
465
|
+
const zeroIndexedPageNumber = page - 1;
|
|
466
|
+
const currentIndex = row.index + zeroIndexedPageNumber * resultsPerPage;
|
|
467
|
+
|
|
468
|
+
if (isEscapeKey) {
|
|
469
|
+
resetDraggingAndHoveredRow(table);
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
389
472
|
|
|
390
|
-
|
|
391
|
-
|
|
473
|
+
if (isSpaceOrEnter) {
|
|
474
|
+
event.preventDefault();
|
|
475
|
+
event.stopPropagation();
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (draggingRow) {
|
|
479
|
+
if (typeof hoveredRow?.index === "number") {
|
|
480
|
+
const { index } = hoveredRow;
|
|
481
|
+
|
|
482
|
+
if (isSpaceOrEnter) {
|
|
483
|
+
const pageRelativeIndex =
|
|
484
|
+
index + zeroIndexedPageNumber * resultsPerPage;
|
|
485
|
+
|
|
486
|
+
if (pageRelativeIndex !== currentIndex) {
|
|
487
|
+
updateRowOrder({
|
|
488
|
+
rowId: row.id,
|
|
489
|
+
newIndex: pageRelativeIndex,
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// Can't transition CSS hover effect. Use timeout to delay hovered row effect removal
|
|
493
|
+
setTimeout(() => {
|
|
494
|
+
resetDraggingAndHoveredRow(table);
|
|
495
|
+
}, odysseyDesignTokens.TransitionDurationMainAsNumber);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (isArrowDown || isArrowUp) {
|
|
501
|
+
const nextIndex = isArrowDown ? index + 1 : index - 1;
|
|
502
|
+
getRowFromTableAndSetHovered(table, data[nextIndex]?.id);
|
|
503
|
+
}
|
|
504
|
+
} else {
|
|
505
|
+
if (isArrowDown || isArrowUp) {
|
|
506
|
+
const nextIndex = isArrowDown ? row.index + 1 : row.index - 1;
|
|
507
|
+
getRowFromTableAndSetHovered(table, data[nextIndex]?.id);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
} else {
|
|
511
|
+
if (isSpaceOrEnter) {
|
|
512
|
+
setDraggingRow(row);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
[
|
|
517
|
+
data,
|
|
518
|
+
draggingRow,
|
|
519
|
+
odysseyDesignTokens,
|
|
520
|
+
page,
|
|
521
|
+
resultsPerPage,
|
|
522
|
+
updateRowOrder,
|
|
523
|
+
]
|
|
524
|
+
);
|
|
525
|
+
|
|
526
|
+
const handleDragHandleOnDragEnd = useCallback(
|
|
527
|
+
(table: TableType) => {
|
|
528
|
+
const cols = table.getAllColumns();
|
|
529
|
+
cols[0].toggleVisibility();
|
|
530
|
+
|
|
531
|
+
const { draggingRow, hoveredRow } = table.getState();
|
|
532
|
+
if (draggingRow) {
|
|
533
|
+
updateRowOrder({
|
|
534
|
+
rowId: draggingRow.id,
|
|
535
|
+
newIndex: (hoveredRow as MRT_RowData).index,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
setDraggingRow(null);
|
|
540
|
+
},
|
|
541
|
+
[updateRowOrder]
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
const handleDragHandleOnDragCapture = useCallback(
|
|
545
|
+
(table: TableType) => {
|
|
546
|
+
if (!draggingRow && table.getState().draggingRow?.id) {
|
|
547
|
+
setDraggingRow(table.getState().draggingRow);
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
[draggingRow]
|
|
551
|
+
);
|
|
392
552
|
|
|
393
553
|
const table = useMaterialReactTable({
|
|
394
554
|
columns: columns,
|
|
@@ -440,13 +600,13 @@ const DataTable = ({
|
|
|
440
600
|
muiTableBodyCellProps: {
|
|
441
601
|
sx: {
|
|
442
602
|
minWidth: 0,
|
|
443
|
-
width:
|
|
603
|
+
width: "auto",
|
|
444
604
|
},
|
|
445
605
|
},
|
|
446
606
|
muiTableHeadCellProps: {
|
|
447
607
|
sx: {
|
|
448
608
|
minWidth: 0,
|
|
449
|
-
width:
|
|
609
|
+
width: "auto",
|
|
450
610
|
},
|
|
451
611
|
},
|
|
452
612
|
},
|
|
@@ -487,29 +647,27 @@ const DataTable = ({
|
|
|
487
647
|
: undefined,
|
|
488
648
|
}),
|
|
489
649
|
|
|
490
|
-
muiRowDragHandleProps: {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if (draggingRow) {
|
|
498
|
-
handleReordering({
|
|
499
|
-
rowId: draggingRow.id,
|
|
500
|
-
newIndex: (hoveredRow as MRT_RowData).index,
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
setDraggingRow(null);
|
|
650
|
+
muiRowDragHandleProps: ({ table, row }) => ({
|
|
651
|
+
title: "Drag row or press space/enter key to start and stop reordering",
|
|
652
|
+
"aria-label":
|
|
653
|
+
"Drag row to reorder. Or, press space or enter to start and stop reordering and esc to cancel.",
|
|
654
|
+
onKeyDown: (event) => handleDragHandleKeyDown({ table, row, event }),
|
|
655
|
+
onBlur: () => {
|
|
656
|
+
resetDraggingAndHoveredRow(table);
|
|
505
657
|
},
|
|
506
|
-
|
|
507
|
-
onDragCapture: () =>
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
658
|
+
onDragEnd: () => handleDragHandleOnDragEnd(table),
|
|
659
|
+
onDragCapture: () => handleDragHandleOnDragCapture(table),
|
|
660
|
+
sx: {
|
|
661
|
+
padding: odysseyDesignTokens.Spacing1,
|
|
662
|
+
borderRadius: odysseyDesignTokens.BorderRadiusMain,
|
|
663
|
+
|
|
664
|
+
"&:focus-visible": {
|
|
665
|
+
boxShadow: `0 0 0 2px ${odysseyDesignTokens.HueNeutralWhite}, 0 0 0 4px ${odysseyDesignTokens.PalettePrimaryMain}`,
|
|
666
|
+
outline: "2px solid transparent",
|
|
667
|
+
outlineOffset: "1px",
|
|
668
|
+
},
|
|
511
669
|
},
|
|
512
|
-
},
|
|
670
|
+
}),
|
|
513
671
|
|
|
514
672
|
renderRowActions: ({ row }) => {
|
|
515
673
|
const currentIndex = row.index + (page - 1) * resultsPerPage;
|
|
@@ -533,14 +691,14 @@ const DataTable = ({
|
|
|
533
691
|
)}
|
|
534
692
|
<MenuItem
|
|
535
693
|
isDisabled={currentIndex <= 0}
|
|
536
|
-
onClick={() =>
|
|
694
|
+
onClick={() => updateRowOrder({ rowId: row.id, newIndex: 0 })}
|
|
537
695
|
>
|
|
538
696
|
<ArrowTopIcon /> Bring to front
|
|
539
697
|
</MenuItem>
|
|
540
698
|
<MenuItem
|
|
541
699
|
isDisabled={currentIndex <= 0}
|
|
542
700
|
onClick={() =>
|
|
543
|
-
|
|
701
|
+
updateRowOrder({
|
|
544
702
|
rowId: row.id,
|
|
545
703
|
newIndex: currentIndex <= 0 ? 0 : currentIndex - 1,
|
|
546
704
|
})
|
|
@@ -551,7 +709,7 @@ const DataTable = ({
|
|
|
551
709
|
<MenuItem
|
|
552
710
|
isDisabled={totalRows ? currentIndex >= totalRows - 1 : false}
|
|
553
711
|
onClick={() =>
|
|
554
|
-
|
|
712
|
+
updateRowOrder({
|
|
555
713
|
rowId: row.id,
|
|
556
714
|
newIndex: currentIndex + 1,
|
|
557
715
|
})
|
|
@@ -564,7 +722,7 @@ const DataTable = ({
|
|
|
564
722
|
<MenuItem
|
|
565
723
|
isDisabled={currentIndex >= totalRows - 1}
|
|
566
724
|
onClick={() =>
|
|
567
|
-
|
|
725
|
+
updateRowOrder({
|
|
568
726
|
rowId: row.id,
|
|
569
727
|
newIndex: totalRows,
|
|
570
728
|
})
|