PluginProbe
Code Snippets / 3.10.2
Code Snippets v3.10.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / js / components / EditMenu / SnippetForm / page / Notices.tsx

Notices.tsx in Code Snippets 3.10.2, at js/components/EditMenu/SnippetForm/page/Notices.tsx

98 lines 3.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { createInterpolateElement } from '@wordpress/element'
2 import React, { useEffect, useRef, useState } from 'react'
3 import { __, sprintf } from '@wordpress/i18n'
4 import { useSnippetForm } from '../WithSnippetFormContext'
5 import { DismissibleNotice } from '../../../common/Notice'
6 import type { ReactNode } from 'react'
7
8 const DESCRIPTION_INDEX = 2
9 const DETAILS_INDEX = 3
10 const hasStackTrace = (notice?: readonly unknown[]): boolean => Boolean(notice?.[DETAILS_INDEX])
11 const renderNoticeLine = (line: ReactNode): ReactNode =>
12 'string' === typeof line
13 ? createInterpolateElement(line, { strong: <strong /> })
14 : line
15
16 interface NoticesProps {
17 placement: 'above-form' | 'sidebar'
18 }
19
20 const StackTraceDetails: React.FC<{ trace: string }> = ({ trace }) => {
21 const preRef = useRef<HTMLPreElement>(null)
22 const [isOpen, setIsOpen] = useState(false)
23 const [showHint, setShowHint] = useState(false)
24
25 useEffect(() => {
26 if (!isOpen) {
27 setShowHint(false)
28 return
29 }
30
31 const updateHintVisibility = () => {
32 const pre = preRef.current
33 setShowHint(Boolean(pre && pre.scrollWidth > pre.clientWidth))
34 }
35
36 updateHintVisibility()
37 window.addEventListener('resize', updateHintVisibility)
38
39 return () => {
40 window.removeEventListener('resize', updateHintVisibility)
41 }
42 }, [isOpen, trace])
43
44 return (
45 <details onToggle={event => setIsOpen(event.currentTarget.open)}>
46 <summary>{__('View stack trace', 'code-snippets')}</summary>
47 <pre ref={preRef}>{trace}</pre>
48 {showHint
49 ? <p className="stack-trace-hint">
50 <em>{__('Scroll horizontally if the trace is cut off.', 'code-snippets')}</em>
51 </p>
52 : null}
53 </details>
54 )
55 }
56
57 export const Notices: React.FC<NoticesProps> = ({ placement }) => {
58 const { currentNotice, setCurrentNotice, snippet, setSnippet } = useSnippetForm()
59 const showCurrentNotice = 'above-form' === placement ? hasStackTrace(currentNotice) : !hasStackTrace(currentNotice)
60 const showCodeErrorNotice = 'sidebar' === placement && !snippet.code_error_trace
61
62 return <>
63 {showCurrentNotice && currentNotice
64 ? <DismissibleNotice
65 className={`${currentNotice[0]} code-snippets-notice`}
66 type={'error' === currentNotice[0] ? 'error' : undefined}
67 onDismiss={() => setCurrentNotice(undefined)}
68 >
69 <p>{renderNoticeLine(currentNotice[1])}</p>
70 {currentNotice[DESCRIPTION_INDEX]
71 ? <p>{renderNoticeLine(currentNotice[DESCRIPTION_INDEX])}</p>
72 : null}
73 {currentNotice[DETAILS_INDEX]
74 ? <StackTraceDetails trace={currentNotice[DETAILS_INDEX]} />
75 : null}
76 </DismissibleNotice>
77 : null}
78
79 {showCodeErrorNotice && !currentNotice && snippet.code_error
80 ? <DismissibleNotice
81 className="notice-error"
82 type="error"
83 onDismiss={() => setSnippet(previous => ({ ...previous, code_error: null, code_error_trace: null }))}
84 >
85 <p>
86 <strong>{sprintf(
87 // translators: %d: line number.
88 __('Snippet automatically deactivated due to an error on line %d:', 'code-snippets'),
89 snippet.code_error[1]
90 )}</strong>
91
92 <blockquote>{snippet.code_error[0]}</blockquote>
93 </p>
94 </DismissibleNotice>
95 : null}
96 </>
97 }
98