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 / usePaletteOverride.js

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

90 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { refreshBlockHighlight } from '@agent/lib/block-highlight';
2 import { getDynamicDuotoneMap } from '@agent/lib/svg-blocks-scanner';
3 import { replaceDuotoneSVG } from '@agent/lib/svg-helpers';
4 import { isInEditor } from '@agent/lib/util';
5 import { parse } from '@wordpress/blocks';
6 import { useSelect } from '@wordpress/data';
7 import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
8
9 const styleId = 'extendify-palette-preview-css';
10 const editorIframeSelector = 'iframe[name="editor-canvas"]';
11 const editorStylesWrapper = '.editor-styles-wrapper';
12
13 const getEditorDocument = () =>
14 document.querySelector(editorIframeSelector)?.contentDocument || document;
15
16 // Ties core's own rules at 0-1-0, so it only wins by coming after them.
17 const appendStyle = (doc, parent) => {
18 const existing = doc.getElementById(styleId);
19 if (existing) return existing;
20
21 const style = doc.createElement('style');
22 style.id = styleId;
23 parent.appendChild(style);
24 return style;
25 };
26
27 // The unframed editor has no <body> of its own to grade.
28 const forEditorWithoutIframe = (css) =>
29 css
30 .replaceAll(':root :where(body)', editorStylesWrapper)
31 .replaceAll(':root', editorStylesWrapper);
32
33 export const usePaletteOverride = ({ css, duotoneTheme }) => {
34 const duotoneCleanup = useRef(null);
35 const [theDocument, setDocument] = useState(null);
36 const onEditor = isInEditor();
37
38 useEffect(() => {
39 if (!css || onEditor) return;
40 appendStyle(document, document.head).innerHTML = css;
41 refreshBlockHighlight();
42 }, [css, onEditor]);
43
44 useEffect(() => {
45 if (!css || !theDocument || !onEditor) return;
46 const hasIframe = document.querySelector(editorIframeSelector);
47 appendStyle(theDocument, theDocument.body).innerHTML = hasIframe
48 ? css
49 : forEditorWithoutIframe(css);
50 }, [css, theDocument, onEditor]);
51
52 useEffect(() => {
53 if (theDocument || !onEditor) return;
54 const timer = setTimeout(() => {
55 const doc = getEditorDocument();
56 if (doc?.body) setDocument(doc);
57 }, 300); // wait for iframe
58 return () => clearTimeout(timer);
59 }, [theDocument, onEditor]);
60
61 const dynamicDuotone = useSelect((select) => {
62 let blocks = select('core/block-editor')?.getBlocks?.() ?? [];
63
64 if (blocks.find((block) => block.name === 'core/template-part')) {
65 const { getEditedPostContent } = select('core/editor');
66 blocks = parse(getEditedPostContent(), {});
67 }
68
69 return getDynamicDuotoneMap(blocks);
70 }, []);
71
72 useEffect(() => {
73 // A palette without duotone must still clear the last one's svg filter.
74 duotoneCleanup.current?.();
75 duotoneCleanup.current = duotoneTheme
76 ? replaceDuotoneSVG({ duotoneTheme, dynamicDuotone })
77 : null;
78 }, [css, duotoneTheme, dynamicDuotone]);
79
80 const undoChange = useCallback(() => {
81 duotoneCleanup.current?.();
82 duotoneCleanup.current = null;
83
84 document.getElementById(styleId)?.remove();
85 if (onEditor) getEditorDocument()?.getElementById(styleId)?.remove();
86 }, [onEditor]);
87
88 return { undoChange };
89 };
90