refactored mouse events on tables into DataGridUtils to fix text selection on child tables.

This commit is contained in:
Tim Chamberlain
2023-12-08 12:01:16 -06:00
parent 6375fc6c25
commit 97ae3a7271
3 changed files with 73 additions and 37 deletions

View File

@ -27,8 +27,8 @@ import Button from "@mui/material/Button";
import Icon from "@mui/material/Icon";
import Tooltip from "@mui/material/Tooltip/Tooltip";
import Typography from "@mui/material/Typography";
import {DataGridPro, GridCallbackDetails, GridRowParams, MuiEvent} from "@mui/x-data-grid-pro";
import React, {useEffect, useState} from "react";
import {DataGridPro, GridCallbackDetails, GridEventListener, GridFilterModel, gridPreferencePanelStateSelector, GridRowParams, GridSelectionModel, GridToolbarColumnsButton, GridToolbarContainer, GridToolbarDensitySelector, GridToolbarExportContainer, GridToolbarFilterButton, MuiEvent, useGridApiContext, useGridApiEventHandler, useGridSelector} from "@mui/x-data-grid-pro";
import React, {useEffect, useRef, useState} from "react";
import {useNavigate, Link} from "react-router-dom";
import Widget, {AddNewRecordButton, LabelComponent} from "qqq/components/widgets/Widget";
import DataGridUtils from "qqq/utils/DataGridUtils";
@ -48,12 +48,15 @@ const qController = Client.getInstance();
function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element
{
const instance = useRef({timer: null});
const [rows, setRows] = useState([]);
const [records, setRecords] = useState([] as QRecord[])
const [columns, setColumns] = useState([]);
const [allColumns, setAllColumns] = useState([])
const [csv, setCsv] = useState(null as string);
const [fileName, setFileName] = useState(null as string);
const [gridMouseDownX, setGridMouseDownX] = useState(0);
const [gridMouseDownY, setGridMouseDownY] = useState(0);
const navigate = useNavigate();
useEffect(() =>
@ -196,19 +199,44 @@ function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element
}
/////////////////////////////////////////////////////////////////
// if a grid preference window is open, ignore and reset timer //
/////////////////////////////////////////////////////////////////
const handleRowClick = (params: GridRowParams, event: MuiEvent<React.MouseEvent>, details: GridCallbackDetails) =>
{
(async () =>
{
const qInstance = await qController.loadMetaData()
const tablePath = qInstance.getTablePathByName(data.childTableMetaData.name)
let tablePath = qInstance.getTablePathByName(data.childTableMetaData.name)
if(tablePath)
{
navigate(`${tablePath}/${params.id}`);
tablePath = `${tablePath}/${params.id}`;
DataGridUtils.handleRowClick(tablePath, event, gridMouseDownX, gridMouseDownY, navigate, instance);
}
})();
};
function CustomToolbar()
{
const handleMouseDown: GridEventListener<"cellMouseDown"> = ( params, event, details ) =>
{
setGridMouseDownX(event.clientX);
setGridMouseDownY(event.clientY);
clearTimeout(instance.current.timer);
};
const handleDoubleClick: GridEventListener<"rowDoubleClick"> = (event: any) =>
{
clearTimeout(instance.current.timer);
};
const apiRef = useGridApiContext();
useGridApiEventHandler(apiRef, "cellMouseDown", handleMouseDown);
useGridApiEventHandler(apiRef, "rowDoubleClick", handleDoubleClick);
return (<GridToolbarContainer />);
}
return (
<Widget
@ -232,7 +260,9 @@ function RecordGridWidget({widgetMetaData, data}: Props): JSX.Element
getRowClassName={(params) => (params.indexRelativeToCurrentPage % 2 === 0 ? "even" : "odd")}
onRowClick={handleRowClick}
// getRowHeight={() => "auto"} // maybe nice? wraps values in cells...
// components={{Toolbar: CustomToolbar, Pagination: CustomPagination, LoadingOverlay: Loading}}
components={{
Toolbar: CustomToolbar
}}
// pinnedColumns={pinnedColumns}
// onPinnedColumnsChange={handlePinnedColumnsChange}
// pagination

View File

@ -903,37 +903,13 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
return;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// strategy for when to trigger or not trigger a row click: //
// To avoid a drag-event that highlighted text in a cell: //
// - we capture the x & y upon mouse-down - then compare them in this method (which fires when the mouse is up) //
// if they are more than 5 pixels away from the mouse-down, then assume it's a drag, not a click. //
// - avoid clicking the row upon double-click, by setting a 500ms timer here - and in the onDoubleClick handler, //
// cancelling the timer. //
// - also avoid a click, then click-again-and-start-dragging, by always cancelling the timer in mouse-down. //
// All in, these seem to have good results - the only downside being the half-second delay... //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const diff = Math.max(Math.abs(event.clientX - gridMouseDownX), Math.abs(event.clientY - gridMouseDownY));
if (diff < 5)
let id = encodeURIComponent(params.id);
if (table.primaryKeyField !== "id")
{
console.log("clearing timeout");
clearTimeout(instance.current.timer);
instance.current.timer = setTimeout(() =>
{
if (table.primaryKeyField !== "id")
{
navigate(`${metaData.getTablePathByName(tableName)}/${encodeURIComponent(params.row[tableMetaData.primaryKeyField])}`);
}
else
{
navigate(`${metaData.getTablePathByName(tableName)}/${encodeURIComponent(params.id)}`);
}
}, 100);
}
else
{
console.log(`row-click mouse-up happened ${diff} x or y pixels away from the mouse-down - so not considering it a click.`);
id = encodeURIComponent(params.row[tableMetaData.primaryKeyField]);
}
const tablePath = `${metaData.getTablePathByName(table.name)}/${id}`;
DataGridUtils.handleRowClick(tablePath, event, gridMouseDownX, gridMouseDownY, navigate, instance);
};

View File

@ -25,10 +25,10 @@ import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QField
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
import {GridColDef, GridFilterItem, GridRowsProp} from "@mui/x-data-grid-pro";
import {GridCallbackDetails, GridColDef, GridFilterItem, GridRowParams, GridRowsProp, MuiEvent} from "@mui/x-data-grid-pro";
import {GridFilterOperator} from "@mui/x-data-grid/models/gridFilterOperator";
import React from "react";
import {Link} from "react-router-dom";
import React, {useRef, useState} from "react";
import {Link, NavigateFunction, useNavigate} from "react-router-dom";
import {buildQGridPvsOperators, QGridBlobOperators, QGridBooleanOperators, QGridNumericOperators, QGridStringOperators} from "qqq/pages/records/query/GridFilterOperators";
import ValueUtils from "qqq/utils/qqq/ValueUtils";
@ -81,6 +81,36 @@ const QGridDateTimeOperators = [
export default class DataGridUtils
{
/*******************************************************************************
**
*******************************************************************************/
public static handleRowClick = (path: string, event: MuiEvent<React.MouseEvent>, gridMouseDownX: number, gridMouseDownY: number, navigate: NavigateFunction, instance: any) =>
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// strategy for when to trigger or not trigger a row click: //
// To avoid a drag-event that highlighted text in a cell: //
// - we capture the x & y upon mouse-down - then compare them in this method (which fires when the mouse is up) //
// if they are more than 5 pixels away from the mouse-down, then assume it's a drag, not a click. //
// - avoid clicking the row upon double-click, by setting a 500ms timer here - and in the onDoubleClick handler, //
// cancelling the timer. //
// - also avoid a click, then click-again-and-start-dragging, by always cancelling the timer in mouse-down. //
// All in, these seem to have good results - the only downside being the half-second delay... //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const diff = Math.max(Math.abs(event.clientX - gridMouseDownX), Math.abs(event.clientY - gridMouseDownY));
if (diff < 5)
{
console.log("clearing timeout");
clearTimeout(instance.current.timer);
instance.current.timer = setTimeout(() =>
{
navigate(path);
}, 100);
}
else
{
console.log(`row-click mouse-up happened ${diff} x or y pixels away from the mouse-down - so not considering it a click.`);
}
}
/*******************************************************************************
**