@elementor/editor-controls 3.32.0-84 → 3.32.0-87

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-controls",
3
3
  "description": "This package contains the controls model and utils for the Elementor editor",
4
- "version": "3.32.0-84",
4
+ "version": "3.32.0-87",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -40,21 +40,21 @@
40
40
  "dev": "tsup --config=../../tsup.dev.ts"
41
41
  },
42
42
  "dependencies": {
43
- "@elementor/editor-current-user": "3.32.0-84",
44
- "@elementor/editor-elements": "3.32.0-84",
45
- "@elementor/editor-props": "3.32.0-84",
46
- "@elementor/editor-responsive": "3.32.0-84",
47
- "@elementor/editor-ui": "3.32.0-84",
48
- "@elementor/editor-v1-adapters": "3.32.0-84",
49
- "@elementor/env": "3.32.0-84",
50
- "@elementor/http-client": "3.32.0-84",
43
+ "@elementor/editor-current-user": "3.32.0-87",
44
+ "@elementor/editor-elements": "3.32.0-87",
45
+ "@elementor/editor-props": "3.32.0-87",
46
+ "@elementor/editor-responsive": "3.32.0-87",
47
+ "@elementor/editor-ui": "3.32.0-87",
48
+ "@elementor/editor-v1-adapters": "3.32.0-87",
49
+ "@elementor/env": "3.32.0-87",
50
+ "@elementor/http-client": "3.32.0-87",
51
51
  "@elementor/icons": "^1.51.1",
52
- "@elementor/locations": "3.32.0-84",
53
- "@elementor/query": "3.32.0-84",
54
- "@elementor/session": "3.32.0-84",
52
+ "@elementor/locations": "3.32.0-87",
53
+ "@elementor/query": "3.32.0-87",
54
+ "@elementor/session": "3.32.0-87",
55
55
  "@elementor/ui": "1.36.8",
56
- "@elementor/utils": "3.32.0-84",
57
- "@elementor/wp-media": "3.32.0-84",
56
+ "@elementor/utils": "3.32.0-87",
57
+ "@elementor/wp-media": "3.32.0-87",
58
58
  "@wordpress/i18n": "^5.13.0",
59
59
  "@monaco-editor/react": "^4.7.0"
60
60
  },
@@ -83,7 +83,7 @@ export const RepeaterContextProvider = < T extends RepeatablePropValue = Repeata
83
83
  const popoverState = usePopupState( { variant: 'popover' } );
84
84
 
85
85
  const addItem = ( ev: React.MouseEvent, config?: AddItem< T > ) => {
86
- const item = config?.item ?? initial;
86
+ const item = config?.item ?? { ...initial };
87
87
  const newIndex = config?.index ?? items.length;
88
88
  const newItems = [ ...items ];
89
89
 
@@ -6,7 +6,6 @@ import { EMPTY_OPEN_ITEM, useRepeaterContext } from '../context/repeater-context
6
6
 
7
7
  export const EditItemPopover = ( { children }: { children: React.ReactNode } ) => {
8
8
  const { popoverState, openItemIndex, isOpen, rowRef, setOpenItemIndex, setRowRef, items } = useRepeaterContext();
9
- const popoverProps = bindPopover( popoverState );
10
9
 
11
10
  if ( ! isOpen || ! rowRef ) {
12
11
  return null;
@@ -15,8 +14,8 @@ export const EditItemPopover = ( { children }: { children: React.ReactNode } ) =
15
14
  const bind = items[ openItemIndex ].item.$$type;
16
15
 
17
16
  const onClose = () => {
18
- popoverProps.onClose?.();
19
17
  setRowRef( null );
18
+ popoverState.setAnchorEl( null );
20
19
  setOpenItemIndex( EMPTY_OPEN_ITEM );
21
20
  };
22
21
 
@@ -29,8 +28,7 @@ export const EditItemPopover = ( { children }: { children: React.ReactNode } ) =
29
28
  },
30
29
  } }
31
30
  anchorOrigin={ { vertical: 'bottom', horizontal: 'left' } }
32
- { ...popoverProps }
33
- anchorEl={ rowRef }
31
+ { ...bindPopover( popoverState ) }
34
32
  onClose={ onClose }
35
33
  >
36
34
  <PropKeyProvider bind={ String( openItemIndex ) }>
