@elementor/editor-controls 4.4.0-1110 → 4.4.0-1112

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.
@@ -14,6 +14,7 @@ import { Box, CircularProgress, Divider, Link, Stack, styled, Typography } from
14
14
  import { useDebounceState } from '@elementor/utils';
15
15
  import { __ } from '@wordpress/i18n';
16
16
 
17
+ import { useCustomIconLibraries } from './custom-icon-libraries';
17
18
  import {
18
19
  createIconSelectionValue,
19
20
  filterFontAwesome7Icons,
@@ -78,7 +79,10 @@ export const IconLibraryPopover = ( {
78
79
  ICON_LIBRARY_VIEW_STORAGE_PREFIX
79
80
  );
80
81
  const view = isIconLibraryView( storedView ) ? storedView : DEFAULT_ICON_LIBRARY_VIEW;
81
- const { data: icons = [], isLoading } = useFontAwesome7Catalog( open );
82
+ const { data: fontAwesomeIcons = [], isLoading: isFontAwesomeLoading } = useFontAwesome7Catalog( open );
83
+ const { data: customIcons = [], isLoading: isCustomLoading } = useCustomIconLibraries( open );
84
+ const isLoading = isFontAwesomeLoading || isCustomLoading;
85
+ const icons = useMemo( () => [ ...fontAwesomeIcons, ...customIcons ], [ customIcons, fontAwesomeIcons ] );
82
86
 
83
87
  const items = useMemo(
84
88
  () => createIconLibraryItems( icons, searchValue, activeLibraries ),
@@ -103,7 +107,7 @@ export const IconLibraryPopover = ( {
103
107
  }
104
108
 
105
109
  onSelect( {
106
- value: createIconSelectionValue( icon.library, icon.name ),
110
+ value: icon.glyphClass ?? createIconSelectionValue( icon.library, icon.name ),
107
111
  library: icon.library,
108
112
  } );
109
113
  };
@@ -254,9 +258,7 @@ const IconLibraryRow = ( item: VirtualizedItem< string, string > ) => {
254
258
  flexShrink: 0,
255
259
  } }
256
260
  >
257
- { icon.paths.length > 0 ? (
258
- <FontAwesomeGlyph icon={ icon } size={ ICON_GLYPH_SIZE } color="currentColor" />
259
- ) : null }
261
+ <FontAwesomeGlyph icon={ icon } size={ ICON_GLYPH_SIZE } color="currentColor" />
260
262
  </Box>
261
263
  <Typography variant="caption" color="text.primary" noWrap>
262
264
  { icon.label }
@@ -0,0 +1,53 @@
1
+ const ALLOWED_SVG_TAGS = new Set( [ 'svg', 'g', 'path', 'title', 'desc' ] );
2
+ const ALLOWED_SVG_ATTRS = new Set( [
3
+ 'd',
4
+ 'fill',
5
+ 'viewbox',
6
+ 'xmlns',
7
+ 'width',
8
+ 'height',
9
+ 'transform',
10
+ 'overflow',
11
+ 'aria-hidden',
12
+ 'aria-label',
13
+ 'role',
14
+ ] );
15
+
16
+ export function sanitizeIconSvgMarkup( markup: unknown ): string {
17
+ if ( typeof markup !== 'string' || markup === '' ) {
18
+ return '';
19
+ }
20
+
21
+ const doc = new DOMParser().parseFromString( markup, 'image/svg+xml' );
22
+
23
+ if ( doc.querySelector( 'parsererror' ) ) {
24
+ return '';
25
+ }
26
+
27
+ const svg = doc.querySelector( 'svg' );
28
+
29
+ if ( ! svg ) {
30
+ return '';
31
+ }
32
+
33
+ pruneNode( svg );
34
+
35
+ return svg.tagName.toLowerCase() === 'svg' ? svg.outerHTML : '';
36
+ }
37
+
38
+ function pruneNode( node: Element ): void {
39
+ [ ...node.children ].forEach( ( child ) => {
40
+ if ( ! ALLOWED_SVG_TAGS.has( child.tagName.toLowerCase() ) ) {
41
+ child.remove();
42
+ return;
43
+ }
44
+
45
+ pruneNode( child );
46
+ } );
47
+
48
+ [ ...node.attributes ].forEach( ( attribute ) => {
49
+ if ( ! ALLOWED_SVG_ATTRS.has( attribute.name.toLowerCase() ) ) {
50
+ node.removeAttribute( attribute.name );
51
+ }
52
+ } );
53
+ }
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import { Box, CardMedia, CircularProgress } from '@elementor/ui';
3
3
  import { __ } from '@wordpress/i18n';
4
4
 
5
+ import { useCustomIconLibraries } from './icon-library/custom-icon-libraries';
5
6
  import { findFontAwesome7Icon, type FontAwesome7Icon } from './icon-library/font-awesome-7-catalog';
6
7
  import { FontAwesomeGlyph } from './icon-library/font-awesome-glyph';
7
8
  import { useFontAwesome7Catalog } from './icon-library/use-font-awesome-7-catalog';
@@ -18,10 +19,14 @@ type SvgMediaPreviewProps = {
18
19
 
19
20
  export const SvgMediaPreview = ( { isFetching, src, iconClassName, iconLibrary }: SvgMediaPreviewProps ) => {
20
21
  const shouldLoadIconCatalog = Boolean( iconClassName && iconLibrary );
21
- const { data: icons = [], isLoading } = useFontAwesome7Catalog( shouldLoadIconCatalog );
22
+ const { data: fontAwesomeIcons = [], isLoading: isFontAwesomeLoading } =
23
+ useFontAwesome7Catalog( shouldLoadIconCatalog );
24
+ const { data: customIcons = [], isLoading: isCustomLoading } = useCustomIconLibraries( shouldLoadIconCatalog );
25
+ const icons = [ ...fontAwesomeIcons, ...customIcons ];
22
26
  const selectedIcon = findFontAwesome7Icon( icons, iconClassName, iconLibrary );
27
+ const isLoadingCatalog = shouldLoadIconCatalog && ( isFontAwesomeLoading || isCustomLoading );
23
28
 
24
- if ( isFetching || ( shouldLoadIconCatalog && isLoading ) ) {
29
+ if ( isFetching || isLoadingCatalog ) {
25
30
  return <CircularProgress role="progressbar" />;
26
31
  }
27
32
 
package/src/index.ts CHANGED
@@ -37,6 +37,7 @@ export { TransformSettingsControl } from './controls/transform-control/transform
37
37
  export { TransitionRepeaterControl } from './controls/transition-control/transition-repeater-control';
38
38
  export { PopoverContent } from './components/popover-content';
39
39
  export { enqueueFont } from './controls/font-family-control/enqueue-font';
40
+ export { isDeletedCustomIconLibrary, resolveCustomIconSvg } from './controls/icon-library/custom-icon-libraries';
40
41
  export {
41
42
  getFontAwesome7IconName,
42
43
  resetFontAwesome7IconsCache,