@elementor/editor-canvas 4.4.0-1077 → 4.4.0-1079

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
@@ -2107,6 +2107,9 @@ var timeRangeTransformer = createTransformer((value) => {
2107
2107
  };
2108
2108
  });
2109
2109
 
2110
+ // src/transformers/shared/icon-transformer.ts
2111
+ var import_editor_controls = require("@elementor/editor-controls");
2112
+
2110
2113
  // src/transformers/shared/process-svg-content.ts
2111
2114
  var import_dompurify2 = __toESM(require("dompurify"));
2112
2115
  var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
@@ -2129,128 +2132,36 @@ function processSvgContent(svgText) {
2129
2132
  }
2130
2133
 
2131
2134
  // src/transformers/shared/icon-transformer.ts
2132
- var FONT_AWESOME_JSON = {
2133
- width: 0,
2134
- height: 1,
2135
- aliases: 2,
2136
- unicode: 3,
2137
- path: 4
2138
- };
2139
- var fontAwesomeJsonCache = /* @__PURE__ */ new Map();
2135
+ var EMPTY_ICON_RESULT = { html: null, url: null };
2136
+ var ICON_SVG_SIZE = "100%";
2137
+ var ICON_SVG_OVERFLOW = "visible";
2140
2138
  var iconTransformer = createTransformer(async (value, { signal }) => {
2141
2139
  const iconValue = typeof value.value === "string" ? value.value : null;
2142
2140
  const library = typeof value.library === "string" ? value.library : null;
2143
2141
  if (!iconValue || !library) {
2144
- return { html: null, url: null };
2142
+ return EMPTY_ICON_RESULT;
2145
2143
  }
2146
- const iconName = getFontAwesomeIconName(iconValue);
2147
- const jsonFileName = getFontAwesomeJsonFileName(library);
2148
- if (!iconName || !jsonFileName) {
2149
- return { html: null, url: null };
2144
+ const iconName = (0, import_editor_controls.getFontAwesome7IconName)(iconValue);
2145
+ if (!iconName) {
2146
+ return EMPTY_ICON_RESULT;
2150
2147
  }
2151
- const icons = await fetchFontAwesomeIcons(jsonFileName, signal);
2152
- const iconData = icons?.[iconName];
2148
+ const iconData = await (0, import_editor_controls.resolveFontAwesome7Icon)(library, iconName, signal);
2153
2149
  if (!iconData) {
2154
- return { html: null, url: null };
2150
+ return EMPTY_ICON_RESULT;
2155
2151
  }
2156
2152
  const svgText = buildFontAwesomeSvg(iconData);
2157
2153
  if (!svgText) {
2158
- return { html: null, url: null };
2154
+ return EMPTY_ICON_RESULT;
2159
2155
  }
2160
2156
  const html = processIconSvgContent(svgText);
2161
2157
  return { html, url: null };
2162
2158
  });
2163
- function getFontAwesomeIconName(iconValue) {
2164
- const match = iconValue.match(/^fa\S*\s+fa-(.+)$/);
2165
- return match?.[1] ?? null;
2166
- }
2167
- function getFontAwesomeJsonFileName(library) {
2168
- const fileName = library.replace(/^fa-/, "");
2169
- const config = getFontAwesome7EditorConfig();
2170
- if (!config?.jsonFiles.includes(fileName)) {
2171
- return null;
2172
- }
2173
- return fileName;
2174
- }
2175
- function getFontAwesome7EditorConfig() {
2176
- const config = window.elementorCommon?.config?.fontAwesome?.v7;
2177
- if (!config || !Array.isArray(config.jsonFiles) || typeof config.jsonBaseUrl !== "string" || config.jsonBaseUrl === "") {
2178
- return null;
2179
- }
2180
- return {
2181
- jsonFiles: config.jsonFiles,
2182
- jsonBaseUrl: config.jsonBaseUrl
2183
- };
2184
- }
2185
- async function fetchFontAwesomeIcons(jsonFileName, signal) {
2186
- const cached = fontAwesomeJsonCache.get(jsonFileName);
2187
- if (cached) {
2188
- return cached;
2189
- }
2190
- const icons = await loadFontAwesomeIcons(jsonFileName, signal);
2191
- if (icons) {
2192
- fontAwesomeJsonCache.set(jsonFileName, icons);
2193
- }
2194
- return icons;
2195
- }
2196
- async function loadFontAwesomeIcons(jsonFileName, signal) {
2197
- const config = getFontAwesome7EditorConfig();
2198
- if (!config?.jsonFiles.includes(jsonFileName)) {
2199
- return null;
2200
- }
2201
- try {
2202
- const response = await fetch(`${config.jsonBaseUrl}${jsonFileName}.json`, {
2203
- signal
2204
- });
2205
- if (!response.ok) {
2206
- return null;
2207
- }
2208
- const data = await response.json();
2209
- const icons = data.icons;
2210
- if (!icons || typeof icons !== "object") {
2211
- return null;
2212
- }
2213
- return indexFontAwesomeIcons(icons);
2214
- } catch {
2215
- return null;
2216
- }
2217
- }
2218
- function indexFontAwesomeIcons(icons) {
2219
- const index = {};
2220
- for (const [name, iconData] of Object.entries(icons)) {
2221
- if (!isValidIconTuple(iconData)) {
2222
- continue;
2223
- }
2224
- index[name] = iconData;
2225
- for (const alias of iconData[FONT_AWESOME_JSON.aliases]) {
2226
- if (typeof alias === "string" && alias !== "" && !index[alias]) {
2227
- index[alias] = iconData;
2228
- }
2229
- }
2230
- }
2231
- return index;
2232
- }
2233
- function isValidIconTuple(iconData) {
2234
- return Array.isArray(iconData) && iconData.length >= 5 && typeof iconData[FONT_AWESOME_JSON.width] === "number" && typeof iconData[FONT_AWESOME_JSON.height] === "number" && Array.isArray(iconData[FONT_AWESOME_JSON.aliases]);
2235
- }
2236
2159
  function buildFontAwesomeSvg(iconData) {
2237
- const width = iconData[FONT_AWESOME_JSON.width];
2238
- const height = iconData[FONT_AWESOME_JSON.height];
2239
- const paths = normalizePaths(iconData[FONT_AWESOME_JSON.path]);
2240
- if (paths.length === 0) {
2160
+ if (iconData.paths.length === 0) {
2241
2161
  return null;
2242
2162
  }
2243
- const pathMarkup = paths.map((path) => `<path d="${escapeSvgPath(path)}"></path>`).join("");
2244
- return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}">${pathMarkup}</svg>`;
2245
- }
2246
- function normalizePaths(pathData) {
2247
- if (typeof pathData === "string" && pathData !== "") {
2248
- return [pathData];
2249
- }
2250
- if (!Array.isArray(pathData)) {
2251
- return [];
2252
- }
2253
- return pathData.filter((path) => typeof path === "string" && path !== "");
2163
+ const pathMarkup = iconData.paths.map((path) => `<path d="${escapeSvgPath(path)}"></path>`).join("");
2164
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${iconData.width} ${iconData.height}">${pathMarkup}</svg>`;
2254
2165
  }
2255
2166
  function escapeSvgPath(path) {
2256
2167
  return path.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -2267,9 +2178,9 @@ function processIconSvgContent(svgText) {
2267
2178
  return null;
2268
2179
  }
2269
2180
  svgElement.setAttribute("aria-hidden", "true");
2270
- svgElement.style.setProperty("width", "100%");
2271
- svgElement.style.setProperty("height", "100%");
2272
- svgElement.style.setProperty("overflow", "visible");
2181
+ svgElement.style.setProperty("width", ICON_SVG_SIZE);
2182
+ svgElement.style.setProperty("height", ICON_SVG_SIZE);
2183
+ svgElement.style.setProperty("overflow", ICON_SVG_OVERFLOW);
2273
2184
  return svgElement.outerHTML;
2274
2185
  }
2275
2186
 
@@ -2665,10 +2576,10 @@ var transformSkewTransformer = createTransformer((value) => {
2665
2576
  });
2666
2577
 
2667
2578
  // src/transformers/styles/transition-transformer.ts
2668
- var import_editor_controls = require("@elementor/editor-controls");
2579
+ var import_editor_controls2 = require("@elementor/editor-controls");
2669
2580
  var getAllowedProperties = () => {
2670
2581
  const allowedProperties = /* @__PURE__ */ new Set();
2671
- import_editor_controls.transitionProperties.forEach((category) => {
2582
+ import_editor_controls2.transitionProperties.forEach((category) => {
2672
2583
  category.properties.forEach((property) => {
2673
2584
  allowedProperties.add(property.value);
2674
2585
  });
@@ -3505,7 +3416,7 @@ var ReplacementBase = class {
3505
3416
  // src/legacy/replacements/inline-editing/canvas-inline-editor.tsx
3506
3417
  var React10 = __toESM(require("react"));
3507
3418
  var import_react18 = require("react");
3508
- var import_editor_controls2 = require("@elementor/editor-controls");
3419
+ var import_editor_controls3 = require("@elementor/editor-controls");
3509
3420
  var import_ui5 = require("@elementor/ui");
3510
3421
  var import_react19 = require("@floating-ui/react");
3511
3422
 
@@ -3676,7 +3587,7 @@ var CanvasInlineEditor = ({
3676
3587
  return null;
3677
3588
  }
3678
3589
  return /* @__PURE__ */ React10.createElement(import_ui5.ThemeProvider, null, /* @__PURE__ */ React10.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React10.createElement(
3679
- import_editor_controls2.InlineEditor,
3590
+ import_editor_controls3.InlineEditor,
3680
3591
  {
3681
3592
  onEditorCreate: setEditor,
3682
3593
  mountElement: contentElement,
@@ -3728,7 +3639,7 @@ var InlineEditingToolbar = ({ anchor, editor, id }) => {
3728
3639
  pointerEvents: "none"
3729
3640
  }
3730
3641
  },
3731
- /* @__PURE__ */ React10.createElement(import_editor_controls2.InlineEditorToolbar, { editor, elementId: id })
3642
+ /* @__PURE__ */ React10.createElement(import_editor_controls3.InlineEditorToolbar, { editor, elementId: id })
3732
3643
  ));
3733
3644
  };
3734
3645
 
package/dist/index.mjs CHANGED
@@ -2059,6 +2059,12 @@ var timeRangeTransformer = createTransformer((value) => {
2059
2059
  };
2060
2060
  });
2061
2061
 
2062
+ // src/transformers/shared/icon-transformer.ts
2063
+ import {
2064
+ getFontAwesome7IconName,
2065
+ resolveFontAwesome7Icon
2066
+ } from "@elementor/editor-controls";
2067
+
2062
2068
  // src/transformers/shared/process-svg-content.ts
2063
2069
  import DOMPurify2 from "dompurify";
2064
2070
  var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
@@ -2081,128 +2087,36 @@ function processSvgContent(svgText) {
2081
2087
  }
2082
2088
 
2083
2089
  // src/transformers/shared/icon-transformer.ts
2084
- var FONT_AWESOME_JSON = {
2085
- width: 0,
2086
- height: 1,
2087
- aliases: 2,
2088
- unicode: 3,
2089
- path: 4
2090
- };
2091
- var fontAwesomeJsonCache = /* @__PURE__ */ new Map();
2090
+ var EMPTY_ICON_RESULT = { html: null, url: null };
2091
+ var ICON_SVG_SIZE = "100%";
2092
+ var ICON_SVG_OVERFLOW = "visible";
2092
2093
  var iconTransformer = createTransformer(async (value, { signal }) => {
2093
2094
  const iconValue = typeof value.value === "string" ? value.value : null;
2094
2095
  const library = typeof value.library === "string" ? value.library : null;
2095
2096
  if (!iconValue || !library) {
2096
- return { html: null, url: null };
2097
+ return EMPTY_ICON_RESULT;
2097
2098
  }
2098
- const iconName = getFontAwesomeIconName(iconValue);
2099
- const jsonFileName = getFontAwesomeJsonFileName(library);
2100
- if (!iconName || !jsonFileName) {
2101
- return { html: null, url: null };
2099
+ const iconName = getFontAwesome7IconName(iconValue);
2100
+ if (!iconName) {
2101
+ return EMPTY_ICON_RESULT;
2102
2102
  }
2103
- const icons = await fetchFontAwesomeIcons(jsonFileName, signal);
2104
- const iconData = icons?.[iconName];
2103
+ const iconData = await resolveFontAwesome7Icon(library, iconName, signal);
2105
2104
  if (!iconData) {
2106
- return { html: null, url: null };
2105
+ return EMPTY_ICON_RESULT;
2107
2106
  }
2108
2107
  const svgText = buildFontAwesomeSvg(iconData);
2109
2108
  if (!svgText) {
2110
- return { html: null, url: null };
2109
+ return EMPTY_ICON_RESULT;
2111
2110
  }
2112
2111
  const html = processIconSvgContent(svgText);
2113
2112
  return { html, url: null };
2114
2113
  });
2115
- function getFontAwesomeIconName(iconValue) {
2116
- const match = iconValue.match(/^fa\S*\s+fa-(.+)$/);
2117
- return match?.[1] ?? null;
2118
- }
2119
- function getFontAwesomeJsonFileName(library) {
2120
- const fileName = library.replace(/^fa-/, "");
2121
- const config = getFontAwesome7EditorConfig();
2122
- if (!config?.jsonFiles.includes(fileName)) {
2123
- return null;
2124
- }
2125
- return fileName;
2126
- }
2127
- function getFontAwesome7EditorConfig() {
2128
- const config = window.elementorCommon?.config?.fontAwesome?.v7;
2129
- if (!config || !Array.isArray(config.jsonFiles) || typeof config.jsonBaseUrl !== "string" || config.jsonBaseUrl === "") {
2130
- return null;
2131
- }
2132
- return {
2133
- jsonFiles: config.jsonFiles,
2134
- jsonBaseUrl: config.jsonBaseUrl
2135
- };
2136
- }
2137
- async function fetchFontAwesomeIcons(jsonFileName, signal) {
2138
- const cached = fontAwesomeJsonCache.get(jsonFileName);
2139
- if (cached) {
2140
- return cached;
2141
- }
2142
- const icons = await loadFontAwesomeIcons(jsonFileName, signal);
2143
- if (icons) {
2144
- fontAwesomeJsonCache.set(jsonFileName, icons);
2145
- }
2146
- return icons;
2147
- }
2148
- async function loadFontAwesomeIcons(jsonFileName, signal) {
2149
- const config = getFontAwesome7EditorConfig();
2150
- if (!config?.jsonFiles.includes(jsonFileName)) {
2151
- return null;
2152
- }
2153
- try {
2154
- const response = await fetch(`${config.jsonBaseUrl}${jsonFileName}.json`, {
2155
- signal
2156
- });
2157
- if (!response.ok) {
2158
- return null;
2159
- }
2160
- const data = await response.json();
2161
- const icons = data.icons;
2162
- if (!icons || typeof icons !== "object") {
2163
- return null;
2164
- }
2165
- return indexFontAwesomeIcons(icons);
2166
- } catch {
2167
- return null;
2168
- }
2169
- }
2170
- function indexFontAwesomeIcons(icons) {
2171
- const index = {};
2172
- for (const [name, iconData] of Object.entries(icons)) {
2173
- if (!isValidIconTuple(iconData)) {
2174
- continue;
2175
- }
2176
- index[name] = iconData;
2177
- for (const alias of iconData[FONT_AWESOME_JSON.aliases]) {
2178
- if (typeof alias === "string" && alias !== "" && !index[alias]) {
2179
- index[alias] = iconData;
2180
- }
2181
- }
2182
- }
2183
- return index;
2184
- }
2185
- function isValidIconTuple(iconData) {
2186
- return Array.isArray(iconData) && iconData.length >= 5 && typeof iconData[FONT_AWESOME_JSON.width] === "number" && typeof iconData[FONT_AWESOME_JSON.height] === "number" && Array.isArray(iconData[FONT_AWESOME_JSON.aliases]);
2187
- }
2188
2114
  function buildFontAwesomeSvg(iconData) {
2189
- const width = iconData[FONT_AWESOME_JSON.width];
2190
- const height = iconData[FONT_AWESOME_JSON.height];
2191
- const paths = normalizePaths(iconData[FONT_AWESOME_JSON.path]);
2192
- if (paths.length === 0) {
2115
+ if (iconData.paths.length === 0) {
2193
2116
  return null;
2194
2117
  }
2195
- const pathMarkup = paths.map((path) => `<path d="${escapeSvgPath(path)}"></path>`).join("");
2196
- return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}">${pathMarkup}</svg>`;
2197
- }
2198
- function normalizePaths(pathData) {
2199
- if (typeof pathData === "string" && pathData !== "") {
2200
- return [pathData];
2201
- }
2202
- if (!Array.isArray(pathData)) {
2203
- return [];
2204
- }
2205
- return pathData.filter((path) => typeof path === "string" && path !== "");
2118
+ const pathMarkup = iconData.paths.map((path) => `<path d="${escapeSvgPath(path)}"></path>`).join("");
2119
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${iconData.width} ${iconData.height}">${pathMarkup}</svg>`;
2206
2120
  }
2207
2121
  function escapeSvgPath(path) {
2208
2122
  return path.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -2219,9 +2133,9 @@ function processIconSvgContent(svgText) {
2219
2133
  return null;
2220
2134
  }
2221
2135
  svgElement.setAttribute("aria-hidden", "true");
2222
- svgElement.style.setProperty("width", "100%");
2223
- svgElement.style.setProperty("height", "100%");
2224
- svgElement.style.setProperty("overflow", "visible");
2136
+ svgElement.style.setProperty("width", ICON_SVG_SIZE);
2137
+ svgElement.style.setProperty("height", ICON_SVG_SIZE);
2138
+ svgElement.style.setProperty("overflow", ICON_SVG_OVERFLOW);
2225
2139
  return svgElement.outerHTML;
2226
2140
  }
2227
2141
 
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-1077",
4
+ "version": "4.4.0-1079",
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-1077",
41
- "@elementor/editor-controls": "4.4.0-1077",
42
- "@elementor/editor-documents": "4.4.0-1077",
43
- "@elementor/editor-elements": "4.4.0-1077",
44
- "@elementor/editor-interactions": "4.4.0-1077",
45
- "@elementor/editor-mcp": "4.4.0-1077",
46
- "@elementor/editor-notifications": "4.4.0-1077",
47
- "@elementor/editor-props": "4.4.0-1077",
48
- "@elementor/editor-responsive": "4.4.0-1077",
49
- "@elementor/editor-styles": "4.4.0-1077",
50
- "@elementor/editor-styles-repository": "4.4.0-1077",
51
- "@elementor/editor-ui": "4.4.0-1077",
52
- "@elementor/editor-v1-adapters": "4.4.0-1077",
53
- "@elementor/events": "4.4.0-1077",
54
- "@elementor/http-client": "4.4.0-1077",
55
- "@elementor/schema": "4.4.0-1077",
56
- "@elementor/twing": "4.4.0-1077",
40
+ "@elementor/editor": "4.4.0-1079",
41
+ "@elementor/editor-controls": "4.4.0-1079",
42
+ "@elementor/editor-documents": "4.4.0-1079",
43
+ "@elementor/editor-elements": "4.4.0-1079",
44
+ "@elementor/editor-interactions": "4.4.0-1079",
45
+ "@elementor/editor-mcp": "4.4.0-1079",
46
+ "@elementor/editor-notifications": "4.4.0-1079",
47
+ "@elementor/editor-props": "4.4.0-1079",
48
+ "@elementor/editor-responsive": "4.4.0-1079",
49
+ "@elementor/editor-styles": "4.4.0-1079",
50
+ "@elementor/editor-styles-repository": "4.4.0-1079",
51
+ "@elementor/editor-ui": "4.4.0-1079",
52
+ "@elementor/editor-v1-adapters": "4.4.0-1079",
53
+ "@elementor/events": "4.4.0-1079",
54
+ "@elementor/http-client": "4.4.0-1079",
55
+ "@elementor/schema": "4.4.0-1079",
56
+ "@elementor/twing": "4.4.0-1079",
57
57
  "@elementor/ui": "1.37.5",
58
- "@elementor/utils": "4.4.0-1077",
59
- "@elementor/wp-media": "4.4.0-1077",
58
+ "@elementor/utils": "4.4.0-1079",
59
+ "@elementor/wp-media": "4.4.0-1079",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0",
62
62
  "dompurify": "^3.2.6"
@@ -1,10 +1,10 @@
1
+ import { resetFontAwesome7IconsCache } from '@elementor/editor-controls';
1
2
  import { iconPropTypeUtil, stringPropTypeUtil } from '@elementor/editor-props';
2
3
 
3
4
  import { iconPropType } from '../../../__tests__/prop-types';
4
5
  import { initSettingsTransformers } from '../../../init-settings-transformers';
5
6
  import { createPropsResolver } from '../../../renderers/create-props-resolver';
6
7
  import { settingsTransformersRegistry } from '../../../settings-transformers-registry';
7
- import { resetFontAwesomeIconsCache } from '../icon-transformer';
8
8
 
9
9
  const STAR_PATH = 'M0 0h100v100H0z';
10
10
  const STAR_WIDTH = 576;
@@ -44,7 +44,7 @@ describe( 'iconTransformer', () => {
44
44
 
45
45
  beforeEach( () => {
46
46
  jest.clearAllMocks();
47
- resetFontAwesomeIconsCache();
47
+ resetFontAwesome7IconsCache();
48
48
  initSettingsTransformers();
49
49
  window.elementorCommon = {
50
50
  config: {
@@ -1,55 +1,46 @@
1
+ import {
2
+ type FontAwesome7IconDefinition,
3
+ getFontAwesome7IconName,
4
+ resolveFontAwesome7Icon,
5
+ } from '@elementor/editor-controls';
6
+
1
7
  import { createTransformer } from '../create-transformer';
2
8
  import type { TransformerOptions } from '../types';
3
9
  import { processSvgContent } from './process-svg-content';
4
10
 
11
+ const EMPTY_ICON_RESULT = { html: null, url: null };
12
+ const ICON_SVG_SIZE = '100%';
13
+ const ICON_SVG_OVERFLOW = 'visible';
14
+
5
15
  type IconValue = {
6
16
  value?: unknown;
7
17
  library?: unknown;
8
18
  };
9
19
 
10
- type FontAwesomeIconJson = [ number, number, unknown[], unknown, string | string[] ];
11
-
12
- type FontAwesome7EditorConfig = {
13
- jsonFiles: string[];
14
- jsonBaseUrl: string;
15
- };
16
-
17
- const FONT_AWESOME_JSON = {
18
- width: 0,
19
- height: 1,
20
- aliases: 2,
21
- unicode: 3,
22
- path: 4,
23
- } as const;
24
-
25
- const fontAwesomeJsonCache = new Map< string, Record< string, FontAwesomeIconJson > >();
26
-
27
20
  export const iconTransformer = createTransformer( async ( value: IconValue, { signal }: TransformerOptions ) => {
28
21
  const iconValue = typeof value.value === 'string' ? value.value : null;
29
22
  const library = typeof value.library === 'string' ? value.library : null;
30
23
 
31
24
  if ( ! iconValue || ! library ) {
32
- return { html: null, url: null };
25
+ return EMPTY_ICON_RESULT;
33
26
  }
34
27
 
35
- const iconName = getFontAwesomeIconName( iconValue );
36
- const jsonFileName = getFontAwesomeJsonFileName( library );
28
+ const iconName = getFontAwesome7IconName( iconValue );
37
29
 
38
- if ( ! iconName || ! jsonFileName ) {
39
- return { html: null, url: null };
30
+ if ( ! iconName ) {
31
+ return EMPTY_ICON_RESULT;
40
32
  }
41
33
 
42
- const icons = await fetchFontAwesomeIcons( jsonFileName, signal );
43
- const iconData = icons?.[ iconName ];
34
+ const iconData = await resolveFontAwesome7Icon( library, iconName, signal );
44
35
 
45
36
  if ( ! iconData ) {
46
- return { html: null, url: null };
37
+ return EMPTY_ICON_RESULT;
47
38
  }
48
39
 
49
40
  const svgText = buildFontAwesomeSvg( iconData );
50
41
 
51
42
  if ( ! svgText ) {
52
- return { html: null, url: null };
43
+ return EMPTY_ICON_RESULT;
53
44
  }
54
45
 
55
46
  const html = processIconSvgContent( svgText );
@@ -57,146 +48,14 @@ export const iconTransformer = createTransformer( async ( value: IconValue, { si
57
48
  return { html, url: null };
58
49
  } );
59
50
 
60
- function getFontAwesomeIconName( iconValue: string ): string | null {
61
- const match = iconValue.match( /^fa\S*\s+fa-(.+)$/ );
62
-
63
- return match?.[ 1 ] ?? null;
64
- }
65
-
66
- function getFontAwesomeJsonFileName( library: string ): string | null {
67
- const fileName = library.replace( /^fa-/, '' );
68
- const config = getFontAwesome7EditorConfig();
69
-
70
- if ( ! config?.jsonFiles.includes( fileName ) ) {
71
- return null;
72
- }
73
-
74
- return fileName;
75
- }
76
-
77
- function getFontAwesome7EditorConfig(): FontAwesome7EditorConfig | null {
78
- const config = window.elementorCommon?.config?.fontAwesome?.v7;
79
-
80
- if (
81
- ! config ||
82
- ! Array.isArray( config.jsonFiles ) ||
83
- typeof config.jsonBaseUrl !== 'string' ||
84
- config.jsonBaseUrl === ''
85
- ) {
86
- return null;
87
- }
88
-
89
- return {
90
- jsonFiles: config.jsonFiles,
91
- jsonBaseUrl: config.jsonBaseUrl,
92
- };
93
- }
94
-
95
- async function fetchFontAwesomeIcons(
96
- jsonFileName: string,
97
- signal?: AbortSignal
98
- ): Promise< Record< string, FontAwesomeIconJson > | null > {
99
- const cached = fontAwesomeJsonCache.get( jsonFileName );
100
-
101
- if ( cached ) {
102
- return cached;
103
- }
104
-
105
- const icons = await loadFontAwesomeIcons( jsonFileName, signal );
106
-
107
- if ( icons ) {
108
- fontAwesomeJsonCache.set( jsonFileName, icons );
109
- }
110
-
111
- return icons;
112
- }
113
-
114
- async function loadFontAwesomeIcons(
115
- jsonFileName: string,
116
- signal?: AbortSignal
117
- ): Promise< Record< string, FontAwesomeIconJson > | null > {
118
- const config = getFontAwesome7EditorConfig();
119
-
120
- if ( ! config?.jsonFiles.includes( jsonFileName ) ) {
121
- return null;
122
- }
123
-
124
- try {
125
- const response = await fetch( `${ config.jsonBaseUrl }${ jsonFileName }.json`, {
126
- signal,
127
- } );
128
-
129
- if ( ! response.ok ) {
130
- return null;
131
- }
132
-
133
- const data = ( await response.json() ) as { icons?: Record< string, FontAwesomeIconJson > };
134
- const icons = data.icons;
135
-
136
- if ( ! icons || typeof icons !== 'object' ) {
137
- return null;
138
- }
139
-
140
- return indexFontAwesomeIcons( icons );
141
- } catch {
142
- return null;
143
- }
144
- }
145
-
146
- function indexFontAwesomeIcons( icons: Record< string, FontAwesomeIconJson > ): Record< string, FontAwesomeIconJson > {
147
- const index: Record< string, FontAwesomeIconJson > = {};
148
-
149
- for ( const [ name, iconData ] of Object.entries( icons ) ) {
150
- if ( ! isValidIconTuple( iconData ) ) {
151
- continue;
152
- }
153
-
154
- index[ name ] = iconData;
155
-
156
- for ( const alias of iconData[ FONT_AWESOME_JSON.aliases ] ) {
157
- if ( typeof alias === 'string' && alias !== '' && ! index[ alias ] ) {
158
- index[ alias ] = iconData;
159
- }
160
- }
161
- }
162
-
163
- return index;
164
- }
165
-
166
- function isValidIconTuple( iconData: unknown ): iconData is FontAwesomeIconJson {
167
- return (
168
- Array.isArray( iconData ) &&
169
- iconData.length >= 5 &&
170
- typeof iconData[ FONT_AWESOME_JSON.width ] === 'number' &&
171
- typeof iconData[ FONT_AWESOME_JSON.height ] === 'number' &&
172
- Array.isArray( iconData[ FONT_AWESOME_JSON.aliases ] )
173
- );
174
- }
175
-
176
- function buildFontAwesomeSvg( iconData: FontAwesomeIconJson ): string | null {
177
- const width = iconData[ FONT_AWESOME_JSON.width ];
178
- const height = iconData[ FONT_AWESOME_JSON.height ];
179
- const paths = normalizePaths( iconData[ FONT_AWESOME_JSON.path ] );
180
-
181
- if ( paths.length === 0 ) {
51
+ function buildFontAwesomeSvg( iconData: FontAwesome7IconDefinition ): string | null {
52
+ if ( iconData.paths.length === 0 ) {
182
53
  return null;
183
54
  }
184
55
 
185
- const pathMarkup = paths.map( ( path ) => `<path d="${ escapeSvgPath( path ) }"></path>` ).join( '' );
56
+ const pathMarkup = iconData.paths.map( ( path ) => `<path d="${ escapeSvgPath( path ) }"></path>` ).join( '' );
186
57
 
187
- return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${ width } ${ height }">${ pathMarkup }</svg>`;
188
- }
189
-
190
- function normalizePaths( pathData: string | string[] ): string[] {
191
- if ( typeof pathData === 'string' && pathData !== '' ) {
192
- return [ pathData ];
193
- }
194
-
195
- if ( ! Array.isArray( pathData ) ) {
196
- return [];
197
- }
198
-
199
- return pathData.filter( ( path ): path is string => typeof path === 'string' && path !== '' );
58
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${ iconData.width } ${ iconData.height }">${ pathMarkup }</svg>`;
200
59
  }
201
60
 
202
61
  function escapeSvgPath( path: string ): string {
@@ -219,13 +78,9 @@ function processIconSvgContent( svgText: string ): string | null {
219
78
  }
220
79
 
221
80
  svgElement.setAttribute( 'aria-hidden', 'true' );
222
- svgElement.style.setProperty( 'width', '100%' );
223
- svgElement.style.setProperty( 'height', '100%' );
224
- svgElement.style.setProperty( 'overflow', 'visible' );
81
+ svgElement.style.setProperty( 'width', ICON_SVG_SIZE );
82
+ svgElement.style.setProperty( 'height', ICON_SVG_SIZE );
83
+ svgElement.style.setProperty( 'overflow', ICON_SVG_OVERFLOW );
225
84
 
226
85
  return svgElement.outerHTML;
227
86
  }
228
-
229
- export function resetFontAwesomeIconsCache() {
230
- fontAwesomeJsonCache.clear();
231
- }