Fix grid scrolling issue (#3583)
* Fix grid scrolling issue * Remove outline * Strict null checks * Strict null checks * Strict null checks
This commit is contained in:
parent
cb3f7d971c
commit
7c933f0d9b
3 changed files with 84 additions and 38 deletions
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -17,7 +17,7 @@
|
||||||
"@editorjs/list": "^1.7.0",
|
"@editorjs/list": "^1.7.0",
|
||||||
"@editorjs/paragraph": "^2.8.0",
|
"@editorjs/paragraph": "^2.8.0",
|
||||||
"@editorjs/quote": "^2.4.0",
|
"@editorjs/quote": "^2.4.0",
|
||||||
"@glideapps/glide-data-grid": "^5.0.0",
|
"@glideapps/glide-data-grid": "5.2.1",
|
||||||
"@glideapps/glide-data-grid-cells": "^5.2.1",
|
"@glideapps/glide-data-grid-cells": "^5.2.1",
|
||||||
"@graphiql/plugin-explorer": "^0.1.12",
|
"@graphiql/plugin-explorer": "^0.1.12",
|
||||||
"@graphiql/react": "^0.15.0",
|
"@graphiql/react": "^0.15.0",
|
||||||
|
|
24
package.json
24
package.json
|
@ -24,7 +24,7 @@
|
||||||
"@editorjs/list": "^1.7.0",
|
"@editorjs/list": "^1.7.0",
|
||||||
"@editorjs/paragraph": "^2.8.0",
|
"@editorjs/paragraph": "^2.8.0",
|
||||||
"@editorjs/quote": "^2.4.0",
|
"@editorjs/quote": "^2.4.0",
|
||||||
"@glideapps/glide-data-grid": "^5.0.0",
|
"@glideapps/glide-data-grid": "5.2.1",
|
||||||
"@glideapps/glide-data-grid-cells": "^5.2.1",
|
"@glideapps/glide-data-grid-cells": "^5.2.1",
|
||||||
"@graphiql/plugin-explorer": "^0.1.12",
|
"@graphiql/plugin-explorer": "^0.1.12",
|
||||||
"@graphiql/react": "^0.15.0",
|
"@graphiql/react": "^0.15.0",
|
||||||
|
@ -185,6 +185,16 @@
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@storybook/react": "^5.1.9",
|
"@storybook/react": "^5.1.9",
|
||||||
|
"@swc/core-darwin-arm64": "1.3.40",
|
||||||
|
"@swc/core-darwin-x64": "1.3.40",
|
||||||
|
"@swc/core-linux-arm-gnueabihf": "1.3.40",
|
||||||
|
"@swc/core-linux-arm64-gnu": "1.3.40",
|
||||||
|
"@swc/core-linux-arm64-musl": "1.3.40",
|
||||||
|
"@swc/core-linux-x64-gnu": "1.3.40",
|
||||||
|
"@swc/core-linux-x64-musl": "1.3.40",
|
||||||
|
"@swc/core-win32-arm64-msvc": "1.3.40",
|
||||||
|
"@swc/core-win32-ia32-msvc": "1.3.40",
|
||||||
|
"@swc/core-win32-x64-msvc": "1.3.40",
|
||||||
"@testing-library/jest-dom": "^5.16.5",
|
"@testing-library/jest-dom": "^5.16.5",
|
||||||
"@testing-library/react": "^12.1.5",
|
"@testing-library/react": "^12.1.5",
|
||||||
"@testing-library/react-hooks": "^8.0.1",
|
"@testing-library/react-hooks": "^8.0.1",
|
||||||
|
@ -224,17 +234,7 @@
|
||||||
"mochawesome-report-generator": "^6.0.1",
|
"mochawesome-report-generator": "^6.0.1",
|
||||||
"prettier": "^2.8.4",
|
"prettier": "^2.8.4",
|
||||||
"setup-polly-jest": "^0.9.1",
|
"setup-polly-jest": "^0.9.1",
|
||||||
"ts-jest": "^27.1.5",
|
"ts-jest": "^27.1.5"
|
||||||
"@swc/core-darwin-arm64": "1.3.40",
|
|
||||||
"@swc/core-darwin-x64": "1.3.40",
|
|
||||||
"@swc/core-linux-arm-gnueabihf": "1.3.40",
|
|
||||||
"@swc/core-linux-arm64-gnu": "1.3.40",
|
|
||||||
"@swc/core-linux-arm64-musl": "1.3.40",
|
|
||||||
"@swc/core-linux-x64-gnu": "1.3.40",
|
|
||||||
"@swc/core-linux-x64-musl": "1.3.40",
|
|
||||||
"@swc/core-win32-arm64-msvc": "1.3.40",
|
|
||||||
"@swc/core-win32-ia32-msvc": "1.3.40",
|
|
||||||
"@swc/core-win32-x64-msvc": "1.3.40"
|
|
||||||
},
|
},
|
||||||
"//@swc/*": "swc packages are required until https://github.com/npm/cli/issues/4828 is fixed",
|
"//@swc/*": "swc packages are required until https://github.com/npm/cli/issues/4828 is fixed",
|
||||||
"jest": {
|
"jest": {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import "@glideapps/glide-data-grid/dist/index.css";
|
import "@glideapps/glide-data-grid/dist/index.css";
|
||||||
|
|
||||||
|
import { getAppMountUri } from "@dashboard/config";
|
||||||
import useNavigator from "@dashboard/hooks/useNavigator";
|
import useNavigator from "@dashboard/hooks/useNavigator";
|
||||||
import { usePreventHistoryBack } from "@dashboard/hooks/usePreventHistoryBack";
|
import { usePreventHistoryBack } from "@dashboard/hooks/usePreventHistoryBack";
|
||||||
import DataEditor, {
|
import DataEditor, {
|
||||||
|
CellClickedEventArgs,
|
||||||
DataEditorProps,
|
DataEditorProps,
|
||||||
DataEditorRef,
|
DataEditorRef,
|
||||||
EditableGridCell,
|
EditableGridCell,
|
||||||
|
@ -129,10 +131,10 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { themeValues } = useTheme();
|
const { themeValues } = useTheme();
|
||||||
const datagridTheme = useDatagridTheme(readonly, readonly);
|
const datagridTheme = useDatagridTheme(readonly, readonly);
|
||||||
const editor = useRef<DataEditorRef>();
|
const editor = useRef<DataEditorRef | null>(null);
|
||||||
const customRenderers = useCustomCellRenderers();
|
const customRenderers = useCustomCellRenderers();
|
||||||
|
|
||||||
const hackARef = useRef<HTMLAnchorElement>(null);
|
const hackARef = useRef<HTMLAnchorElement | null>(null);
|
||||||
const navigate = useNavigator();
|
const navigate = useNavigator();
|
||||||
|
|
||||||
const { scrolledToRight, scroller } = useScrollRight();
|
const { scrolledToRight, scroller } = useScrollRight();
|
||||||
|
@ -210,6 +212,10 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
const handleOnCellEdited = useCallback(
|
const handleOnCellEdited = useCallback(
|
||||||
([column, row]: Item, newValue: EditableGridCell): void => {
|
([column, row]: Item, newValue: EditableGridCell): void => {
|
||||||
onCellEdited([column, row], newValue);
|
onCellEdited([column, row], newValue);
|
||||||
|
if (!editor.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
editor.current.updateCells(
|
editor.current.updateCells(
|
||||||
range(availableColumns.length).map(offset => ({
|
range(availableColumns.length).map(offset => ({
|
||||||
cell: [column + offset, row],
|
cell: [column + offset, row],
|
||||||
|
@ -219,15 +225,6 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
[onCellEdited, availableColumns],
|
[onCellEdited, availableColumns],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCellClick = useCallback(
|
|
||||||
(item: Item) => {
|
|
||||||
if (onRowClick && item[0] !== -1) {
|
|
||||||
onRowClick(item);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[onRowClick],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleRowHover = useCallback(
|
const handleRowHover = useCallback(
|
||||||
(args: GridMouseEventArgs) => {
|
(args: GridMouseEventArgs) => {
|
||||||
if (hasRowHover) {
|
if (hasRowHover) {
|
||||||
|
@ -249,11 +246,26 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
hackARef.current.style.width = `${args.bounds.width}px`;
|
hackARef.current.style.width = `${args.bounds.width}px`;
|
||||||
hackARef.current.style.top = `${window.scrollY + args.bounds.y}px`;
|
hackARef.current.style.top = `${window.scrollY + args.bounds.y}px`;
|
||||||
hackARef.current.style.height = `${args.bounds.height}px`;
|
hackARef.current.style.height = `${args.bounds.height}px`;
|
||||||
hackARef.current.href = href;
|
hackARef.current.href =
|
||||||
|
getAppMountUri() + (href.startsWith("/") ? href.slice(1) : href);
|
||||||
|
hackARef.current.dataset.reactRouterPath = href;
|
||||||
},
|
},
|
||||||
[hasRowHover, rowAnchor],
|
[hasRowHover, rowAnchor],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleCellClick = useCallback(
|
||||||
|
(item: Item, args: CellClickedEventArgs) => {
|
||||||
|
if (onRowClick && item[0] !== -1) {
|
||||||
|
onRowClick(item);
|
||||||
|
}
|
||||||
|
handleRowHover(args);
|
||||||
|
if (hackARef.current) {
|
||||||
|
hackARef.current.click();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onRowClick, handleRowHover],
|
||||||
|
);
|
||||||
|
|
||||||
const handleGridSelectionChange = (gridSelection: GridSelection) => {
|
const handleGridSelectionChange = (gridSelection: GridSelection) => {
|
||||||
// In readonly we not allow selecting cells, but we allow selcting column
|
// In readonly we not allow selecting cells, but we allow selcting column
|
||||||
if (readonly && !gridSelection.current) {
|
if (readonly && !gridSelection.current) {
|
||||||
|
@ -275,7 +287,7 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
themeValues.colors.background.interactiveNeutralSecondaryHovering,
|
themeValues.colors.background.interactiveNeutralSecondaryHovering,
|
||||||
bgCellMedium:
|
bgCellMedium:
|
||||||
themeValues.colors.background.interactiveNeutralSecondaryHovering,
|
themeValues.colors.background.interactiveNeutralSecondaryHovering,
|
||||||
accentLight: undefined,
|
accentLight: undefined as string | undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (readonly) {
|
if (readonly) {
|
||||||
|
@ -321,6 +333,9 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
clearTooltip();
|
clearTooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!onColumnResize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
onColumnResize(column, newSize);
|
onColumnResize(column, newSize);
|
||||||
},
|
},
|
||||||
[clearTooltip, onColumnResize, tooltip],
|
[clearTooltip, onColumnResize, tooltip],
|
||||||
|
@ -331,6 +346,9 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
if (tooltip) {
|
if (tooltip) {
|
||||||
clearTooltip();
|
clearTooltip();
|
||||||
}
|
}
|
||||||
|
if (!onColumnMoved) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
onColumnMoved(startIndex, endIndex);
|
onColumnMoved(startIndex, endIndex);
|
||||||
},
|
},
|
||||||
[clearTooltip, onColumnMoved, tooltip],
|
[clearTooltip, onColumnMoved, tooltip],
|
||||||
|
@ -338,7 +356,7 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
|
|
||||||
const selectionActionsComponent = useMemo(
|
const selectionActionsComponent = useMemo(
|
||||||
() =>
|
() =>
|
||||||
selection?.rows.length > 0
|
selection?.rows && selection?.rows.length > 0
|
||||||
? selectionActions(Array.from(selection.rows), {
|
? selectionActions(Array.from(selection.rows), {
|
||||||
removeRows: handleRemoveRows,
|
removeRows: handleRemoveRows,
|
||||||
})
|
})
|
||||||
|
@ -346,6 +364,29 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
[selection, selectionActions, handleRemoveRows],
|
[selection, selectionActions, handleRemoveRows],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Hide the link when scrolling over it so that the scroll/wheel events go through to the Datagrid
|
||||||
|
// Show the link quickly after the last scroll/wheel event
|
||||||
|
const hideLinkAndShowAfterDelay = useCallback(
|
||||||
|
(() => {
|
||||||
|
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
return () => {
|
||||||
|
if (timer) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hackARef.current) {
|
||||||
|
hackARef.current.style.display = "none";
|
||||||
|
}
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
if (hackARef.current) {
|
||||||
|
hackARef.current.style.display = "block";
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
})(),
|
||||||
|
[hackARef],
|
||||||
|
);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Box display="flex" justifyContent="center" marginY={12}>
|
<Box display="flex" justifyContent="center" marginY={12}>
|
||||||
|
@ -387,7 +428,7 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
<CardContent classes={{ root: classes.cardContentRoot }}>
|
<CardContent classes={{ root: classes.cardContentRoot }}>
|
||||||
{rowsTotal > 0 ? (
|
{rowsTotal > 0 ? (
|
||||||
<>
|
<>
|
||||||
{selection?.rows.length > 0 && (
|
{selection?.rows && selection?.rows.length > 0 && (
|
||||||
<div className={classes.actionBtnBar}>
|
<div className={classes.actionBtnBar}>
|
||||||
{selectionActionsComponent}
|
{selectionActionsComponent}
|
||||||
</div>
|
</div>
|
||||||
|
@ -510,16 +551,21 @@ export const Datagrid: React.FC<DatagridProps> = ({
|
||||||
bounds={tooltip?.bounds}
|
bounds={tooltip?.bounds}
|
||||||
title={tooltip?.title}
|
title={tooltip?.title}
|
||||||
/>
|
/>
|
||||||
<a
|
{rowAnchor && (
|
||||||
ref={hackARef}
|
<a
|
||||||
style={{ position: "absolute" }}
|
ref={hackARef}
|
||||||
tabIndex={-1}
|
style={{ position: "absolute" }}
|
||||||
aria-hidden={true}
|
tabIndex={-1}
|
||||||
onClick={e => {
|
aria-hidden={true}
|
||||||
e.preventDefault();
|
onWheelCapture={hideLinkAndShowAfterDelay}
|
||||||
navigate(e.currentTarget.pathname);
|
onClick={e => {
|
||||||
}}
|
e.preventDefault();
|
||||||
/>
|
if (e.currentTarget.dataset.reactRouterPath) {
|
||||||
|
navigate(e.currentTarget.dataset.reactRouterPath);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</FullScreenContainer>
|
</FullScreenContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue