@elementor/editor-canvas 0.18.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +19 -0
- package/dist/index.js +79 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +60 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/__tests__/__snapshots__/style-renderer.test.tsx.snap +30 -0
- package/src/components/__tests__/style-renderer.test.tsx +16 -14
- package/src/components/style-renderer.tsx +7 -2
- package/src/hooks/__tests__/__snapshots__/use-documents-css-links.test.tsx.snap +30 -0
- package/src/hooks/__tests__/use-documents-css-links.test.tsx +84 -0
- package/src/hooks/__tests__/use-style-items.test.ts +3 -3
- package/src/hooks/use-documents-css-links.ts +58 -0
- package/src/hooks/use-style-items.ts +1 -1
- package/src/sync/{get-canvas-iframe-head.ts → get-canvas-iframe-document.ts} +2 -2
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`useDocumentsCssLinks should return an array of links attrs and remove them from the dom 1`] = `
|
|
4
|
+
<head>
|
|
5
|
+
<link
|
|
6
|
+
href="10.css"
|
|
7
|
+
id="elementor-post-10-css"
|
|
8
|
+
rel="stylesheet"
|
|
9
|
+
/>
|
|
10
|
+
<link
|
|
11
|
+
href="not-elementor.css"
|
|
12
|
+
id="not-elementor-css"
|
|
13
|
+
rel="stylesheet"
|
|
14
|
+
/>
|
|
15
|
+
<link
|
|
16
|
+
data-e-removed="true"
|
|
17
|
+
data-from-hook="true"
|
|
18
|
+
href="2.css"
|
|
19
|
+
id="elementor-post-2-css"
|
|
20
|
+
rel="stylesheet"
|
|
21
|
+
/>
|
|
22
|
+
<link
|
|
23
|
+
data-e-removed="true"
|
|
24
|
+
data-from-hook="true"
|
|
25
|
+
href="5.css"
|
|
26
|
+
id="elementor-post-5-css"
|
|
27
|
+
rel="stylesheet"
|
|
28
|
+
/>
|
|
29
|
+
</head>
|
|
30
|
+
`;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
import { createDOMElement } from 'test-utils';
|
|
4
|
+
import { render, renderHook } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
import { getCanvasIframeDocument } from '../../sync/get-canvas-iframe-document';
|
|
7
|
+
import { useDocumentsCssLinks } from '../use-documents-css-links';
|
|
8
|
+
|
|
9
|
+
jest.mock( '../../sync/get-canvas-iframe-document', () => ( {
|
|
10
|
+
getCanvasIframeDocument: jest.fn(),
|
|
11
|
+
} ) );
|
|
12
|
+
|
|
13
|
+
describe( 'useDocumentsCssLinks', () => {
|
|
14
|
+
const head = createDOMElement( {
|
|
15
|
+
tag: 'head',
|
|
16
|
+
children: [
|
|
17
|
+
createDOMElement( {
|
|
18
|
+
tag: 'link',
|
|
19
|
+
attrs: { href: '2.css', rel: 'stylesheet', id: 'elementor-post-2-css' },
|
|
20
|
+
} ),
|
|
21
|
+
createDOMElement( {
|
|
22
|
+
tag: 'link',
|
|
23
|
+
attrs: { href: '10.css', rel: 'stylesheet', id: 'elementor-post-10-css' },
|
|
24
|
+
} ),
|
|
25
|
+
createDOMElement( {
|
|
26
|
+
tag: 'link',
|
|
27
|
+
attrs: { href: '5.css', rel: 'stylesheet', id: 'elementor-post-5-css' },
|
|
28
|
+
} ),
|
|
29
|
+
createDOMElement( {
|
|
30
|
+
tag: 'link',
|
|
31
|
+
attrs: { href: 'not-elementor.css', rel: 'stylesheet', id: 'not-elementor-css' },
|
|
32
|
+
} ),
|
|
33
|
+
],
|
|
34
|
+
} );
|
|
35
|
+
|
|
36
|
+
const body = createDOMElement( {
|
|
37
|
+
tag: 'body',
|
|
38
|
+
children: [
|
|
39
|
+
createDOMElement( { tag: 'div', attrs: { 'data-elementor-id': '2' } } ),
|
|
40
|
+
createDOMElement( { tag: 'div', attrs: { 'data-elementor-id': '4' } } ),
|
|
41
|
+
createDOMElement( {
|
|
42
|
+
tag: 'div',
|
|
43
|
+
children: [ createDOMElement( { tag: 'div', attrs: { 'data-elementor-id': '5' } } ) ],
|
|
44
|
+
} ),
|
|
45
|
+
],
|
|
46
|
+
} );
|
|
47
|
+
|
|
48
|
+
const Component = () => {
|
|
49
|
+
const links = useDocumentsCssLinks();
|
|
50
|
+
|
|
51
|
+
return createPortal(
|
|
52
|
+
<>
|
|
53
|
+
{ links.map( ( link ) => (
|
|
54
|
+
<link key={ link.id } { ...link } data-from-hook />
|
|
55
|
+
) ) }
|
|
56
|
+
</>,
|
|
57
|
+
head
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
it( 'should return an array of links attrs and remove them from the dom', () => {
|
|
62
|
+
// Arrange.
|
|
63
|
+
const document = { body, head };
|
|
64
|
+
|
|
65
|
+
jest.mocked( getCanvasIframeDocument ).mockReturnValue( document as never );
|
|
66
|
+
|
|
67
|
+
// Act.
|
|
68
|
+
render( <Component /> );
|
|
69
|
+
|
|
70
|
+
// Assert.
|
|
71
|
+
expect( head ).toMatchSnapshot();
|
|
72
|
+
} );
|
|
73
|
+
|
|
74
|
+
it( 'should return empty array when iframe document is not available', () => {
|
|
75
|
+
// Arrange.
|
|
76
|
+
jest.mocked( getCanvasIframeDocument ).mockReturnValue( null );
|
|
77
|
+
|
|
78
|
+
// Act.
|
|
79
|
+
const { result } = renderHook( () => useDocumentsCssLinks(), { initialProps: {} } );
|
|
80
|
+
|
|
81
|
+
// Assert.
|
|
82
|
+
expect( result.current ).toEqual( [] );
|
|
83
|
+
} );
|
|
84
|
+
} );
|
|
@@ -71,7 +71,7 @@ describe( 'useStyleItems', () => {
|
|
|
71
71
|
} );
|
|
72
72
|
|
|
73
73
|
// Assert.
|
|
74
|
-
expect( result.current ).toEqual( [ { id: '
|
|
74
|
+
expect( result.current ).toEqual( [ { id: 'style2' }, { id: 'style1' } ] );
|
|
75
75
|
|
|
76
76
|
// Act.
|
|
77
77
|
await act( async () => {
|
|
@@ -83,7 +83,7 @@ describe( 'useStyleItems', () => {
|
|
|
83
83
|
} );
|
|
84
84
|
|
|
85
85
|
// Assert.
|
|
86
|
-
expect( result.current ).toEqual( [ { id: '
|
|
86
|
+
expect( result.current ).toEqual( [ { id: 'style4' }, { id: 'style3' }, { id: 'style2' }, { id: 'style1' } ] );
|
|
87
87
|
} );
|
|
88
88
|
|
|
89
89
|
it( 'should return style items when attach-preview command is triggered', async () => {
|
|
@@ -128,6 +128,6 @@ describe( 'useStyleItems', () => {
|
|
|
128
128
|
} );
|
|
129
129
|
|
|
130
130
|
// Assert.
|
|
131
|
-
expect( result.current ).toEqual( [ { id: '
|
|
131
|
+
expect( result.current ).toEqual( [ { id: 'style4' }, { id: 'style3' }, { id: 'style2' }, { id: 'style1' } ] );
|
|
132
132
|
} );
|
|
133
133
|
} );
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { __privateUseListenTo as useListenTo, commandEndEvent } from '@elementor/editor-v1-adapters';
|
|
2
|
+
|
|
3
|
+
import { getCanvasIframeDocument } from '../sync/get-canvas-iframe-document';
|
|
4
|
+
|
|
5
|
+
const REMOVED_ATTR = 'data-e-removed';
|
|
6
|
+
const DOCUMENT_WRAPPER_ATTR = 'data-elementor-id';
|
|
7
|
+
const CSS_LINK_ID_PREFIX = 'elementor-post-';
|
|
8
|
+
const CSS_LINK_ID_SUFFIX = '-css';
|
|
9
|
+
|
|
10
|
+
export function useDocumentsCssLinks() {
|
|
11
|
+
return useListenTo( commandEndEvent( 'editor/documents/attach-preview' ), () => {
|
|
12
|
+
const iframeDocument = getCanvasIframeDocument();
|
|
13
|
+
|
|
14
|
+
if ( ! iframeDocument ) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const relevantLinkIds = getDocumentsIdsInCanvas( iframeDocument ).map(
|
|
19
|
+
( id ) => `${ CSS_LINK_ID_PREFIX }${ id }${ CSS_LINK_ID_SUFFIX }`
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const links = getDocumentsCssLinks( iframeDocument ).filter( ( link ) =>
|
|
23
|
+
relevantLinkIds.includes( link.getAttribute( 'id' ) ?? '' )
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
links.forEach( ( link ) => {
|
|
27
|
+
if ( ! link.hasAttribute( REMOVED_ATTR ) ) {
|
|
28
|
+
link.remove();
|
|
29
|
+
}
|
|
30
|
+
} );
|
|
31
|
+
|
|
32
|
+
return links.map( ( link ) => ( {
|
|
33
|
+
...getLinkAttrs( link ),
|
|
34
|
+
id: link.getAttribute( 'id' ) ?? '',
|
|
35
|
+
[ REMOVED_ATTR ]: true,
|
|
36
|
+
} ) );
|
|
37
|
+
} );
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function getDocumentsIdsInCanvas( document: Document ) {
|
|
41
|
+
return [ ...( document.body.querySelectorAll< HTMLElement >( `[${ DOCUMENT_WRAPPER_ATTR }]` ) ?? [] ) ].map(
|
|
42
|
+
( el ) => el.getAttribute( DOCUMENT_WRAPPER_ATTR ) || ''
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getDocumentsCssLinks( document: Document ) {
|
|
47
|
+
return [
|
|
48
|
+
...( document.head.querySelectorAll< HTMLLinkElement >(
|
|
49
|
+
`link[rel="stylesheet"][id^=${ CSS_LINK_ID_PREFIX }][id$=${ CSS_LINK_ID_SUFFIX }]`
|
|
50
|
+
) ?? [] ),
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getLinkAttrs( el: HTMLLinkElement ) {
|
|
55
|
+
const entries = [ ...el.attributes ].map( ( attr ) => [ attr.name, attr.value ] as const );
|
|
56
|
+
|
|
57
|
+
return Object.fromEntries( entries );
|
|
58
|
+
}
|
|
@@ -66,7 +66,7 @@ type CreateProviderSubscriberArgs = {
|
|
|
66
66
|
function createProviderSubscriber( { provider, renderStyles, setStyleItems }: CreateProviderSubscriberArgs ) {
|
|
67
67
|
return abortPreviousRuns( ( abortController ) =>
|
|
68
68
|
signalizedProcess( abortController.signal )
|
|
69
|
-
.then( ( _, signal ) => renderStyles( { styles: provider.actions.all(), signal } ) )
|
|
69
|
+
.then( ( _, signal ) => renderStyles( { styles: [ ...provider.actions.all() ].reverse(), signal } ) )
|
|
70
70
|
.then( ( items ) => {
|
|
71
71
|
setStyleItems( ( prev ) => ( {
|
|
72
72
|
...prev,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CanvasExtendedWindow } from './types';
|
|
2
2
|
|
|
3
|
-
export function
|
|
3
|
+
export function getCanvasIframeDocument() {
|
|
4
4
|
const extendedWindow = window as unknown as CanvasExtendedWindow;
|
|
5
5
|
|
|
6
|
-
return extendedWindow.elementor?.$preview?.[ 0 ]?.contentDocument
|
|
6
|
+
return extendedWindow.elementor?.$preview?.[ 0 ]?.contentDocument;
|
|
7
7
|
}
|