diff --git a/src/index.tsx b/src/index.tsx index 9e05703c..b9ed1275 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,7 +6,7 @@ import './test/theming-test.scss'; import { config, enablePinnedToBodyConfig, disabledInitialFocusLocationConfig, enableAdditionalContentConfig, enableAdditionalContentWithFlexRowConfig, enableSymetric, enableTopLeftResponsiveSticky, enableTopLeftResponsiveStickyPinnedToBody, - enableBottomRightResponsiveSticky, enableBottomRightResponsiveStickyPinnedToBody, enableSpannedCells, disableVirtualScrolling + enableBottomRightResponsiveSticky, enableBottomRightResponsiveStickyPinnedToBody, enableSpannedCells, disableVirtualScrolling, errorHandler } from './test/testEnvConfig'; let component = ; ExtTestGrid.displayName = 'DisabledVirtualScrolling'; break; + case '/onErrorHandler': + component = ; + ExtTestGrid.displayName = 'onErrorHandler'; + break; default: break; } diff --git a/src/lib/Components/ErrorBoundary.tsx b/src/lib/Components/ErrorBoundary.tsx index 5e6e0579..1197b4a4 100644 --- a/src/lib/Components/ErrorBoundary.tsx +++ b/src/lib/Components/ErrorBoundary.tsx @@ -1,4 +1,5 @@ -import React, { Component, ErrorInfo } from 'react'; +import React, { Component, ErrorInfo } from "react"; +import { GridErrorEventHandler } from "../Model/PublicModel"; interface ErrorBoundaryState { error?: Error; @@ -6,7 +7,7 @@ interface ErrorBoundaryState { hasError: boolean; } -export class ErrorBoundary extends Component, ErrorBoundaryState> { +export class ErrorBoundary extends Component & { onError?: GridErrorEventHandler}, ErrorBoundaryState> { state: ErrorBoundaryState = { hasError: false, @@ -22,15 +23,20 @@ export class ErrorBoundary extends Component, ErrorBound render(): React.ReactNode { const { hasError, errorInfo, error } = this.state; - if (hasError) { - return (<> -

{error?.message}



-
- {error?.stack} - {errorInfo?.componentStack} -
- ) + const errorHandlerResult = this.props.onError?.({ error, errorInfo } as { error: Error; errorInfo: ErrorInfo }); + return errorHandlerResult ? ( + errorHandlerResult + ) : ( + <> +

{error?.message}


+
+
+ {error?.stack} + {errorInfo?.componentStack} +
+ + ); } else { return this.props.children; } diff --git a/src/lib/Components/GridRenderer.tsx b/src/lib/Components/GridRenderer.tsx index 858a13be..9dab532c 100644 --- a/src/lib/Components/GridRenderer.tsx +++ b/src/lib/Components/GridRenderer.tsx @@ -6,13 +6,13 @@ import { useReactGridState } from './StateProvider'; import { isBrowserFirefox } from '../Functions/firefox'; export const GridRenderer: React.FC = ({ eventHandlers, children }) => { - const { cellMatrix, props } = useReactGridState(); + const { cellMatrix, props, onError } = useReactGridState(); const sharedStyles = { width: props?.enableFullWidthHeader ? '100%' : cellMatrix.width, height: cellMatrix.height, }; return ( - +
{ diff --git a/src/lib/Model/PublicModel.ts b/src/lib/Model/PublicModel.ts index 58d283e3..0353a998 100644 --- a/src/lib/Model/PublicModel.ts +++ b/src/lib/Model/PublicModel.ts @@ -11,6 +11,7 @@ import { } from './../CellTemplates'; import { Range } from './Range'; +import { ErrorInfo, ReactNode } from "react"; /** * `Range` is a class. This class represents a rectangular area with a width, height, upper-left position, and lower-right position. @@ -27,6 +28,9 @@ export type SelectionMode = | 'column' | 'range' + +export type GridErrorEventHandler = ({error, errorInfo}:{error: Error, errorInfo: ErrorInfo}) => ReactNode | undefined | void | null; + /** * `ReactGrid`'s component props * @@ -224,6 +228,8 @@ export interface ReactGridProps { * @returns {boolean} Return `true` to allow droping column at specific column */ readonly canReorderRows?: (targetRowId: Id, rowIds: Id[], dropPosition: DropPosition) => boolean; + + readonly onError?: GridErrorEventHandler } diff --git a/src/lib/Model/State.ts b/src/lib/Model/State.ts index c8898dd4..ca502bf7 100644 --- a/src/lib/Model/State.ts +++ b/src/lib/Model/State.ts @@ -1,4 +1,4 @@ -import { CellTemplates, Cell, ReactGridProps, Compatible, Highlight, CellChange, Id, SelectionMode } from './PublicModel'; +import { CellTemplates, Cell, ReactGridProps, Compatible, Highlight, CellChange, Id, SelectionMode, GridErrorEventHandler } from './PublicModel'; import { isBrowserIE } from '../Functions/internetExplorer'; import { isBrowserEdge } from '../Functions/microsoftEdge'; import { DefaultBehavior } from '../Behaviors/DefaultBehavior'; @@ -64,6 +64,7 @@ export interface State = (props) => { {render && = (props) => { onSelectionChanged={handleSelectionChanged} onSelectionChanging={handleSelectionChanging} moveRightOnEnter={config.moveRightOnEnter} + onError={config.onError} />} {config.additionalContent &&
@@ -673,6 +674,9 @@ export const TestGridOptionsSelect: React.FC = () => { + ); diff --git a/src/test/testEnvConfig.ts b/src/test/testEnvConfig.ts index 820510a7..0b488f38 100644 --- a/src/test/testEnvConfig.ts +++ b/src/test/testEnvConfig.ts @@ -1,5 +1,5 @@ import React from 'react'; -import { CellLocation, Highlight, TextLabels } from '../core'; +import { CellLocation, Highlight, Row, TextLabels } from "../core"; /** * All of the properties that cypress tests files can read @@ -240,5 +240,12 @@ export interface TestConfig { fillViewport?: boolean; withDivComponentStyles: React.CSSProperties; + onError?: (context: {error:Error, errorInfo:React.ErrorInfo}) => void | React.ReactNode | undefined; + rowsOverride?: Row[] +} +export const errorHandler = { + ...config, + onError: (context: {error:Error, errorInfo:React.ErrorInfo}): string => `This could be custom: ${context?.error?.message}`, + rowsOverride: [{ rowId: 1, cells: [{type:'text'}] }], //it causes grid to throw missing 'text' property }