block-edit.js
3 weeks ago
block-form.js
2 months ago
block-placeholder.js
6 months ago
block-preview.js
6 months ago
block-toolbar-fields.js
2 months ago
error-boundary.js
2 months ago
inline-editing-toolbar.js
6 months ago
jsx-parser.js
2 months ago
popover-wrapper.js
2 months ago
error-boundary.js
133 lines
| 1 | import { Component, createContext } from '@wordpress/element'; |
| 2 | import { BlockPlaceholder } from './block-placeholder'; |
| 3 | |
| 4 | // Create context outside the class |
| 5 | export const ErrorBoundaryContext = createContext( null ); |
| 6 | |
| 7 | // Initial state constant |
| 8 | const initialState = { didCatch: false, error: null }; |
| 9 | |
| 10 | // Error Boundary Component |
| 11 | export class ErrorBoundary extends Component { |
| 12 | constructor( props ) { |
| 13 | super( props ); |
| 14 | this.resetErrorBoundary = this.resetErrorBoundary.bind( this ); |
| 15 | this.state = initialState; |
| 16 | } |
| 17 | |
| 18 | static getDerivedStateFromError( error ) { |
| 19 | return { didCatch: true, error: error }; |
| 20 | } |
| 21 | |
| 22 | resetErrorBoundary() { |
| 23 | const { error } = this.state; |
| 24 | if ( error !== null ) { |
| 25 | // Collect all arguments passed to reset |
| 26 | const args = Array.from( arguments ); |
| 27 | |
| 28 | // Call optional onReset callback with context |
| 29 | if ( this.props.onReset ) { |
| 30 | this.props.onReset( { |
| 31 | args: args, |
| 32 | reason: 'imperative-api', |
| 33 | } ); |
| 34 | } |
| 35 | |
| 36 | this.setState( initialState ); |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | componentDidCatch( error, errorInfo ) { |
| 41 | if ( this.props.onError ) { |
| 42 | this.props.onError( error, errorInfo ); |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | componentDidUpdate( prevProps, prevState ) { |
| 47 | const { didCatch } = this.state; |
| 48 | const { resetKeys } = this.props; |
| 49 | |
| 50 | // Auto-reset if resetKeys prop changed |
| 51 | if ( |
| 52 | didCatch && |
| 53 | prevState.error !== null && |
| 54 | hasResetKeysChanged( prevProps.resetKeys, resetKeys ) |
| 55 | ) { |
| 56 | if ( this.props.onReset ) { |
| 57 | this.props.onReset( { |
| 58 | next: resetKeys, |
| 59 | prev: prevProps.resetKeys, |
| 60 | reason: 'keys', |
| 61 | } ); |
| 62 | } |
| 63 | this.setState( initialState ); |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | render() { |
| 68 | const { children, fallbackRender, FallbackComponent, fallback } = |
| 69 | this.props; |
| 70 | const { didCatch, error } = this.state; |
| 71 | |
| 72 | let content = children; |
| 73 | |
| 74 | if ( didCatch ) { |
| 75 | const errorProps = { |
| 76 | error: error, |
| 77 | resetErrorBoundary: this.resetErrorBoundary, |
| 78 | }; |
| 79 | |
| 80 | if ( typeof fallbackRender === 'function' ) { |
| 81 | content = fallbackRender( errorProps ); |
| 82 | } else if ( FallbackComponent ) { |
| 83 | content = <FallbackComponent { ...errorProps } />; |
| 84 | } else if ( fallback !== undefined ) { |
| 85 | content = fallback; |
| 86 | } else { |
| 87 | throw error; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | return ( |
| 92 | <ErrorBoundaryContext.Provider |
| 93 | value={ { |
| 94 | didCatch, |
| 95 | error, |
| 96 | resetErrorBoundary: this.resetErrorBoundary, |
| 97 | } } |
| 98 | > |
| 99 | { content } |
| 100 | </ErrorBoundaryContext.Provider> |
| 101 | ); |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | // Helper function to check if reset keys changed |
| 106 | function hasResetKeysChanged( prevKeys = [], nextKeys = [] ) { |
| 107 | return ( |
| 108 | prevKeys.length !== nextKeys.length || |
| 109 | prevKeys.some( ( key, index ) => ! Object.is( key, nextKeys[ index ] ) ) |
| 110 | ); |
| 111 | } |
| 112 | |
| 113 | export const BlockPreviewErrorFallback = ( { |
| 114 | setBlockFormModalOpen, |
| 115 | blockLabel, |
| 116 | error, |
| 117 | } ) => { |
| 118 | let errorMessage = null; |
| 119 | |
| 120 | if ( error ) { |
| 121 | acf.debug( 'Block preview error:', error ); |
| 122 | errorMessage = acf.__( 'Error previewing block v3' ); |
| 123 | } |
| 124 | |
| 125 | return ( |
| 126 | <BlockPlaceholder |
| 127 | setBlockFormModalOpen={ setBlockFormModalOpen } |
| 128 | blockLabel={ blockLabel } |
| 129 | instructions={ errorMessage } |
| 130 | /> |
| 131 | ); |
| 132 | }; |
| 133 |