@@ -26,6 +26,15 @@ export const Item = < T extends RepeatablePropValue >( {
26
26
  setOpenItemIndex( index );
27
27
  };
28
28
 
29
+ const setRef = ( ref: HTMLDivElement | null ) => {
30
+ if ( ! ref || openItemIndex !== index || ref === popoverState.anchorEl ) {
31
+ return;
32
+ }
33
+
34
+ setRowRef( ref );
35
+ popoverState.setAnchorEl( ref );
36
+ };
37
+
29
38
  return (
30
39
  <>
31
40
  <UnstableTag
@@ -38,7 +47,7 @@ export const Item = < T extends RepeatablePropValue >( {
38
47
  }
39
48
  showActionsOnHover
40
49
  fullWidth
41
- ref={ ( ref ) => ref && openItemIndex === index && setRowRef( ref ) }
50
+ ref={ setRef }
42
51
  variant="outlined"
43
52
  aria-label={ __( 'Open item', 'elementor' ) }
44
53
  sx={ { minHeight: ( theme ) => theme.spacing( 4 ) } }
@@ -1,13 +1,18 @@
1
1
  import * as React from 'react';
2
2
  import { type RefObject, useRef } from 'react';
3
- import { boxShadowPropTypeUtil, type PropKey, shadowPropTypeUtil, type ShadowPropValue } from '@elementor/editor-props';
4
- import { FormLabel, Grid, type SxProps, type Theme, UnstableColorIndicator } from '@elementor/ui';
3
+ import { boxShadowPropTypeUtil, shadowPropTypeUtil, type ShadowPropValue } from '@elementor/editor-props';
4
+ import { FormLabel, Grid, styled, type SxProps, type Theme, UnstableColorIndicator } from '@elementor/ui';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
7
  import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
8
8
  import { PopoverContent } from '../components/popover-content';
9
9
  import { PopoverGridContainer } from '../components/popover-grid-container';
10
- import { Repeater } from '../components/repeater';
10
+ import { Header, Item, ItemsContainer, TooltipAddItemAction, UnstableRepeater } from '../components/unstable-repeater';
11
+ import { DisableItemAction } from '../components/unstable-repeater/actions/disable-item-action';
12
+ import { DuplicateItemAction } from '../components/unstable-repeater/actions/duplicate-item-action';
13
+ import { RemoveItemAction } from '../components/unstable-repeater/actions/remove-item-action';
14
+ import { useRepeaterContext } from '../components/unstable-repeater/context/repeater-context';
15
+ import { EditItemPopover } from '../components/unstable-repeater/items/edit-item-popover';
11
16
  import { createControl } from '../create-control';
12
17
  import { ColorControl } from './color-control';
13
18
  import { SelectControl } from './select-control';
@@ -18,38 +23,37 @@ export const BoxShadowRepeaterControl = createControl( () => {
18
23
 
19
24
  return (
20
25
  <PropProvider propType={ propType } value={ value } setValue={ setValue } isDisabled={ () => disabled }>
21
- <Repeater
22
- openOnAdd
23
- disabled={ disabled }
24
- values={ value ?? [] }
25
- setValues={ setValue }
26
- label={ __( 'Box shadow', 'elementor' ) }
27
- itemSettings={ {
28
- Icon: ItemIcon,
29
- Label: ItemLabel,
30
- Content: ItemContent,
31
- initialValues: initialShadow,
32
- } }
33
- />
26
+ <UnstableRepeater initial={ initialShadow } propTypeUtil={ boxShadowPropTypeUtil }>
27
+ <Header label={ __( 'Box shadow', 'elementor' ) }>
28
+ <TooltipAddItemAction newItemIndex={ 0 } disabled={ disabled } />
29
+ </Header>
30
+ <ItemsContainer itemTemplate={ <Item Icon={ ItemIcon } Label={ ItemLabel } /> }>
31
+ <DuplicateItemAction />
32
+ <DisableItemAction />
33
+ <RemoveItemAction />
34
+ </ItemsContainer>
35
+ <EditItemPopover>
36
+ <Content />
37
+ </EditItemPopover>
38
+ </UnstableRepeater>
34
39
  </PropProvider>
35
40
  );
36
41
  } );
37
42
 
43
+ const StyledUnstableColorIndicator = styled( UnstableColorIndicator )( ( { theme } ) => ( {
44
+ height: '1rem',
45
+ width: '1rem',
46
+ borderRadius: `${ theme.shape.borderRadius / 2 }px`,
47
+ } ) );
48
+
38
49
  const ItemIcon = ( { value }: { value: ShadowPropValue } ) => (
39
- <UnstableColorIndicator size="inherit" component="span" value={ value.value.color?.value } />
50
+ <StyledUnstableColorIndicator size="inherit" component="span" value={ value.value.color?.value } />
40
51
  );
41
52
 
42
- const ItemContent = ( { anchorEl, bind }: { anchorEl: HTMLElement | null; bind: PropKey } ) => {
43
- return (
44
- <PropKeyProvider bind={ bind }>
45
- <Content anchorEl={ anchorEl } />
46
- </PropKeyProvider>
47
- );
48
- };
49
-
50
- const Content = ( { anchorEl }: { anchorEl: HTMLElement | null } ) => {
53
+ const Content = () => {
51
54
  const context = useBoundProp( shadowPropTypeUtil );
52
55
  const rowRef: RefObject< HTMLDivElement >[] = [ useRef( null ), useRef( null ) ];
56
+ const { rowRef: anchorEl } = useRepeaterContext();
53
57
 
54
58
  return (
55
59
  <PropProvider { ...context }>
@@ -0,0 +1,49 @@
1
+ import { __ } from '@wordpress/i18n';
2
+
3
+ export type FilterFunction =
4
+ | 'blur'
5
+ | 'brightness'
6
+ | 'contrast'
7
+ | 'hue-rotate'
8
+ | 'saturate'
9
+ | 'grayscale'
10
+ | 'invert'
11
+ | 'sepia'
12
+ | 'drop-shadow';
13
+
14
+ export type FilterFunctionGroup = 'blur' | 'color-tone' | 'hue-rotate' | 'intensity' | 'drop-shadow';
15
+
16
+ export type FilterGroup = {
17
+ [ filter in FilterFunction ]?: {
18
+ name: string;
19
+ valueName?: string;
20
+ };
21
+ };
22
+
23
+ export const FILTERS_BY_GROUP: Record< FilterFunctionGroup, FilterGroup > = {
24
+ blur: {
25
+ blur: {
26
+ name: __( 'Blur', 'elementor' ),
27
+ valueName: __( 'Radius', 'elementor' ),
28
+ },
29
+ },
30
+ intensity: {
31
+ brightness: { name: __( 'Brightness', 'elementor' ) },
32
+ contrast: { name: __( 'Contrast', 'elementor' ) },
33
+ saturate: { name: __( 'Saturate', 'elementor' ) },
34
+ },
35
+ 'hue-rotate': {
36
+ 'hue-rotate': {
37
+ name: __( 'Hue Rotate', 'elementor' ),
38
+ valueName: __( 'Angle', 'elementor' ),
39
+ },
40
+ },
41
+ 'color-tone': {
42
+ grayscale: { name: __( 'Grayscale', 'elementor' ) },
43
+ invert: { name: __( 'Invert', 'elementor' ) },
44
+ sepia: { name: __( 'Sepia', 'elementor' ) },
45
+ },
46
+ 'drop-shadow': {
47
+ 'drop-shadow': { name: __( 'Drop shadow', 'elementor' ), valueName: __( 'Drop-shadow', 'elementor' ) },
48
+ },
49
+ };
@@ -0,0 +1,49 @@
1
+ import * as React from 'react';
2
+ import { createContext, useContext, useMemo } from 'react';
3
+ import { cssFilterFunctionPropUtil, type PropType } from '@elementor/editor-props';
4
+
5
+ import { useBoundProp } from '../../../bound-prop-context';
6
+ import { type FilterFunction } from '../configs';
7
+ import { buildFilterConfig, type FilterConfigEntry } from '../utils';
8
+
9
+ type FilterConfigMap = Record< FilterFunction, FilterConfigEntry >;
10
+
11
+ type FilterConfigContextValue = {
12
+ config: FilterConfigMap;
13
+ filterOptions: Array< { value: string; label: string } >;
14
+ getFilterFunctionConfig: ( filterFunction: FilterFunction ) => FilterConfigEntry;
15
+ getInitialValue: () => unknown;
16
+ };
17
+
18
+ const FilterConfigContext = createContext< FilterConfigContextValue | null >( null );
19
+
20
+ export function FilterConfigProvider( { children }: React.PropsWithChildren ) {
21
+ const propContext = useBoundProp( cssFilterFunctionPropUtil ) as { propType: { item_prop_type: PropType } };
22
+
23
+ const contextValue = useMemo( () => {
24
+ const config = buildFilterConfig( propContext.propType.item_prop_type );
25
+ const filterOptions = Object.entries( config ).map( ( [ key, conf ] ) => ( {
26
+ value: key,
27
+ label: conf.name,
28
+ } ) );
29
+
30
+ return {
31
+ config,
32
+ filterOptions,
33
+ getFilterFunctionConfig: ( filterFunction: FilterFunction ) => config[ filterFunction ],
34
+ getInitialValue: () => config.blur.defaultValue,
35
+ };
36
+ }, [ propContext.propType ] );
37
+
38
+ return <FilterConfigContext.Provider value={ contextValue }>{ children }</FilterConfigContext.Provider>;
39
+ }
40
+
41
+ export function useFilterConfig(): FilterConfigContextValue {
42
+ const context = useContext( FilterConfigContext );
43
+
44
+ if ( ! context ) {
45
+ throw new Error( 'useFilterConfig must be used within FilterConfigProvider' );
46
+ }
47
+
48
+ return context;
49
+ }
@@ -4,12 +4,11 @@ import { dropShadowFilterPropTypeUtil } from '@elementor/editor-props';
4
4
  import { Grid } from '@elementor/ui';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
- import { PropKeyProvider, PropProvider, useBoundProp } from '../../bound-prop-context';
8
- import { ControlFormLabel } from '../../components/control-form-label';
9
- import { PopoverGridContainer } from '../../components/popover-grid-container';
10
- import { type LengthUnit } from '../../utils/size-control';
11
- import { ColorControl } from '../color-control';
12
- import { SizeControl } from '../size-control';
7
+ import { PropKeyProvider, PropProvider, useBoundProp } from '../../../bound-prop-context';
8
+ import { ControlFormLabel } from '../../../components/control-form-label';
9
+ import { PopoverGridContainer } from '../../../components/popover-grid-container';
10
+ import { ColorControl } from '../../color-control';
11
+ import { SizeControl } from '../../size-control';
13
12
 
14
13
  const items = [
15
14
  {
@@ -34,13 +33,7 @@ const items = [
34
33
  },
35
34
  ];
36
35
 
37
- export const DropShadowItemContent = ( {
38
- units,
39
- anchorEl,
40
- }: {
41
- units: LengthUnit[];
42
- anchorEl?: HTMLElement | null;
43
- } ) => {
36
+ export const DropShadowItemContent = ( { anchorEl }: { anchorEl?: HTMLElement | null } ) => {
44
37
  const context = useBoundProp( dropShadowFilterPropTypeUtil );
45
38
  const rowRefs = [ useRef< HTMLDivElement >( null ), useRef< HTMLDivElement >( null ) ];
46
39
 
@@ -56,7 +49,11 @@ export const DropShadowItemContent = ( {
56
49
  { item.bind === 'color' ? (
57
50
  <ColorControl anchorEl={ anchorEl } />
58
51
  ) : (
59
- <SizeControl anchorRef={ rowRefs[ item.rowIndex ] } units={ units } defaultUnit="px" />
52
+ <SizeControl
53
+ anchorRef={ rowRefs[ item.rowIndex ] }
54
+ enablePropTypeUnits
55
+ defaultUnit="px"
56
+ />
60
57
  ) }
61
58
  </Grid>
62
59
  </PropKeyProvider>
@@ -0,0 +1,78 @@
1
+ import * as React from 'react';
2
+ import {
3
+ type CreateOptions,
4
+ cssFilterFunctionPropUtil,
5
+ type FilterItemPropValue,
6
+ type PropKey,
7
+ } from '@elementor/editor-props';
8
+ import { Grid } from '@elementor/ui';
9
+ import { __ } from '@wordpress/i18n';
10
+
11
+ import { PropKeyProvider, PropProvider, useBoundProp } from '../../bound-prop-context';
12
+ import { ControlFormLabel } from '../../components/control-form-label';
13
+ import { PopoverContent } from '../../components/popover-content';
14
+ import { PopoverGridContainer } from '../../components/popover-grid-container';
15
+ import { useRepeaterContext } from '../../components/unstable-repeater/context/repeater-context';
16
+ import { SelectControl } from '../select-control';
17
+ import { type FilterFunction } from './configs';
18
+ import { useFilterConfig } from './context/filter-config-context';
19
+ import { DropShadowItemContent } from './drop-shadow/drop-shadow-item-content';
20
+ import { SingleSizeItemContent } from './single-size/single-size-item-content';
21
+
22
+ type Value = FilterItemPropValue[ 'value' ];
23
+
24
+ export const FilterContent = () => {
25
+ const propContext = useBoundProp( cssFilterFunctionPropUtil );
26
+ const { filterOptions, getFilterFunctionConfig } = useFilterConfig();
27
+
28
+ const handleValueChange = ( value: Value, _?: CreateOptions, meta?: { bind?: PropKey } ) => {
29
+ let newValue = structuredClone( value );
30
+ const funcConfig = getFilterFunctionConfig( newValue?.func.value as FilterFunction );
31
+
32
+ if ( meta?.bind === 'func' ) {
33
+ newValue = funcConfig.defaultValue.value as FilterItemPropValue[ 'value' ];
34
+ }
35
+
36
+ if ( ! newValue.args ) {
37
+ return;
38
+ }
39
+
40
+ propContext.setValue( newValue );
41
+ };
42
+
43
+ return (
44
+ <PropProvider { ...propContext } setValue={ handleValueChange }>
45
+ <PropKeyProvider bind="css-filter-func">
46
+ <PopoverContent p={ 1.5 }>
47
+ <PopoverGridContainer>
48
+ <Grid item xs={ 6 }>
49
+ <ControlFormLabel>{ __( 'Filter', 'elementor' ) }</ControlFormLabel>
50
+ </Grid>
51
+ <Grid item xs={ 6 }>
52
+ <PropKeyProvider bind="func">
53
+ <SelectControl options={ filterOptions } />
54
+ </PropKeyProvider>
55
+ </Grid>
56
+ </PopoverGridContainer>
57
+ <PropKeyProvider bind="args">
58
+ <FilterValueContent />
59
+ </PropKeyProvider>
60
+ </PopoverContent>
61
+ </PropKeyProvider>
62
+ </PropProvider>
63
+ );
64
+ };
65
+
66
+ const FilterValueContent = () => {
67
+ const { openItemIndex, items } = useRepeaterContext();
68
+ const currentItem = items[ openItemIndex ];
69
+
70
+ const filterFunc = ( currentItem.item.value as FilterItemPropValue[ 'value' ] ).func.value;
71
+ const isDropShadow = filterFunc === 'drop-shadow';
72
+
73
+ if ( isDropShadow ) {
74
+ return <DropShadowItemContent />;
75
+ }
76
+
77
+ return <SingleSizeItemContent filterFunc={ filterFunc as FilterFunction } />;
78
+ };
@@ -0,0 +1,21 @@
1
+ import * as React from 'react';
2
+ import { type DropShadowFilterPropValue, type FilterItemPropValue } from '@elementor/editor-props';
3
+ import { styled, UnstableColorIndicator } from '@elementor/ui';
4
+
5
+ export const FilterIcon = ( { value }: { value: FilterItemPropValue } ) => {
6
+ if ( value.value.func.value !== 'drop-shadow' ) {
7
+ return null;
8
+ }
9
+
10
+ return (
11
+ <StyledUnstableColorIndicator
12
+ size="inherit"
13
+ component="span"
14
+ value={ ( value.value.args as DropShadowFilterPropValue ).value?.color.value }
15
+ />
16
+ );
17
+ };
18
+
19
+ const StyledUnstableColorIndicator = styled( UnstableColorIndicator )( ( { theme } ) => ( {
20
+ borderRadius: `${ theme.shape.borderRadius / 2 }px`,
21
+ } ) );
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import type { FilterItemPropValue } from '@elementor/editor-props';
3
+
4
+ import { DropShadowItemLabel } from './drop-shadow/drop-shadow-item-label';
5
+ import { SingleSizeItemLabel } from './single-size/single-size-item-label';
6
+
7
+ export const FilterLabel = ( { value }: { value: FilterItemPropValue } ) => {
8
+ if ( value.value.func.value === 'drop-shadow' ) {
9
+ return <DropShadowItemLabel value={ value } />;
10
+ }
11
+
12
+ return <SingleSizeItemLabel value={ value } />;
13
+ };
@@ -0,0 +1,93 @@
1
+ import * as React from 'react';
2
+ import {
3
+ backdropFilterPropTypeUtil,
4
+ type FilterItemPropValue,
5
+ filterPropTypeUtil,
6
+ type PropTypeUtil,
7
+ } from '@elementor/editor-props';
8
+ import { __ } from '@wordpress/i18n';
9
+
10
+ import { PropProvider, useBoundProp } from '../../bound-prop-context';
11
+ import {
12
+ Header,
13
+ Item,
14
+ ItemsContainer,
15
+ TooltipAddItemAction,
16
+ UnstableRepeater,
17
+ } from '../../components/unstable-repeater';
18
+ import { DisableItemAction } from '../../components/unstable-repeater/actions/disable-item-action';
19
+ import { DuplicateItemAction } from '../../components/unstable-repeater/actions/duplicate-item-action';
20
+ import { RemoveItemAction } from '../../components/unstable-repeater/actions/remove-item-action';
21
+ import { EditItemPopover } from '../../components/unstable-repeater/items/edit-item-popover';
22
+ import type { RepeatablePropValue } from '../../components/unstable-repeater/types';
23
+ import { createControl } from '../../create-control';
24
+ import { FilterConfigProvider, useFilterConfig } from './context/filter-config-context';
25
+ import { FilterContent } from './filter-content';
26
+ import { FilterIcon } from './filter-icon';
27
+ import { FilterLabel } from './filter-label';
28
+
29
+ type FilterPropName = {
30
+ filterPropName?: 'filter' | 'backdrop-filter';
31
+ };
32
+
33
+ type Config = {
34
+ propTypeUtil: PropTypeUtil< string, FilterItemPropValue[] >;
35
+ label: string;
36
+ };
37
+
38
+ const FILTER_CONFIG: Record< string, Config > = {
39
+ filter: {
40
+ propTypeUtil: filterPropTypeUtil,
41
+ label: __( 'Filters', 'elementor' ),
42
+ },
43
+ 'backdrop-filter': {
44
+ propTypeUtil: backdropFilterPropTypeUtil,
45
+ label: __( 'Backdrop Filters', 'elementor' ),
46
+ },
47
+ } as const;
48
+
49
+ export const FilterRepeaterControl = createControl( ( { filterPropName = 'filter' }: FilterPropName ) => {
50
+ const { propTypeUtil, label } = ensureFilterConfig( filterPropName );
51
+ const { propType, value: filterValues, setValue } = useBoundProp( propTypeUtil );
52
+
53
+ return (
54
+ <FilterConfigProvider>
55
+ <PropProvider propType={ propType } value={ filterValues } setValue={ setValue }>
56
+ <Repeater
57
+ propTypeUtil={ propTypeUtil as PropTypeUtil< string, RepeatablePropValue[] > }
58
+ label={ label }
59
+ />
60
+ </PropProvider>
61
+ </FilterConfigProvider>
62
+ );
63
+ } );
64
+
65
+ type RepeaterProps = { propTypeUtil: PropTypeUtil< string, RepeatablePropValue[] >; label: string };
66
+
67
+ const Repeater = ( { propTypeUtil, label }: RepeaterProps ) => {
68
+ const { getInitialValue } = useFilterConfig();
69
+
70
+ return (
71
+ <UnstableRepeater initial={ getInitialValue() as RepeatablePropValue } propTypeUtil={ propTypeUtil }>
72
+ <Header label={ label }>
73
+ <TooltipAddItemAction newItemIndex={ 0 } />
74
+ </Header>
75
+ <ItemsContainer itemTemplate={ <Item Label={ FilterLabel } Icon={ FilterIcon } /> }>
76
+ <DuplicateItemAction />
77
+ <DisableItemAction />
78
+ <RemoveItemAction />
79
+ </ItemsContainer>
80
+ <EditItemPopover>
81
+ <FilterContent />
82
+ </EditItemPopover>
83
+ </UnstableRepeater>
84
+ );
85
+ };
86
+
87
+ function ensureFilterConfig( name: string ): Config {
88
+ if ( name && name in FILTER_CONFIG ) {
89
+ return FILTER_CONFIG[ name ];
90
+ }
91
+
92
+ return FILTER_CONFIG.filter;
93
+ }
@@ -0,0 +1,48 @@
1
+ import { useRef } from 'react';
2
+ import * as React from 'react';
3
+ import {
4
+ blurFilterPropTypeUtil,
5
+ colorToneFilterPropTypeUtil,
6
+ type createPropUtils,
7
+ hueRotateFilterPropTypeUtil,
8
+ intensityFilterPropTypeUtil,
9
+ } from '@elementor/editor-props';
10
+ import { Grid } from '@elementor/ui';
11
+
12
+ import { PropKeyProvider, PropProvider, useBoundProp } from '../../../bound-prop-context';
13
+ import { ControlFormLabel } from '../../../components/control-form-label';
14
+ import { PopoverGridContainer } from '../../../components/popover-grid-container';
15
+ import { SizeControl } from '../../size-control';
16
+ import { type FilterFunction } from '../configs';
17
+ import { useFilterConfig } from '../context/filter-config-context';
18
+
19
+ export const propTypeMap: Record< string, ReturnType< typeof createPropUtils > > = {
20
+ blur: blurFilterPropTypeUtil,
21
+ intensity: intensityFilterPropTypeUtil,
22
+ 'hue-rotate': hueRotateFilterPropTypeUtil,
23
+ 'color-tone': colorToneFilterPropTypeUtil,
24
+ };
25
+
26
+ export const SingleSizeItemContent = ( { filterFunc }: { filterFunc: FilterFunction } ) => {
27
+ const rowRef = useRef< HTMLDivElement >( null );
28
+ const { getFilterFunctionConfig } = useFilterConfig();
29
+ const { valueName, filterFunctionGroup } = getFilterFunctionConfig( filterFunc );
30
+ const context = useBoundProp( propTypeMap[ filterFunctionGroup as string ] );
31
+
32
+ return (
33
+ <PropProvider { ...context }>
34
+ <PropKeyProvider bind={ filterFunctionGroup }>
35
+ <PropKeyProvider bind={ 'size' }>
36
+ <PopoverGridContainer ref={ rowRef }>
37
+ <Grid item xs={ 6 }>
38
+ <ControlFormLabel>{ valueName }</ControlFormLabel>
39
+ </Grid>
40
+ <Grid item xs={ 6 }>
41
+ <SizeControl anchorRef={ rowRef } enablePropTypeUnits />
42
+ </Grid>
43
+ </PopoverGridContainer>
44
+ </PropKeyProvider>
45
+ </PropKeyProvider>
46
+ </PropProvider>
47
+ );
48
+ };
@@ -0,0 +1,30 @@
1
+ import * as React from 'react';
2
+ import type { FilterItemPropValue, SizePropValue } from '@elementor/editor-props';
3
+ import { Box } from '@elementor/ui';
4
+
5
+ import { lengthUnits } from '../../../utils/size-control';
6
+ import { type FilterFunction } from '../configs';
7
+ import { useFilterConfig } from '../context/filter-config-context';
8
+
9
+ export const SingleSizeItemLabel = ( { value }: { value: FilterItemPropValue } ) => {
10
+ const { func, args } = value.value;
11
+ const { getFilterFunctionConfig } = useFilterConfig();
12
+ const { defaultValue } = getFilterFunctionConfig( ( func.value ?? '' ) as FilterFunction );
13
+ const defaultUnit =
14
+ ( defaultValue.value.args.value as { size: SizePropValue } )?.size?.value?.unit ?? lengthUnits[ 0 ];
15
+
16
+ const { unit, size } = ( args.value as { size: SizePropValue } ).size?.value ?? { unit: defaultUnit, size: 0 };
17
+
18
+ const label = (
19
+ <Box component="span" style={ { textTransform: 'capitalize' } }>
20
+ { func.value ?? '' }:
21
+ </Box>
22
+ );
23
+
24
+ return (
25
+ <Box component="span">
26
+ { label }
27
+ { unit !== 'custom' ? ` ${ size ?? 0 }${ unit ?? defaultUnit }` : size }
28
+ </Box>
29
+ );
30
+ };