PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Agent / hooks / useFontVariationOverride.js

useFontVariationOverride.js in Extendify 3.2.1, at src/Agent/hooks/useFontVariationOverride.js

135 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { getDynamicDuotoneMap } from '@agent/lib/svg-blocks-scanner';
2 import { replaceDuotoneSVG } from '@agent/lib/svg-helpers';
3 import apiFetch from '@wordpress/api-fetch';
4 import { parse } from '@wordpress/blocks';
5 import { useSelect } from '@wordpress/data';
6 import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
7
8 const id = 'global-styles-inline-css';
9 const path = window.location.pathname;
10 const s = new URLSearchParams(window.location.search);
11 const onEditor =
12 path.includes('/wp-admin/post.php') && s.get('action') === 'edit';
13 const { globalStylesPostID } = window.extSharedData;
14
15 export const useFontVariationOverride = ({ css }) => {
16 const frontStyles = useRef(null);
17 const duotoneCleanup = useRef(null);
18 const [theDocument, setDocument] = useState(null);
19 const [duotoneTheme, setDuotoneTheme] = useState(null);
20
21 useEffect(() => {
22 apiFetch({
23 path: `/wp/v2/global-styles/${globalStylesPostID}?context=edit`,
24 }).then((stylesResponse) => {
25 // The stored list is plain after a palette, origin-keyed after a variation.
26 const duotone = stylesResponse?.settings?.color?.duotone;
27 setDuotoneTheme(Array.isArray(duotone) ? duotone : duotone?.theme);
28 });
29 }, [css]);
30
31 useEffect(() => {
32 if (!css || onEditor) return;
33 const style = document.getElementById(id);
34 if (!style) return;
35 if (!frontStyles.current) {
36 frontStyles.current = style.innerHTML;
37 }
38 style.innerHTML = css;
39 }, [css]);
40
41 // Handle the editor
42 useEffect(() => {
43 if (!css || !theDocument || !onEditor) return;
44 const style = theDocument.getElementById(id);
45 const hasIframe = document.querySelector('iframe[name="editor-canvas"]');
46 style.innerHTML = css.replaceAll(
47 ':root',
48 // If the iframe was removed, target the editor the old way
49 hasIframe ? ':root' : '.editor-styles-wrapper',
50 );
51
52 // Since these effects should not affect the whole editor, only the text
53 if (!hasIframe) {
54 // we need to replace the individual elements with the style wrapper
55 style.innerHTML = style.innerHTML
56 .replace('body{', '.editor-styles-wrapper{')
57 // or prefix them with the editor class
58 .replace(
59 /(h[1-6](?:\s*,\s*h[1-6])*)\s*\{/g,
60 '.editor-styles-wrapper $1{',
61 );
62 }
63 }, [css, theDocument]);
64
65 useEffect(() => {
66 if (theDocument) return;
67 const timer = setTimeout(() => {
68 if (theDocument) return;
69 const frame = document.querySelector('iframe[name="editor-canvas"]');
70 const doc = frame?.contentDocument || document;
71 if (!doc || !doc.body) return;
72 // Add a tag to the body
73 const newStyle = doc.createElement('style');
74 newStyle.id = id;
75 doc.body.appendChild(newStyle);
76 setDocument(doc);
77 }, 300); // wait for iframe
78 return () => clearTimeout(timer);
79 }, [theDocument]);
80
81 const dynamicDuotone = useSelect((select) => {
82 let blocks = select('core/block-editor')?.getBlocks?.() ?? [];
83
84 const hasShowTemplateOn = blocks.find(
85 (block) => block.name === 'core/template-part',
86 );
87
88 if (hasShowTemplateOn) {
89 const { getEditedPostContent } = select('core/editor');
90 blocks = parse(getEditedPostContent(), {});
91 }
92
93 return getDynamicDuotoneMap(blocks);
94 }, []);
95
96 // Handle duotone changes
97 useEffect(() => {
98 if (!duotoneTheme) return;
99
100 // Clean up previous duotone changes
101 if (duotoneCleanup.current) {
102 duotoneCleanup.current();
103 duotoneCleanup.current = null;
104 }
105
106 // Apply new duotone changes and store cleanup
107 duotoneCleanup.current = replaceDuotoneSVG({
108 duotoneTheme,
109 dynamicDuotone,
110 });
111 }, [css, duotoneTheme, dynamicDuotone]);
112
113 const undoChange = useCallback(() => {
114 // Revert duotone changes
115 if (duotoneCleanup.current) {
116 duotoneCleanup.current();
117 duotoneCleanup.current = null;
118 }
119
120 // Revert CSS changes
121 const style = document.getElementById(id);
122 if (style && frontStyles.current) {
123 style.innerHTML = frontStyles.current;
124 }
125
126 // Remove editor CSS
127 if (!onEditor) return;
128 const iframe = document.querySelector('iframe[name="editor-canvas"]');
129 const doc = iframe?.contentDocument || document;
130 doc?.getElementById(id)?.remove();
131 }, []);
132
133 return { undoChange };
134 };
135