PluginProbe
Code Block Pro – Beautiful Syntax Highlighting / 1.9.0
Code Block Pro – Beautiful Syntax Highlighting v1.9.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.9.0, at src/editor/Edit.tsx

188 lines 6.0 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 (disablePadding && !lineNumbersWidth ? 0 : 16) +
164 // If line numbers are disabled, just offset the 12px padding
165 (lineNumbersWidth ?? -12) +
166 12,
167 right: 0,
168 }}
169 style={{ backgroundColor, color }}
170 // eslint-disable-next-line
171 onKeyDown={(e: any) =>
172 e.key === 'Tab' &&
173 // Tab lock here. Pressing Escape will unlock.
174 textAreaRef.current?.querySelector('textarea')?.focus()
175 }
176 highlight={(code: string) =>
177 highlighter
178 ?.codeToHtml(code, {
179 lang: language ?? previousLanguage,
180 lineOptions: [...getHighlights(), ...getBlurs()],
181 })
182 ?.replace(/<\/?[pre|code][^>]*>/g, '')
183 }
184 />
185 </div>
186 );
187 };
188