UNPKG

@wordpress/editor

Version:
8 lines (7 loc) 9.39 kB
{ "version": 3, "sources": ["../../../src/components/error-boundary/index.js"], "sourcesContent": ["import { Component } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\n// eslint-disable-next-line @wordpress/use-recommended-components -- The fallback UI renders outside the editor's notice system.\nimport { Card, CollapsibleCard, Notice, Stack, Text } from '@wordpress/ui';\nimport { select } from '@wordpress/data';\nimport { useCopyToClipboard } from '@wordpress/compose';\nimport { doAction } from '@wordpress/hooks';\nimport { store as editorStore } from '../../store';\n\nfunction getContent() {\n\ttry {\n\t\t// While `select` in a component is generally discouraged, it is\n\t\t// used here because it (a) reduces the chance of data loss in the\n\t\t// case of additional errors by performing a direct retrieval and\n\t\t// (b) avoids the performance cost associated with unnecessary\n\t\t// content serialization throughout the lifetime of a non-erroring\n\t\t// application.\n\t\treturn select( editorStore ).getEditedPostContent();\n\t} catch {}\n}\n\n// A boundary catches whatever was thrown, which is not always an `Error`.\nfunction getErrorName( error ) {\n\treturn ( error instanceof Error && error.name ) || 'Error';\n}\n\nfunction getErrorMessage( error ) {\n\tif ( typeof error === 'string' && error ) {\n\t\treturn error;\n\t}\n\n\tif ( typeof error?.message === 'string' && error.message ) {\n\t\treturn error.message;\n\t}\n\n\treturn 'An unknown error occurred.';\n}\n\n// The sections of the report, shared by the copied Markdown and the details\n// panel so that the two cannot drift apart. Deliberately untranslated: both\n// are developer-facing, and the report is pasted into a bug report.\nfunction getErrorSections( error, componentStack ) {\n\tconst sections = [\n\t\t{ label: getErrorName( error ), content: getErrorMessage( error ) },\n\t];\n\n\tif ( error?.stack ) {\n\t\tsections.push( {\n\t\t\tlabel: 'Stack',\n\t\t\tcontent: error.stack.trim(),\n\t\t\tpreformatted: true,\n\t\t} );\n\t}\n\n\tif ( componentStack ) {\n\t\tsections.push( {\n\t\t\tlabel: 'Component stack',\n\t\t\tcontent: componentStack.trim(),\n\t\t\tpreformatted: true,\n\t\t} );\n\t}\n\n\tsections.push( {\n\t\tlabel: 'Environment',\n\t\tcontent: `User agent: ${ window.navigator.userAgent }`,\n\t\tpreformatted: true,\n\t} );\n\n\treturn sections;\n}\n\n// Markdown, so the report stays readable as plain text and renders when pasted\n// into a bug report.\nfunction getErrorReport( error, componentStack ) {\n\tconst sections = getErrorSections( error, componentStack ).map(\n\t\t( { label, content, preformatted } ) =>\n\t\t\t`**${ label }**\\n\\n${\n\t\t\t\tpreformatted ? `\\`\\`\\`\\n${ content }\\n\\`\\`\\`` : content\n\t\t\t}`\n\t);\n\n\treturn [ '### Error report', ...sections ].join( '\\n\\n' );\n}\n\nfunction CopyButton( { text, children, variant = 'outline' } ) {\n\tconst ref = useCopyToClipboard( text );\n\treturn (\n\t\t<Notice.ActionButton variant={ variant } ref={ ref }>\n\t\t\t{ children }\n\t\t</Notice.ActionButton>\n\t);\n}\n\nfunction ErrorReport( { error, componentStack } ) {\n\treturn (\n\t\t<Stack\n\t\t\tclassName=\"editor-error-boundary__report\"\n\t\t\tdirection=\"column\"\n\t\t\tgap=\"md\"\n\t\t>\n\t\t\t{ getErrorSections( error, componentStack ).map(\n\t\t\t\t( { label, content } ) => (\n\t\t\t\t\t<Stack key={ label } direction=\"column\" gap=\"xs\">\n\t\t\t\t\t\t<Text variant=\"heading-md\">{ label }</Text>\n\t\t\t\t\t\t<pre className=\"editor-error-boundary__report-section\">\n\t\t\t\t\t\t\t{ content }\n\t\t\t\t\t\t</pre>\n\t\t\t\t\t</Stack>\n\t\t\t\t)\n\t\t\t) }\n\t\t</Stack>\n\t);\n}\n\nfunction ErrorDetails( { error, componentStack } ) {\n\treturn (\n\t\t<CollapsibleCard.Root className=\"editor-error-boundary__details\">\n\t\t\t<CollapsibleCard.Header>\n\t\t\t\t<Card.Title>{ __( 'Error details' ) }</Card.Title>\n\t\t\t</CollapsibleCard.Header>\n\t\t\t<CollapsibleCard.Content>\n\t\t\t\t<ErrorReport\n\t\t\t\t\terror={ error }\n\t\t\t\t\tcomponentStack={ componentStack }\n\t\t\t\t/>\n\t\t\t</CollapsibleCard.Content>\n\t\t</CollapsibleCard.Root>\n\t);\n}\n\nclass ErrorBoundary extends Component {\n\tconstructor() {\n\t\tsuper( ...arguments );\n\n\t\tthis.state = {\n\t\t\terror: null,\n\t\t\tcomponentStack: null,\n\t\t};\n\t}\n\n\tcomponentDidCatch( error, errorInfo ) {\n\t\tthis.setState( { componentStack: errorInfo?.componentStack } );\n\t\tdoAction( 'editor.ErrorBoundary.errorLogged', error, errorInfo );\n\t}\n\n\tstatic getDerivedStateFromError( error ) {\n\t\treturn { error };\n\t}\n\n\trender() {\n\t\tconst { error, componentStack } = this.state;\n\t\tconst { canCopyContent = false } = this.props;\n\t\tif ( ! error ) {\n\t\t\treturn this.props.children;\n\t\t}\n\n\t\treturn (\n\t\t\t<Stack\n\t\t\t\tclassName=\"editor-error-boundary\"\n\t\t\t\tdirection=\"column\"\n\t\t\t\tgap=\"lg\"\n\t\t\t>\n\t\t\t\t<Notice.Root intent=\"error\">\n\t\t\t\t\t<Notice.Title>\n\t\t\t\t\t\t{ __( 'The editor has crashed' ) }\n\t\t\t\t\t</Notice.Title>\n\t\t\t\t\t<Notice.Description>\n\t\t\t\t\t\t{ __(\n\t\t\t\t\t\t\t'An unknown error occurred. Reload your browser to try again, or copy the error to report the problem or search.'\n\t\t\t\t\t\t) }\n\t\t\t\t\t</Notice.Description>\n\t\t\t\t\t<Notice.Actions>\n\t\t\t\t\t\t{ canCopyContent && (\n\t\t\t\t\t\t\t<CopyButton text={ getContent }>\n\t\t\t\t\t\t\t\t{ __( 'Copy contents' ) }\n\t\t\t\t\t\t\t</CopyButton>\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<CopyButton\n\t\t\t\t\t\t\tvariant=\"solid\"\n\t\t\t\t\t\t\ttext={ () =>\n\t\t\t\t\t\t\t\tgetErrorReport( error, componentStack )\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ __( 'Copy error' ) }\n\t\t\t\t\t\t</CopyButton>\n\t\t\t\t\t</Notice.Actions>\n\t\t\t\t</Notice.Root>\n\t\t\t\t{ globalThis.SCRIPT_DEBUG ? (\n\t\t\t\t\t<ErrorDetails\n\t\t\t\t\t\terror={ error }\n\t\t\t\t\t\tcomponentStack={ componentStack }\n\t\t\t\t\t/>\n\t\t\t\t) : null }\n\t\t\t</Stack>\n\t\t);\n\t}\n}\n\n/**\n * ErrorBoundary is used to catch JavaScript errors anywhere in a child component tree, log those errors, and display a fallback UI.\n *\n * It uses the lifecycle methods getDerivedStateFromError and componentDidCatch to catch errors in a child component tree.\n *\n * getDerivedStateFromError is used to render a fallback UI after an error has been thrown, and componentDidCatch is used to log error information.\n *\n * @class ErrorBoundary\n * @augments Component\n */\nexport default ErrorBoundary;\n"], "mappings": "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", "names": [] }