PluginProbe
Code Snippets / 3.10.1
Code Snippets v3.10.1
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 3.0.1 All 64 releases
code-snippets / js / components / EditMenu / SnippetForm / fields / CodeEditor.tsx

CodeEditor.tsx in Code Snippets 3.10.1, at js/components/EditMenu/SnippetForm/fields/CodeEditor.tsx

109 lines 3.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import React, { useEffect, useId, useRef } from 'react'
2 import { __ } from '@wordpress/i18n'
3 import { useSubmitSnippet } from '../../../../hooks/useSubmitSnippet'
4 import { handleUnknownError } from '../../../../utils/errors'
5 import { isMacOS } from '../../../../utils/screen'
6 import { useSnippetForm } from '../WithSnippetFormContext'
7 import { Button } from '../../../common/Button'
8 import { ExpandIcon } from '../../../common/icons/ExpandIcon'
9 import { MinimiseIcon } from '../../../common/icons/MinimiseIcon'
10 import { CodeEditorShortcuts } from './CodeEditorShortcuts'
11 import type { Dispatch, RefObject, SetStateAction } from 'react'
12
13 interface EditorTextareaProps {
14 textareaRef: RefObject<HTMLTextAreaElement>
15 snippetCodeId: string
16 }
17
18 const EditorTextarea: React.FC<EditorTextareaProps> = ({ textareaRef, snippetCodeId }) => {
19 const descriptionId = useId()
20 const { snippet, setSnippet } = useSnippetForm()
21
22 return (
23 <div
24 className="snippet-editor"
25 role="application"
26 aria-label={__('Code editor', 'code-snippets')}
27 aria-describedby={descriptionId}
28 >
29 <p id={descriptionId} className="screen-reader-text">
30 {__('In the editing area, the Tab key enters a tab character. To exit the code editor, press the Escape key and then the Tab key.', 'code-snippets')}
31 </p>
32 <textarea
33 ref={textareaRef}
34 id={snippetCodeId}
35 name="snippet_code"
36 value={snippet.code}
37 aria-label={__('Snippet code', 'code-snippets')}
38 rows={200}
39 spellCheck={false}
40 onChange={event => {
41 setSnippet(previous => ({ ...previous, code: event.target.value }))
42 }}
43 />
44 <CodeEditorShortcuts editorTheme={window.CODE_SNIPPETS_EDIT?.editorTheme ?? 'default'} />
45 </div>
46 )
47 }
48
49 export interface CodeEditorProps {
50 isExpanded: boolean
51 setIsExpanded: Dispatch<SetStateAction<boolean>>
52 }
53
54 export const CodeEditor: React.FC<CodeEditorProps> = ({ isExpanded, setIsExpanded }) => {
55 const { snippet, setSnippet, codeEditorInstance, setCodeEditorInstance } = useSnippetForm()
56 const { submitSnippet } = useSubmitSnippet()
57 const textareaRef = useRef<HTMLTextAreaElement>(null)
58 const snippetCodeId = useId()
59
60 useEffect(() => {
61 setCodeEditorInstance(editorInstance => {
62 if (textareaRef.current && !editorInstance && window.wp.codeEditor) {
63 editorInstance = window.wp.codeEditor.initialize(textareaRef.current)
64
65 editorInstance.codemirror.on('changes', instance => {
66 setSnippet(previous => ({ ...previous, code: instance.getValue() }))
67 })
68 }
69
70 return editorInstance
71 })
72 }, [setCodeEditorInstance, textareaRef, setSnippet])
73
74 useEffect(() => {
75 if (codeEditorInstance) {
76 const extraKeys = codeEditorInstance.codemirror.getOption('extraKeys') ?? {}
77 const controlKey = isMacOS() ? 'Cmd' : 'Ctrl'
78 const onSave = () => {
79 submitSnippet(snippet)
80 .then(() => undefined)
81 .catch(handleUnknownError)
82 }
83
84 codeEditorInstance.codemirror.setOption('extraKeys', {
85 ...'object' === typeof extraKeys ? extraKeys : undefined,
86 [`${controlKey}-S`]: onSave,
87 [`${controlKey}-Enter`]: onSave
88 })
89 }
90 }, [submitSnippet, codeEditorInstance, snippet])
91
92 return (
93 <div className="snippet-code-container">
94 <div className="above-snippet-code">
95 <label htmlFor={snippetCodeId}>
96 {__('Snippet Content', 'code-snippets')}
97 </label>
98
99 <Button small className="expand-editor-button" onClick={() => setIsExpanded(current => !current)}>
100 {isExpanded ? <MinimiseIcon aria-hidden="true" /> : <ExpandIcon aria-hidden="true" />}
101 {isExpanded ? __('Minimize', 'code-snippets') : __('Expand', 'code-snippets')}
102 </Button>
103 </div>
104
105 <EditorTextarea textareaRef={textareaRef} snippetCodeId={snippetCodeId} />
106 </div>
107 )
108 }
109