PluginProbe
Code Block Pro – Beautiful Syntax Highlighting / 1.10.0
Code Block Pro – Beautiful Syntax Highlighting v1.10.0
1.27.1 1.27.2 1.27.3 1.27.4 1.27.5 1.27.6 1.27.7 1.28.0 1.3.0 1.4.0 1.5.0 1.5.1 1.5.2 1.6.0 1.7.0 1.8.0 1.9.0 1.9.1 1.9.2 1.9.3 trunk 1.1.0 1.10.0 1.11.0 1.11.1 All 63 releases
code-block-pro / src / editor / Edit.tsx

Edit.tsx in Code Block Pro – Beautiful Syntax Highlighting 1.10.0, at src/editor/Edit.tsx

189 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {
2 useCallback,
3 useEffect,
4 useLayoutEffect,
5 useRef,
6 } from '@wordpress/element';
7 import { applyFilters } from '@wordpress/hooks';
8 import { colord } from 'colord';
9 import Editor from 'react-simple-code-editor';
10 import { useDefaults } from '../hooks/useDefaults';
11 import { useTheme } from '../hooks/useTheme';
12 import { useLanguageStore } from '../state/language';
13 import { AttributesPropsAndSetter } from '../types';
14 import { parseJSONArrayWithRanges } from '../util/arrayHelpers';
15
16 export const Edit = ({
17 attributes,
18 setAttributes,
19 }: AttributesPropsAndSetter) => {
20 const {
21 language,
22 theme,
23 code = '',
24 bgColor: backgroundColor,
25 textColor: color,
26 disablePadding,
27 lineNumbersWidth,
28 lineNumbers,
29 startingLineNumber,
30 footerType,
31 fontSize,
32 fontFamily,
33 lineHeight,
34 lineBlurs,
35 lineHighlights,
36 enableBlurring,
37 enableHighlighting,
38 } = attributes;
39
40 const textAreaRef = useRef<HTMLDivElement>(null);
41 const handleChange = (code: string) => setAttributes({ code });
42 const { previousLanguage } = useLanguageStore();
43 const { highlighter, error, loading } = useTheme({
44 theme,
45 lang: language ?? previousLanguage,
46 });
47 const hasFooter = footerType && footerType !== 'none';
48 useDefaults({ attributes, setAttributes });
49
50 const getHighlights = useCallback(() => {
51 if (!enableHighlighting) return [];
52 return parseJSONArrayWithRanges(lineHighlights, startingLineNumber).map(
53 (line: number) => ({
54 line,
55 classes: ['cbp-line-highlight'],
56 }),
57 );
58 }, [enableHighlighting, lineHighlights, startingLineNumber]);
59 const getBlurs = useCallback(() => {
60 if (!enableBlurring) return [];
61 return parseJSONArrayWithRanges(lineBlurs, startingLineNumber).map(
62 (line: number) => ({
63 line,
64 classes: ['cbp-no-blur'],
65 }),
66 );
67 }, [enableBlurring, lineBlurs, startingLineNumber]);
68
69 useEffect(() => {
70 if (!highlighter) return;
71 setAttributes({
72 bgColor: highlighter.getBackgroundColor(),
73 textColor: highlighter.getForegroundColor(),
74 });
75 }, [theme, highlighter, setAttributes]);
76
77 useEffect(() => {
78 if (!highlighter) return;
79 setAttributes({
80 codeHTML: applyFilters(
81 'blocks.codeBlockPro.codeHTML',
82 highlighter.codeToHtml(code, {
83 lang: language ?? previousLanguage,
84 lineOptions: [...getHighlights(), ...getBlurs()],
85 }),
86 attributes,
87 ) as string,
88 lineHighlightColor: colord(color)
89 .saturate(0.5)
90 .alpha(0.2)
91 .toRgbString(),
92 });
93 }, [
94 highlighter,
95 color,
96 code,
97 language,
98 setAttributes,
99 previousLanguage,
100 attributes,
101 lineHighlights,
102 lineBlurs,
103 getBlurs,
104 getHighlights,
105 ]);
106
107 useLayoutEffect(() => {
108 if (!textAreaRef.current) return;
109 if (!lineNumbers) {
110 setAttributes({ lineNumbersWidth: undefined });
111 return;
112 }
113 // Get the last line (assumingly the widest)
114 const lastLine = Array.from(
115 textAreaRef?.current?.querySelectorAll('.line') ?? [],
116 )?.at(-1) as HTMLElement;
117 // Make sure there are no width constraints
118 lastLine?.classList?.add('cbp-line-number-width-forced');
119 const lastLineWidth = lastLine?.getBoundingClientRect()?.width ?? 0;
120 // Add .cbp-line-number-disabled to disable the line number
121 lastLine?.classList.add('cbp-line-number-disabled');
122 // Re calculate the width of the last line
123 const newWidth = lastLine?.getBoundingClientRect()?.width ?? 0;
124 // Remove the classes
125 lastLine?.classList.remove('cbp-line-number-disabled');
126 lastLine?.classList?.remove('cbp-line-number-width-forced');
127 // Calculate the difference
128 if (lastLineWidth - newWidth > 0) {
129 setAttributes({ lineNumbersWidth: lastLineWidth - newWidth - 12 });
130 }
131 }, [
132 lineNumbers,
133 startingLineNumber,
134 code,
135 loading,
136 error,
137 textAreaRef,
138 setAttributes,
139 fontSize,
140 fontFamily,
141 lineHeight,
142 ]);
143
144 if ((loading && code) || error) {
145 return (
146 <div
147 className="p-8 px-4 text-left"
148 style={{ backgroundColor, color }}>
149 {error?.message ?? ''}
150 </div>
151 );
152 }
153
154 return (
155 <div ref={textAreaRef}>
156 <Editor
157 value={code}
158 onValueChange={handleChange}
159 padding={{
160 top: disablePadding ? 0 : 16,
161 bottom: disablePadding || hasFooter ? 0 : 16,
162 left: (() => {
163 if (!lineNumbers && disablePadding) return 0;
164 if (!lineNumbers) return 16;
165 if (disablePadding) return (lineNumbersWidth ?? 0) + 16;
166 return (lineNumbersWidth ?? 0) + 32;
167 })(),
168 right: 0,
169 }}
170 style={{ backgroundColor, color }}
171 // eslint-disable-next-line
172 onKeyDown={(e: any) =>
173 e.key === 'Tab' &&
174 // Tab lock here. Pressing Escape will unlock.
175 textAreaRef.current?.querySelector('textarea')?.focus()
176 }
177 highlight={(code: string) =>
178 highlighter
179 ?.codeToHtml(code, {
180 lang: language ?? previousLanguage,
181 lineOptions: [...getHighlights(), ...getBlurs()],
182 })
183 ?.replace(/<\/?[pre|code][^>]*>/g, '')
184 }
185 />
186 </div>
187 );
188 };
189