@elementor/editor-canvas 4.4.0-1136 → 4.4.0-1138

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/dist/index.js CHANGED
@@ -187,7 +187,9 @@ var SINGLE_BLOCK_KEY = "default";
187
187
  var convertBlocks = async (blocks) => {
188
188
  const { data } = await (0, import_http_client2.httpService)().post(
189
189
  CSS_TO_ATOMIC_URL,
190
- { blocks }
190
+ {
191
+ blocks
192
+ }
191
193
  );
192
194
  return data.data;
193
195
  };
@@ -2206,6 +2208,8 @@ var svgSrcTransformer = createTransformer(async (value, { signal }) => {
2206
2208
  var EMPTY_ICON_RESULT = { html: null, url: null };
2207
2209
  var ICON_SVG_SIZE = "100%";
2208
2210
  var ICON_SVG_OVERFLOW = "visible";
2211
+ var FONT_AWESOME_LIBRARY_PREFIX = "fa-";
2212
+ var EICONS_LIBRARY = "eicons";
2209
2213
  var DEFAULT_SVG_RELATIVE_PATH = "images/default-svg.svg";
2210
2214
  var iconTransformer = createTransformer(async (value, { signal }) => {
2211
2215
  const iconValue = typeof value.value === "string" ? value.value : null;
@@ -2217,14 +2221,14 @@ var iconTransformer = createTransformer(async (value, { signal }) => {
2217
2221
  if (fontAwesomeHtml) {
2218
2222
  return { html: fontAwesomeHtml, url: null };
2219
2223
  }
2220
- if ((0, import_editor_controls.isDeletedCustomIconLibrary)(library, iconValue)) {
2221
- return resolveDefaultSvg(signal);
2224
+ if (library.startsWith(FONT_AWESOME_LIBRARY_PREFIX) || EICONS_LIBRARY === library) {
2225
+ return EMPTY_ICON_RESULT;
2222
2226
  }
2223
- const customHtml = await resolveCustomSvg(library, iconValue, signal);
2224
- if (customHtml) {
2225
- return { html: customHtml, url: null };
2227
+ const providerHtml = await resolveProviderSvg(library, iconValue, signal);
2228
+ if (providerHtml) {
2229
+ return { html: providerHtml, url: null };
2226
2230
  }
2227
- return EMPTY_ICON_RESULT;
2231
+ return resolveDefaultSvg(signal);
2228
2232
  });
2229
2233
  async function resolveDefaultSvg(signal) {
2230
2234
  const assetsUrl = window.elementorCommon?.config?.urls?.assets;
@@ -2239,8 +2243,8 @@ async function resolveDefaultSvg(signal) {
2239
2243
  { key: "svg", signal }
2240
2244
  );
2241
2245
  }
2242
- async function resolveCustomSvg(library, iconValue, signal) {
2243
- const markup = await (0, import_editor_controls.resolveCustomIconSvg)(library, iconValue, signal);
2246
+ async function resolveProviderSvg(library, iconValue, signal) {
2247
+ const markup = await (0, import_editor_controls.resolveProviderIconSvg)(library, iconValue, signal);
2244
2248
  return markup ? processIconSvgContent(markup) : null;
2245
2249
  }
2246
2250
  async function resolveFontAwesomeSvg(library, iconValue, signal) {
package/dist/index.mjs CHANGED
@@ -118,7 +118,9 @@ var SINGLE_BLOCK_KEY = "default";
118
118
  var convertBlocks = async (blocks) => {
119
119
  const { data } = await httpService2().post(
120
120
  CSS_TO_ATOMIC_URL,
121
- { blocks }
121
+ {
122
+ blocks
123
+ }
122
124
  );
123
125
  return data.data;
124
126
  };
@@ -2092,9 +2094,8 @@ var timeRangeTransformer = createTransformer((value) => {
2092
2094
  // src/transformers/shared/icon-transformer.ts
2093
2095
  import {
2094
2096
  getFontAwesome7IconName,
2095
- isDeletedCustomIconLibrary,
2096
- resolveCustomIconSvg,
2097
- resolveFontAwesome7Icon
2097
+ resolveFontAwesome7Icon,
2098
+ resolveProviderIconSvg
2098
2099
  } from "@elementor/editor-controls";
2099
2100
 
2100
2101
  // src/transformers/shared/process-svg-content.ts
@@ -2163,6 +2164,8 @@ var svgSrcTransformer = createTransformer(async (value, { signal }) => {
2163
2164
  var EMPTY_ICON_RESULT = { html: null, url: null };
2164
2165
  var ICON_SVG_SIZE = "100%";
2165
2166
  var ICON_SVG_OVERFLOW = "visible";
2167
+ var FONT_AWESOME_LIBRARY_PREFIX = "fa-";
2168
+ var EICONS_LIBRARY = "eicons";
2166
2169
  var DEFAULT_SVG_RELATIVE_PATH = "images/default-svg.svg";
2167
2170
  var iconTransformer = createTransformer(async (value, { signal }) => {
2168
2171
  const iconValue = typeof value.value === "string" ? value.value : null;
@@ -2174,14 +2177,14 @@ var iconTransformer = createTransformer(async (value, { signal }) => {
2174
2177
  if (fontAwesomeHtml) {
2175
2178
  return { html: fontAwesomeHtml, url: null };
2176
2179
  }
2177
- if (isDeletedCustomIconLibrary(library, iconValue)) {
2178
- return resolveDefaultSvg(signal);
2180
+ if (library.startsWith(FONT_AWESOME_LIBRARY_PREFIX) || EICONS_LIBRARY === library) {
2181
+ return EMPTY_ICON_RESULT;
2179
2182
  }
2180
- const customHtml = await resolveCustomSvg(library, iconValue, signal);
2181
- if (customHtml) {
2182
- return { html: customHtml, url: null };
2183
+ const providerHtml = await resolveProviderSvg(library, iconValue, signal);
2184
+ if (providerHtml) {
2185
+ return { html: providerHtml, url: null };
2183
2186
  }
2184
- return EMPTY_ICON_RESULT;
2187
+ return resolveDefaultSvg(signal);
2185
2188
  });
2186
2189
  async function resolveDefaultSvg(signal) {
2187
2190
  const assetsUrl = window.elementorCommon?.config?.urls?.assets;
@@ -2196,8 +2199,8 @@ async function resolveDefaultSvg(signal) {
2196
2199
  { key: "svg", signal }
2197
2200
  );
2198
2201
  }
2199
- async function resolveCustomSvg(library, iconValue, signal) {
2200
- const markup = await resolveCustomIconSvg(library, iconValue, signal);
2202
+ async function resolveProviderSvg(library, iconValue, signal) {
2203
+ const markup = await resolveProviderIconSvg(library, iconValue, signal);
2201
2204
  return markup ? processIconSvgContent(markup) : null;
2202
2205
  }
2203
2206
  async function resolveFontAwesomeSvg(library, iconValue, signal) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "4.4.0-1136",
4
+ "version": "4.4.0-1138",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,26 +37,26 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.4.0-1136",
41
- "@elementor/editor-controls": "4.4.0-1136",
42
- "@elementor/editor-documents": "4.4.0-1136",
43
- "@elementor/editor-elements": "4.4.0-1136",
44
- "@elementor/editor-interactions": "4.4.0-1136",
45
- "@elementor/editor-mcp": "4.4.0-1136",
46
- "@elementor/editor-notifications": "4.4.0-1136",
47
- "@elementor/editor-props": "4.4.0-1136",
48
- "@elementor/editor-responsive": "4.4.0-1136",
49
- "@elementor/editor-styles": "4.4.0-1136",
50
- "@elementor/editor-styles-repository": "4.4.0-1136",
51
- "@elementor/editor-ui": "4.4.0-1136",
52
- "@elementor/editor-v1-adapters": "4.4.0-1136",
53
- "@elementor/events": "4.4.0-1136",
54
- "@elementor/http-client": "4.4.0-1136",
55
- "@elementor/schema": "4.4.0-1136",
56
- "@elementor/twing": "4.4.0-1136",
40
+ "@elementor/editor": "4.4.0-1138",
41
+ "@elementor/editor-controls": "4.4.0-1138",
42
+ "@elementor/editor-documents": "4.4.0-1138",
43
+ "@elementor/editor-elements": "4.4.0-1138",
44
+ "@elementor/editor-interactions": "4.4.0-1138",
45
+ "@elementor/editor-mcp": "4.4.0-1138",
46
+ "@elementor/editor-notifications": "4.4.0-1138",
47
+ "@elementor/editor-props": "4.4.0-1138",
48
+ "@elementor/editor-responsive": "4.4.0-1138",
49
+ "@elementor/editor-styles": "4.4.0-1138",
50
+ "@elementor/editor-styles-repository": "4.4.0-1138",
51
+ "@elementor/editor-ui": "4.4.0-1138",
52
+ "@elementor/editor-v1-adapters": "4.4.0-1138",
53
+ "@elementor/events": "4.4.0-1138",
54
+ "@elementor/http-client": "4.4.0-1138",
55
+ "@elementor/schema": "4.4.0-1138",
56
+ "@elementor/twing": "4.4.0-1138",
57
57
  "@elementor/ui": "1.41.3",
58
- "@elementor/utils": "4.4.0-1136",
59
- "@elementor/wp-media": "4.4.0-1136",
58
+ "@elementor/utils": "4.4.0-1138",
59
+ "@elementor/wp-media": "4.4.0-1138",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0",
62
62
  "dompurify": "^3.2.6"
@@ -22,7 +22,9 @@ const convertBlocks = async (
22
22
  ): Promise< Record< string, CssConversionResult > > => {
23
23
  const { data } = await httpService().post< HttpResponse< Record< string, CssConversionResult > > >(
24
24
  CSS_TO_ATOMIC_URL,
25
- { blocks }
25
+ {
26
+ blocks,
27
+ }
26
28
  );
27
29
 
28
30
  return data.data;
@@ -1,10 +1,8 @@
1
- jest.mock( '@elementor/http-client', () => ( {
2
- httpService: () => ( {
3
- get: jest.fn().mockRejectedValue( new Error( 'no custom svg' ) ),
4
- } ),
5
- } ) );
6
-
7
- import { resetFontAwesome7IconsCache } from '@elementor/editor-controls';
1
+ import {
2
+ registerIconLibraryProvider,
3
+ resetFontAwesome7IconsCache,
4
+ unregisterIconLibraryProvider,
5
+ } from '@elementor/editor-controls';
8
6
  import { iconPropTypeUtil, stringPropTypeUtil } from '@elementor/editor-props';
9
7
 
10
8
  import { iconPropType } from '../../../__tests__/prop-types';
@@ -186,15 +184,12 @@ describe( 'iconTransformer', () => {
186
184
  expect( result ).toEqual( { html: null, url: null } );
187
185
  } );
188
186
 
189
- it( 'falls back to the default svg when a custom library has been deleted', async () => {
187
+ it( 'falls back to the default svg when no provider resolves a non-native library', async () => {
190
188
  // Arrange.
191
- window.elementor = {
192
- config: {
193
- icons: {
194
- libraries: [ { name: 'fa-solid', prefix: 'fa-', native: true } ],
195
- },
196
- },
197
- } as typeof window.elementor;
189
+ registerIconLibraryProvider( {
190
+ id: 'test-provider',
191
+ useIcons: () => ( { data: [], isLoading: false } ),
192
+ } );
198
193
  const defaultSvg =
199
194
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><path d="M24.9999 4.31543"></path></svg>';
200
195
  global.fetch = jest.fn().mockResolvedValue( {
@@ -206,6 +201,8 @@ describe( 'iconTransformer', () => {
206
201
  // Act.
207
202
  const result = await resolveSavedIcon( 'missing-set missing-set-ghost', 'missing-set' );
208
203
 
204
+ unregisterIconLibraryProvider( 'test-provider' );
205
+
209
206
  // Assert.
210
207
  expect( global.fetch ).toHaveBeenCalledWith(
211
208
  'https://example.com/assets/images/default-svg.svg',
@@ -217,6 +214,59 @@ describe( 'iconTransformer', () => {
217
214
  } );
218
215
  } );
219
216
 
217
+ it( 'falls back to the default svg for a non-native library when no provider is registered', async () => {
218
+ // Arrange.
219
+ const defaultSvg =
220
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><path d="M24.9999 4.31543"></path></svg>';
221
+ global.fetch = jest.fn().mockResolvedValue( {
222
+ ok: true,
223
+ headers: new Headers( { 'content-type': 'image/svg+xml' } ),
224
+ text: () => Promise.resolve( defaultSvg ),
225
+ } );
226
+
227
+ // Act.
228
+ const result = await resolveSavedIcon( 'my-set my-set-star', 'my-set' );
229
+
230
+ // Assert.
231
+ expect( result ).toEqual( {
232
+ html: expect.stringContaining( 'M24.9999 4.31543' ),
233
+ url: 'https://example.com/assets/images/default-svg.svg',
234
+ } );
235
+ } );
236
+
237
+ it( 'does not replace PHP-managed eicons with the default svg', async () => {
238
+ // Arrange.
239
+ global.fetch = jest.fn();
240
+
241
+ // Act.
242
+ const result = await resolveSavedIcon( 'eicon-edit', 'eicons' );
243
+
244
+ // Assert.
245
+ expect( result ).toEqual( { html: null, url: null } );
246
+ expect( global.fetch ).not.toHaveBeenCalled();
247
+ } );
248
+
249
+ it( 'renders and sanitizes svg returned by a provider', async () => {
250
+ // Arrange.
251
+ registerIconLibraryProvider( {
252
+ id: 'test-provider',
253
+ useIcons: () => ( { data: [], isLoading: false } ),
254
+ resolveSvg: () =>
255
+ Promise.resolve(
256
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><script>alert(1)</script><path d="M1 1h8v8H1z"></path></svg>'
257
+ ),
258
+ } );
259
+
260
+ // Act.
261
+ const result = ( await resolveSavedIcon( 'my-set my-set-star', 'my-set' ) ) as { html: string };
262
+
263
+ unregisterIconLibraryProvider( 'test-provider' );
264
+
265
+ // Assert.
266
+ expect( result.html ).toContain( 'M1 1h8v8H1z' );
267
+ expect( result.html ).not.toContain( 'script' );
268
+ } );
269
+
220
270
  it( 'returns null html when value or library is missing', async () => {
221
271
  // Act.
222
272
  const resolve = createPropsResolver( {
@@ -47,7 +47,10 @@ describe( 'svgSrcTransformer', () => {
47
47
  const result = ( await svgSrcTransformer(
48
48
  { id: null, url: 'https://example.com/icon.svg' },
49
49
  { key: 'svg' }
50
- ) ) as { html: string; url: string };
50
+ ) ) as {
51
+ html: string;
52
+ url: string;
53
+ };
51
54
 
52
55
  // Assert.
53
56
  expect( result.html ).toContain( 'width: 100%' );
@@ -91,7 +94,10 @@ describe( 'svgSrcTransformer', () => {
91
94
  const result = ( await svgSrcTransformer(
92
95
  { id: 99, url: 'https://example.com/fallback.svg' },
93
96
  { key: 'svg' }
94
- ) ) as { html: string; url: string };
97
+ ) ) as {
98
+ html: string;
99
+ url: string;
100
+ };
95
101
 
96
102
  // Assert.
97
103
  expect( result.url ).toBe( 'https://example.com/fallback.svg' );
@@ -146,7 +152,10 @@ describe( 'svgSrcTransformer', () => {
146
152
  const result = ( await svgSrcTransformer(
147
153
  { id: null, url: 'https://example.com/styled.svg' },
148
154
  { key: 'svg' }
149
- ) ) as { html: string; url: string };
155
+ ) ) as {
156
+ html: string;
157
+ url: string;
158
+ };
150
159
 
151
160
  // Assert.
152
161
  expect( result.html ).toContain( 'display: block' );
@@ -1,9 +1,8 @@
1
1
  import {
2
2
  type FontAwesome7IconDefinition,
3
3
  getFontAwesome7IconName,
4
- isDeletedCustomIconLibrary,
5
- resolveCustomIconSvg,
6
4
  resolveFontAwesome7Icon,
5
+ resolveProviderIconSvg,
7
6
  } from '@elementor/editor-controls';
8
7
 
9
8
  import { createTransformer } from '../create-transformer';
@@ -14,6 +13,8 @@ import { svgSrcTransformer } from './svg-src-transformer';
14
13
  const EMPTY_ICON_RESULT = { html: null, url: null };
15
14
  const ICON_SVG_SIZE = '100%';
16
15
  const ICON_SVG_OVERFLOW = 'visible';
16
+ const FONT_AWESOME_LIBRARY_PREFIX = 'fa-';
17
+ const EICONS_LIBRARY = 'eicons';
17
18
  const DEFAULT_SVG_RELATIVE_PATH = 'images/default-svg.svg';
18
19
 
19
20
  type IconValue = {
@@ -35,17 +36,17 @@ export const iconTransformer = createTransformer( async ( value: IconValue, { si
35
36
  return { html: fontAwesomeHtml, url: null };
36
37
  }
37
38
 
38
- if ( isDeletedCustomIconLibrary( library, iconValue ) ) {
39
- return resolveDefaultSvg( signal );
39
+ if ( library.startsWith( FONT_AWESOME_LIBRARY_PREFIX ) || EICONS_LIBRARY === library ) {
40
+ return EMPTY_ICON_RESULT;
40
41
  }
41
42
 
42
- const customHtml = await resolveCustomSvg( library, iconValue, signal );
43
+ const providerHtml = await resolveProviderSvg( library, iconValue, signal );
43
44
 
44
- if ( customHtml ) {
45
- return { html: customHtml, url: null };
45
+ if ( providerHtml ) {
46
+ return { html: providerHtml, url: null };
46
47
  }
47
48
 
48
- return EMPTY_ICON_RESULT;
49
+ return resolveDefaultSvg( signal );
49
50
  } );
50
51
 
51
52
  async function resolveDefaultSvg( signal?: AbortSignal ) {
@@ -64,8 +65,12 @@ async function resolveDefaultSvg( signal?: AbortSignal ) {
64
65
  );
65
66
  }
66
67
 
67
- async function resolveCustomSvg( library: string, iconValue: string, signal?: AbortSignal ): Promise< string | null > {
68
- const markup = await resolveCustomIconSvg( library, iconValue, signal );
68
+ async function resolveProviderSvg(
69
+ library: string,
70
+ iconValue: string,
71
+ signal?: AbortSignal
72
+ ): Promise< string | null > {
73
+ const markup = await resolveProviderIconSvg( library, iconValue, signal );
69
74
 
70
75
  return markup ? processIconSvgContent( markup ) : null;
71
76
  }