update react-data-grid, fix side drawer navigation

This commit is contained in:
Sidney Alcantara
2021-09-08 16:01:55 +10:00
parent 812a48e4c5
commit 0a44804dfb
39 changed files with 233 additions and 159 deletions

View File

@@ -42,7 +42,7 @@
"react": "^17.0.2",
"react-beautiful-dnd": "^13.0.0",
"react-color": "^2.17.3",
"react-data-grid": "7.0.0-canary.30",
"react-data-grid": "^7.0.0-beta.5",
"react-div-100vh": "^0.6.0",
"react-dnd": "^11.1.3",
"react-dnd-html5-backend": "^11.1.3",

View File

@@ -2,13 +2,19 @@ import React, { useState } from "react";
import clsx from "clsx";
import { makeStyles, createStyles } from "@material-ui/styles";
import { Tooltip, TooltipProps, Button, ButtonProps } from "@material-ui/core";
import {
Tooltip,
TooltipProps,
Typography,
Button,
ButtonProps,
} from "@material-ui/core";
const useStyles = makeStyles((theme) =>
createStyles({
tooltip: {
backgroundColor: theme.palette.background.default,
boxShadow: theme.shadows[2],
boxShadow: theme.shadows[8],
...theme.typography.body2,
color: theme.palette.text.primary,
@@ -27,42 +33,42 @@ const useStyles = makeStyles((theme) =>
cursor: "default",
display: "grid",
gridTemplateColumns: "40px auto",
gap: theme.spacing(1, 2),
gridTemplateColumns: "48px auto",
gap: theme.spacing(1, 1.5),
},
emoji: {
fontSize: `${40 / 16}rem`,
fontWeight: 400,
fontFamily:
"apple color emoji, segoe ui emoji, noto color emoji, android emoji, emojisymbols, emojione mozilla, twemoji mozilla, segoe ui symbol",
icon: {
marginTop: theme.spacing(-0.5),
fontSize: `${48 / 16}rem`,
},
message: {
alignSelf: "center",
},
dismissButton: {
marginLeft: theme.spacing(-1),
gridColumn: 2,
justifySelf: "flex-start",
},
})
);
export interface IRichTooltipProps extends Partial<TooltipProps> {
export interface IRichTooltipProps
extends Partial<Omit<TooltipProps, "title">> {
render: (props: {
openTooltip: () => void;
closeTooltip: () => void;
toggleTooltip: () => void;
}) => TooltipProps["children"];
emoji?: React.ReactNode;
message: React.ReactNode;
icon?: React.ReactNode;
title: React.ReactNode;
message?: React.ReactNode;
dismissButtonText?: React.ReactNode;
dismissButtonProps?: Partial<ButtonProps>;
}
export default function RichTooltip({
render,
emoji,
icon,
title,
message,
dismissButtonText,
dismissButtonProps,
@@ -86,11 +92,16 @@ export default function RichTooltip({
classes={{ tooltip: classes.tooltip, arrow: classes.arrow }}
title={
<div className={classes.grid} onClick={closeTooltip}>
<span className={classes.emoji}>{emoji}</span>
<span className={classes.icon}>{icon}</span>
<div className={classes.message}>{message}</div>
<div className={classes.message}>
<Typography variant="subtitle2" gutterBottom>
{title}
</Typography>
<Typography>{message}</Typography>
</div>
{dismissButtonText && (
{dismissButtonText ? (
<Button
{...dismissButtonProps}
onClick={closeTooltip}
@@ -101,6 +112,14 @@ export default function RichTooltip({
>
{dismissButtonText}
</Button>
) : (
<Typography
variant="caption"
color="text.disabled"
className={classes.dismissButton}
>
Click to dismiss
</Typography>
)}
</div>
}

View File

@@ -45,7 +45,12 @@ export default function SideDrawer() {
setCell!((cell) => ({ column: cell!.column, row }));
const idx = tableState?.columns[cell!.column]?.index;
dataGridRef?.current?.selectCell({ rowIdx: row, idx });
console.log(
"selectCell",
{ rowIdx: cell!.row, idx },
dataGridRef?.current?.selectCell
);
dataGridRef?.current?.selectCell({ rowIdx: row, idx }, false);
};
const [urlDocState, dispatchUrlDoc] = useDoc({});

View File

@@ -1,45 +1,35 @@
import clsx from "clsx";
import { styled } from "@material-ui/core/styles";
import { Box } from "@material-ui/core";
import ErrorIcon from "@material-ui/icons/ErrorOutline";
import WarningIcon from "@material-ui/icons/WarningAmber";
import { makeStyles, createStyles } from "@material-ui/styles";
import RichTooltip from "components/RichTooltip";
const useStyles = makeStyles((theme) =>
createStyles({
root: {
"&&": {
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
padding: "var(--cell-padding)",
const Root = styled(Box)({
width: "100%",
height: "100%",
padding: "var(--cell-padding)",
position: "relative",
overflow: "hidden",
contain: "strict",
display: "flex",
alignItems: "center",
},
},
overflow: "hidden",
contain: "strict",
display: "flex",
alignItems: "center",
});
isInvalid: {
boxShadow: `inset 0 0 0 2px ${theme.palette.error.main}`,
},
const Dot = styled("div")(({ theme }) => ({
position: "absolute",
right: -5,
top: "50%",
transform: "translateY(-50%)",
zIndex: 1,
dot: {
position: "absolute",
right: -5,
top: "50%",
transform: "translateY(-50%)",
zIndex: 1,
width: 12,
height: 12,
width: 12,
height: 12,
borderRadius: "50%",
backgroundColor: theme.palette.error.main,
},
})
);
borderRadius: "50%",
backgroundColor: theme.palette.error.main,
}));
export interface ICellValidationProps
extends React.DetailedHTMLProps<
@@ -55,13 +45,9 @@ export default function CellValidation({
value,
required,
validationRegex,
className,
children,
...props
}: ICellValidationProps) {
const classes = useStyles();
}: // ...props
ICellValidationProps) {
const isInvalid = validationRegex && !new RegExp(validationRegex).test(value);
const isMissing = required && value === undefined;
@@ -69,20 +55,21 @@ export default function CellValidation({
return (
<>
<RichTooltip
emoji="⛔️"
message="Invalid data. This row will not be registered to the database until all the required fields are validated."
icon={<ErrorIcon fontSize="inherit" color="error" />}
title="Invalid Data"
message="This row will not be saved until all the required fields contain valid data"
placement="right"
render={({ openTooltip }) => (
<div className={classes.dot} onClick={openTooltip} />
)}
render={({ openTooltip }) => <Dot onClick={openTooltip} />}
/>
<div
{...props}
className={clsx(classes.root, classes.isInvalid, className)}
<Root
// {...props}
sx={{
boxShadow: (theme) => `inset 0 0 0 2px ${theme.palette.error.main}`,
}}
>
{children}
</div>
</Root>
</>
);
@@ -90,26 +77,29 @@ export default function CellValidation({
return (
<>
<RichTooltip
emoji="⚠️"
message="Required field. This row will not be registered to the database until all the required fields contain valid data."
icon={<WarningIcon fontSize="inherit" color="warning" />}
title="Required Field"
message="This row will not be saved until all the required fields contain valid data"
placement="right"
render={({ openTooltip }) => (
<div className={classes.dot} onClick={openTooltip} />
)}
render={({ openTooltip }) => <Dot onClick={openTooltip} />}
/>
<div
{...props}
className={clsx(classes.root, classes.isInvalid, className)}
<Root
// {...props}
sx={{
boxShadow: (theme) => `inset 0 0 0 2px ${theme.palette.error.main}`,
}}
>
{children}
</div>
</Root>
</>
);
return (
<div {...props} className={clsx(classes.root, className)}>
<Root
// {...props}
>
{children}
</div>
</Root>
);
}

View File

@@ -2,7 +2,7 @@ import { useRef } from "react";
import clsx from "clsx";
import { HeaderRendererProps } from "react-data-grid";
import { useDrag, useDrop, DragObjectWithType } from "react-dnd";
import { useCombinedRefs } from "react-data-grid/lib/hooks";
import useCombinedRefs from "hooks/useCombinedRefs";
import { makeStyles, createStyles } from "@material-ui/styles";
import {
@@ -36,9 +36,8 @@ const useStyles = makeStyles((theme) =>
cursor: "move",
margin: theme.spacing(0, -1.5),
padding: theme.spacing(0, 0.5, 0, 1),
width: `calc(100% + ${theme.spacing(1.5 * 2)})`,
width: "100%",
},
isDragging: { opacity: 0.5 },
isOver: {
@@ -153,20 +152,16 @@ export default function DraggableHeaderRenderer<R>({
});
};
const isSorted = orderBy?.[0]?.key === (column.key as string);
const isSorted = orderBy?.[0]?.key === column.key;
const isAsc = isSorted && orderBy?.[0]?.direction === "asc";
const handleSortClick = () => {
if (isAsc) {
const ordering: TableOrder = [
{ key: column.key as string, direction: "desc" },
];
const ordering: TableOrder = [{ key: column.key, direction: "desc" }];
tableActions.table.orderBy(ordering);
} else {
const ordering: TableOrder = [
{ key: column.key as string, direction: "asc" },
];
const ordering: TableOrder = [{ key: column.key, direction: "asc" }];
tableActions.table.orderBy(ordering);
}
};
@@ -184,13 +179,13 @@ export default function DraggableHeaderRenderer<R>({
wrap="nowrap"
onContextMenu={handleOpenMenu}
>
{column.width > 140 && (
{(column.width as number) > 140 && (
<Tooltip
title={
<>
Click to copy field key:
<br />
<b>{column.key as string}</b>
<b>{column.key}</b>
</>
}
enterDelay={1000}
@@ -199,7 +194,7 @@ export default function DraggableHeaderRenderer<R>({
<Grid
item
onClick={() => {
navigator.clipboard.writeText(column.key as string);
navigator.clipboard.writeText(column.key);
}}
>
{column.editable === false ? (
@@ -215,7 +210,7 @@ export default function DraggableHeaderRenderer<R>({
<Tooltip
title={
<Typography className={classes.columnName} color="inherit">
{column.name}
{column.name as string}
</Typography>
}
enterDelay={1000}
@@ -253,7 +248,7 @@ export default function DraggableHeaderRenderer<R>({
component="div"
color="inherit"
>
{column.name}
{column.name as string}
</Typography>
</Tooltip>
</Grid>
@@ -288,7 +283,7 @@ export default function DraggableHeaderRenderer<R>({
<IconButton
size="small"
className={classes.dropdownButton}
aria-label={`Show ${column.name} column dropdown`}
aria-label={`Show ${column.name as string} column dropdown`}
color="inherit"
onClick={handleOpenMenu}
ref={buttonRef}
@@ -308,7 +303,7 @@ export default function DraggableHeaderRenderer<R>({
// cursor: 'move'
// }}
// >
// {props.column.name}
// {props.column.name as string}
// </div>
// );
}

View File

@@ -291,7 +291,7 @@ export default function ColumnMenu() {
{getFieldProp("icon", column.type)}
</ListItemIcon>
<ListItemText
primary={column.name}
primary={column.name as string}
secondary={
<>
Key: <span style={{ userSelect: "all" }}>{column.key}</span>

View File

@@ -13,10 +13,11 @@ const useStyles = makeStyles((theme) =>
border: "none",
".rdg.rdg &": { padding: theme.spacing(0, 0.75) },
position: "relative",
"&::before": {
content: "''",
display: "block",
width: 46,
width: 43,
height: "100%",
position: "absolute",

View File

@@ -1,4 +1,4 @@
import { Stack, Button } from "@material-ui/core";
import { Stack, Button, Typography } from "@material-ui/core";
import { isCollectionGroup } from "utils/fns";
import AddRowIcon from "assets/icons/AddRow";
@@ -105,6 +105,15 @@ export default function TableHeader() {
{/* Spacer */} <div />
<HiddenFields />
<Filters />
{/* Spacer */} <div />
<Typography
variant="body2"
color="text.disabled"
display="block"
style={{ userSelect: "none" }}
>
Loaded {tableState.rows.length} rows
</Typography>
<div style={{ flexGrow: 1, minWidth: 64 }} />
<RowHeight />
{/* Spacer */} <div />

View File

@@ -29,7 +29,7 @@ export default function withSideDrawerEditor(
<HeavyCell
{...(props as any)}
value={getCellValue(row, column.key)}
name={column.name}
name={column.name as string}
type={(column as any).type}
docRef={props.row.ref}
onSubmit={() => {}}

View File

@@ -13,10 +13,11 @@ const useStyles = makeStyles((theme) =>
createStyles({
"@global": {
".final-column-cell": {
".rdg .rdg-cell&": {
".rdg.rdg .rdg-cell&": {
backgroundColor: "var(--header-background-color)",
borderColor: "var(--header-background-color)",
color: theme.palette.text.disabled,
padding: "var(--cell-padding)",
},
},
},

View File

@@ -1,14 +1,14 @@
import React, { useEffect, useRef, useMemo, useState } from "react";
import _orderBy from "lodash/orderBy";
import _find from "lodash/find";
import _findIndex from "lodash/findIndex";
import _difference from "lodash/difference";
import _get from "lodash/get";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import "react-data-grid/dist/react-data-grid.css";
// import "react-data-grid/dist/react-data-grid.css";
import DataGrid, {
Column,
SelectColumn as _SelectColumn,
@@ -84,7 +84,11 @@ export default function Table() {
return null;
},
...column,
width: column.width ? (column.width > 380 ? 380 : column.width) : 150,
width: (column.width as number)
? (column.width as number) > 380
? 380
: (column.width as number)
: 150,
}))
.filter((column) => !userDocHiddenFields.includes(column.key));
@@ -95,7 +99,7 @@ export default function Table() {
{
isNew: true,
key: "new",
name: "Add column",
name: "Add Column",
type: FieldType.last,
index: _columns.length ?? 0,
width: 204,
@@ -119,7 +123,7 @@ export default function Table() {
tableState?.rows.map((row) =>
columns.reduce(
(acc, currColumn) => {
if ((currColumn.key as string).includes(".")) {
if (currColumn.key.includes(".")) {
return {
...acc,
[currColumn.key]: _get(row, currColumn.key),
@@ -208,29 +212,29 @@ export default function Table() {
});
setSelectedRowsSet(newSelectedSet);
}}
onRowsChange={() => {
//console.log('onRowsChange',rows)
}}
onFill={(e) => {
console.log("onFill", e);
const { columnKey, sourceRow, targetRows } = e;
if (updateCell)
targetRows.forEach((row) =>
updateCell(row.ref, columnKey, sourceRow[columnKey])
);
return [];
}}
// onRowsChange={() => {
//console.log('onRowsChange',rows)
// }}
// TODO: onFill={(e) => {
// console.log("onFill", e);
// const { columnKey, sourceRow, targetRows } = e;
// if (updateCell)
// targetRows.forEach((row) =>
// updateCell(row.ref, columnKey, sourceRow[columnKey])
// );
// return [];
// }}
onPaste={(e) => {
const copiedValue = e.sourceRow[e.sourceColumnKey];
if (updateCell) {
updateCell(e.targetRow.ref, e.targetColumnKey, copiedValue);
}
}}
onRowClick={(rowIdx, column) => {
onRowClick={(row, column) => {
if (sideDrawerRef?.current) {
sideDrawerRef.current.setCell({
row: rowIdx,
column: column.key as string,
row: _findIndex(tableState.rows, { id: row.id }),
column: column.key,
});
}
}}

View File

@@ -61,10 +61,11 @@ export const useStyles = makeStyles((theme) =>
"& .rdg-cell": {
display: "flex",
alignItems: "center",
padding: "var(--cell-padding)",
padding: 0,
overflow: "visible",
contain: "none",
position: "relative",
},
"& .rdg-cell-frozen-last": {

View File

@@ -120,7 +120,7 @@ export default function ActionFab({
: needsConfirmation
? () =>
requestConfirmation({
title: `${column.name} Confirmation`,
title: `${column.name as string} Confirmation`,
body: (actionState === "undo" && config.undoConfirmation
? config.undoConfirmation
: config.confirmation

View File

@@ -52,7 +52,7 @@ export default function ParamsDialog({
return (
<FormDialog
onClose={handleClose}
title={`${column.name}`}
title={`${column.name as string}`}
fields={fields}
values={{}}
onSubmit={handleRun}

View File

@@ -59,7 +59,7 @@ export default function Checkbox({
color="success"
/>
}
label={column.name}
label={column.name as string}
labelPlacement="start"
classes={{ root: classes.formControlLabel, label: classes.label }}
/>

View File

@@ -68,7 +68,7 @@ export default function Checkbox({
return (
<FormControlLabel
control={component}
label={column.name}
label={column.name as string}
labelPlacement="start"
// className="cell-collapse-padding"
classes={{ root: classes.root, label: classes.label }}

View File

@@ -18,7 +18,7 @@ export default function Email({
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
placeholder={column.name as string}
onChange={onChange}
onBlur={onBlur}
value={value}

View File

@@ -47,6 +47,7 @@ const useStyles = makeStyles((theme) =>
chip: {
width: "100%",
height: 24,
display: "flex",
},
endButtonContainer: {},
@@ -78,7 +79,7 @@ export default function File_({
if (file) {
upload({
docRef: row.ref,
fieldName: column.key as string,
fieldName: column.key,
files: [file],
previousValue: value,
onComplete: (newValue) => {
@@ -121,7 +122,7 @@ export default function File_({
<input {...getInputProps()} />
<div className={classes.chipList}>
<Grid container spacing={0.5} wrap="nowrap">
<Grid container spacing={0.5} wrap="nowrap" style={{ height: "100%" }}>
{Array.isArray(value) &&
value.map((file: FileValue) => (
<Grid

View File

@@ -132,7 +132,7 @@ export default function Image_({
if (imageFile) {
upload({
docRef: row.ref,
fieldName: column.key as string,
fieldName: column.key,
files: [imageFile],
previousValue: value,
onComplete: (newValue) => {
@@ -184,7 +184,7 @@ export default function Image_({
<input {...getInputProps()} />
<div className={classes.imglistContainer}>
<Grid container spacing={1} wrap="nowrap">
<Grid container spacing={0.5} wrap="nowrap">
{Array.isArray(value) &&
value.map((file: FileValue) => (
<Grid item key={file.downloadURL}>

View File

@@ -18,7 +18,7 @@ export default function LongText({
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
placeholder={column.name as string}
onChange={onChange}
onBlur={onBlur}
value={value}

View File

@@ -22,8 +22,8 @@ export default function MultiSelect({
multiple
freeText={config.freeText}
disabled={disabled}
label={column.name}
labelPlural={column.name}
label={column.name as string}
labelPlural={column.name as string}
TextFieldProps={{
style: { display: "none" },
SelectProps: {

View File

@@ -20,7 +20,7 @@ export default function Number_({
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
placeholder={column.name as string}
onChange={handleChange}
onBlur={onBlur}
value={value}

View File

@@ -47,7 +47,7 @@ export default function Percentage({
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
placeholder={column.name as string}
onChange={handleChange}
onBlur={onBlur}
value={typeof value === "number" ? value * 100 : value}

View File

@@ -18,7 +18,7 @@ export default function Phone({
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
placeholder={column.name as string}
onChange={onChange}
onBlur={onBlur}
value={value}

View File

@@ -37,7 +37,7 @@ export default function Rating({
render={({ onChange, value }) => (
<Grid container alignItems="center" className={fieldClasses.root}>
<MuiRating
name={column.key as string}
name={column.key}
id={`sidedrawer-field-${column.key}`}
value={typeof value === "number" ? value : 0}
disabled={disabled}

View File

@@ -29,7 +29,7 @@ export default function Rating({
return (
<MuiRating
name={`${row.id}-${column.key as string}`}
name={`${row.id}-${column.key}`}
value={typeof value === "number" ? value : 0}
onClick={(e) => e.stopPropagation()}
disabled={disabled}

View File

@@ -53,7 +53,7 @@ const useStyles = makeStyles((theme) =>
export default function RichText({ column, value }: IHeavyCellProps) {
const { tableState } = useProjectContext();
const classes = useStyles({
width: column.width,
width: column.width as number,
rowHeight: tableState?.config?.rowHeight ?? 44,
});

View File

@@ -18,7 +18,7 @@ export default function ShortText({
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
placeholder={column.name as string}
onChange={onChange}
onBlur={onBlur}
value={value}

View File

@@ -22,8 +22,8 @@ export default function SingleSelect({
multiple={false}
freeText={config.freeText}
disabled={disabled}
label={column.name}
labelPlural={column.name}
label={column.name as string}
labelPlural={column.name as string}
TextFieldProps={{
style: { display: "none" },
SelectProps: {

View File

@@ -25,7 +25,7 @@ export default function SubTable({
return (
<Grid container wrap="nowrap">
<div className={fieldClasses.root}>
{documentCount} {column.name}: {label}
{documentCount} {column.name as string}: {label}
</div>
<IconButton

View File

@@ -34,7 +34,7 @@ export default function SubTable({ column, row }: IHeavyCellProps) {
className={clsx("cell-collapse-padding", classes.root)}
>
<Grid item xs className={classes.labelContainer}>
{documentCount} {column.name}: {label}
{documentCount} {column.name as string}: {label}
</Grid>
<Grid item>

View File

@@ -15,7 +15,7 @@ export const useSubTableData = (
else return row[curr];
}, "")
: "";
const fieldName = column.key as string;
const fieldName = column.key;
const documentCount: string = row[fieldName]?.count ?? "";
const router = useRouter();

View File

@@ -20,7 +20,7 @@ export default function Url({
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
placeholder={column.name as string}
onChange={onChange}
onBlur={onBlur}
value={value}

View File

@@ -29,7 +29,7 @@ export default function withBasicCell(
>
<BasicCellComponent
value={value}
name={name}
name={name as string}
type={(props.column as any).type as FieldType}
/>
</CellValidation>

View File

@@ -47,7 +47,7 @@ export default function withHeavyCell(
// Declare basicCell here so props can be reused by HeavyCellComponent
const basicCellProps = {
value: localValue,
name: props.column.name,
name: props.column.name as string,
type: (props.column as any).type as FieldType,
};
const basicCell = <BasicCellComponent {...basicCellProps} />;
@@ -67,7 +67,7 @@ export default function withHeavyCell(
const handleSubmit = (value: any) => {
if (updateCell && !readOnly) {
updateCell(props.row.ref, props.column.key as string, value);
updateCell(props.row.ref, props.column.key, value);
setLocalValue(value);
}
};

View File

@@ -72,7 +72,7 @@ export default function withPopoverCell(
const inlineCellRef = useRef<any>(null);
// TODO: Investigate if this still needs to be a state
const value = getCellValue(props.row, props.column.key as string);
const value = getCellValue(props.row, props.column.key);
const [localValue, setLocalValue] = useState(value);
useEffect(() => {
setLocalValue(value);
@@ -81,7 +81,7 @@ export default function withPopoverCell(
// Declare basicCell here so props can be reused by HeavyCellComponent
const basicCellProps = {
value: localValue,
name: props.column.name,
name: props.column.name as string,
type: (props.column as any).type as FieldType,
};
@@ -100,7 +100,7 @@ export default function withPopoverCell(
const handleSubmit = (value: any) => {
if (updateCell && !options?.readOnly) {
updateCell(props.row.ref, props.column.key as string, value);
updateCell(props.row.ref, props.column.key, value);
setLocalValue(value);
}
};

View File

@@ -16,7 +16,7 @@ export interface IFieldConfig {
icon?: React.ReactNode;
description?: string;
setupGuideLink?: string;
TableCell: React.ComponentType<FormatterProps>;
TableCell: React.ComponentType<FormatterProps<any>>;
TableEditor: React.ComponentType<EditorProps<any, any>>;
SideDrawerField: React.ComponentType<ISideDrawerFieldProps>;
settings?: React.ComponentType<ISettingsProps>;

View File

@@ -0,0 +1,43 @@
import { useCallback, Ref } from "react";
// From https://github.com/adazzle/react-data-grid/blob/main/src/hooks/useCombinedRefs.ts
// The MIT License (MIT)
// Original work Copyright (c) 2014 Prometheus Research
// Modified work Copyright 2015 Adazzle
// For the original source code please see https://github.com/prometheusresearch-archive/react-grid
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
export default function useCombinedRefs<T>(...refs: readonly Ref<T>[]) {
return useCallback(
(handle: T | null) => {
for (const ref of refs) {
if (typeof ref === "function") {
ref(handle);
} else if (ref !== null) {
// @ts-expect-error: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31065
ref.current = handle;
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
refs
);
}

View File

@@ -13442,10 +13442,10 @@ react-color@^2.17.3, react-color@^2.19.3:
reactcss "^1.2.0"
tinycolor2 "^1.4.1"
react-data-grid@7.0.0-canary.30:
version "7.0.0-canary.30"
resolved "https://registry.yarnpkg.com/react-data-grid/-/react-data-grid-7.0.0-canary.30.tgz#779cf014abcebc41a4635c22519beb3f183e64c1"
integrity sha512-NxGqaHnjHBWTh2eBCae5bb57+N3UBy9DQLnlg3JUZ1ggRnruXDl9Qgci6Xg2XwLdJBC5i0B0F0MbeKTucgArJA==
react-data-grid@^7.0.0-beta.5:
version "7.0.0-beta.5"
resolved "https://registry.yarnpkg.com/react-data-grid/-/react-data-grid-7.0.0-beta.5.tgz#bc39ce45b7a7f42ebfb66840e0ec1c8619d60f10"
integrity sha512-rtN4wnePrQ80UN6lYF/zUQqVVJMT3HW5bTLx9nR5XOKQiG72cGzX2d2+b+e82vUh23zTFBicEnuWSlN9Fa/83Q==
dependencies:
clsx "^1.1.1"
@@ -13547,6 +13547,11 @@ react-error-overlay@^6.0.9:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
react-fast-compare@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
react-firebaseui@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/react-firebaseui/-/react-firebaseui-5.0.2.tgz#7496bc595454abdd3e1c10612bb3446cb125181a"