@elementor/editor-controls 1.5.0 → 3.32.0-21

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +0 -22
  2. package/dist/index.d.mts +95 -25
  3. package/dist/index.d.ts +95 -25
  4. package/dist/index.js +2045 -1041
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +1962 -964
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +18 -18
  9. package/src/components/control-toggle-button-group.tsx +78 -14
  10. package/src/components/floating-bar.tsx +45 -0
  11. package/src/components/{font-family-selector.tsx → item-selector.tsx} +62 -50
  12. package/src/components/repeater.tsx +1 -1
  13. package/src/components/restricted-link-infotip.tsx +76 -0
  14. package/src/components/size-control/size-input.tsx +8 -7
  15. package/src/components/size-control/text-field-inner-selection.tsx +60 -14
  16. package/src/components/text-field-popover.tsx +30 -7
  17. package/src/components/unstable-repeater/actions/add-item-action.tsx +50 -0
  18. package/src/components/unstable-repeater/actions/disable-item-action.tsx +39 -0
  19. package/src/components/unstable-repeater/actions/duplicate-item-action.tsx +32 -0
  20. package/src/components/unstable-repeater/actions/remove-item-action.tsx +27 -0
  21. package/src/components/unstable-repeater/context/repeater-context.tsx +137 -0
  22. package/src/components/unstable-repeater/header/header.tsx +23 -0
  23. package/src/components/unstable-repeater/index.ts +5 -0
  24. package/src/components/unstable-repeater/items/edit-item-popover.tsx +28 -0
  25. package/src/components/unstable-repeater/items/item.tsx +71 -0
  26. package/src/components/unstable-repeater/items/items-container.tsx +49 -0
  27. package/src/components/unstable-repeater/items/use-popover.tsx +26 -0
  28. package/src/{locations.ts → components/unstable-repeater/locations.ts} +9 -1
  29. package/src/components/unstable-repeater/types.ts +26 -0
  30. package/src/components/unstable-repeater/unstable-repeater.tsx +24 -0
  31. package/src/control-actions/control-actions.tsx +3 -20
  32. package/src/control-replacements.tsx +41 -0
  33. package/src/controls/background-control/background-control.tsx +1 -8
  34. package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx +17 -16
  35. package/src/controls/equal-unequal-sizes-control.tsx +2 -9
  36. package/src/controls/filter-control/drop-shadow-item-content.tsx +4 -6
  37. package/src/controls/filter-control/drop-shadow-item-label.tsx +2 -2
  38. package/src/controls/filter-repeater-control.tsx +149 -110
  39. package/src/controls/font-family-control/font-family-control.tsx +22 -10
  40. package/src/controls/key-value-control.tsx +9 -6
  41. package/src/controls/link-control.tsx +8 -91
  42. package/src/controls/linked-dimensions-control.tsx +3 -16
  43. package/src/controls/number-control.tsx +10 -1
  44. package/src/controls/position-control.tsx +4 -16
  45. package/src/controls/repeatable-control.tsx +8 -5
  46. package/src/controls/select-control.tsx +7 -2
  47. package/src/controls/selection-size-control.tsx +74 -0
  48. package/src/controls/size-control.tsx +181 -126
  49. package/src/controls/stroke-control.tsx +2 -2
  50. package/src/controls/toggle-control.tsx +3 -2
  51. package/src/controls/transform-control/functions/axis-row.tsx +4 -2
  52. package/src/controls/transform-control/functions/move.tsx +2 -1
  53. package/src/controls/transform-control/functions/rotate.tsx +48 -0
  54. package/src/controls/transform-control/functions/scale-axis-row.tsx +32 -0
  55. package/src/controls/transform-control/functions/scale.tsx +45 -0
  56. package/src/controls/transform-control/functions/skew.tsx +43 -0
  57. package/src/controls/transform-control/transform-content.tsx +60 -23
  58. package/src/controls/transform-control/transform-icon.tsx +10 -2
  59. package/src/controls/transform-control/transform-label.tsx +39 -2
  60. package/src/controls/transform-control/transform-repeater-control.tsx +2 -10
  61. package/src/controls/transform-control/types.ts +58 -0
  62. package/src/controls/transform-control/use-transform-tabs-history.tsx +107 -0
  63. package/src/controls/transition-control/data.ts +34 -0
  64. package/src/controls/transition-control/transition-repeater-control.tsx +63 -0
  65. package/src/controls/transition-control/transition-selector.tsx +88 -0
  66. package/src/controls/unstable-transform-control/unstable-transform-repeater-control.tsx +35 -0
  67. package/src/hooks/use-filtered-items-list.ts +24 -0
  68. package/src/hooks/use-size-extended-options.ts +1 -6
  69. package/src/index.ts +13 -3
  70. package/src/utils/size-control.ts +12 -6
  71. package/src/hooks/use-filtered-font-families.ts +0 -24
@@ -0,0 +1,26 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { bindPopover, type PopoverProps, usePopupState } from '@elementor/ui';
3
+
4
+ export const usePopover = ( openOnMount: boolean, onOpen: () => void ) => {
5
+ const [ ref, setRef ] = useState< HTMLElement | null >( null );
6
+
7
+ const popoverState = usePopupState( { variant: 'popover' } );
8
+
9
+ const popoverProps: Partial< PopoverProps > = bindPopover( popoverState );
10
+
11
+ useEffect( () => {
12
+ if ( openOnMount && ref ) {
13
+ popoverState.open( ref );
14
+ onOpen?.();
15
+ }
16
+ // eslint-disable-next-line react-compiler/react-compiler
17
+ // eslint-disable-next-line react-hooks/exhaustive-deps
18
+ }, [ ref ] );
19
+
20
+ return {
21
+ popoverState,
22
+ ref,
23
+ setRef,
24
+ popoverProps,
25
+ };
26
+ };
@@ -1,5 +1,5 @@
1
1
  import { type PropValue } from '@elementor/editor-props';
2
- import { createReplaceableLocation } from '@elementor/locations';
2
+ import { createLocation, createReplaceableLocation } from '@elementor/locations';
3
3
 
4
4
  // Repeaters
5
5
  export const { Slot: RepeaterItemIconSlot, inject: injectIntoRepeaterItemIcon } = createReplaceableLocation< {
@@ -9,3 +9,11 @@ export const { Slot: RepeaterItemIconSlot, inject: injectIntoRepeaterItemIcon }
9
9
  export const { Slot: RepeaterItemLabelSlot, inject: injectIntoRepeaterItemLabel } = createReplaceableLocation< {
10
10
  value: PropValue;
11
11
  } >();
12
+
13
+ export const { Slot: RepeaterHeaderActionsSlot, inject: injectIntoRepeaterHeaderActions } = createLocation< {
14
+ value: PropValue;
15
+ } >();
16
+
17
+ export const { Slot: RepeaterItemActionsSlot, inject: injectIntoRepeaterItemActions } = createLocation< {
18
+ index: number;
19
+ } >();
@@ -0,0 +1,26 @@
1
+ import { type PropKey, type PropTypeUtil } from '@elementor/editor-props';
2
+
3
+ export type CollectionPropUtil< T > = PropTypeUtil< PropKey, T[] >;
4
+
5
+ export type Item< T > = {
6
+ disabled?: boolean;
7
+ } & T;
8
+
9
+ type RepeaterItemContentProps< T > = {
10
+ anchorEl: HTMLElement | null;
11
+ bind: PropKey;
12
+ value: T;
13
+ collectionPropUtil?: CollectionPropUtil< T >;
14
+ };
15
+
16
+ type RepeaterItemContent< T > = React.ComponentType< RepeaterItemContentProps< T > >;
17
+
18
+ export type ItemProps< T > = {
19
+ Label: React.ComponentType< { value: T } >;
20
+ Icon: React.ComponentType< { value: T } >;
21
+ Content: RepeaterItemContent< T >;
22
+ value?: Item< T >;
23
+ key?: string | number;
24
+ index?: number;
25
+ openOnMount?: boolean;
26
+ };
@@ -0,0 +1,24 @@
1
+ import * as React from 'react';
2
+ import { type PropTypeUtil, type PropValue } from '@elementor/editor-props';
3
+
4
+ import { SlotChildren } from '../../control-replacements';
5
+ import { SectionContent } from '../section-content';
6
+ import { RepeaterContextProvider } from './context/repeater-context';
7
+ import { Header } from './header/header';
8
+ import { ItemsContainer } from './items/items-container';
9
+
10
+ export const UnstableRepeater = < T extends PropValue >( {
11
+ children,
12
+ initial,
13
+ propTypeUtil,
14
+ }: React.PropsWithChildren< { initial: T; propTypeUtil: PropTypeUtil< string, T[] > } > ) => {
15
+ return (
16
+ <SectionContent>
17
+ <RepeaterContextProvider initial={ initial } propTypeUtil={ propTypeUtil }>
18
+ <SlotChildren whitelist={ [ Header, ItemsContainer ] as React.FC[] } sorted>
19
+ { children }
20
+ </SlotChildren>
21
+ </RepeaterContextProvider>
22
+ </SectionContent>
23
+ );
24
+ };
@@ -1,23 +1,10 @@
1
1
  import * as React from 'react';
2
- import { type PropsWithChildren, type ReactElement } from 'react';
3
- import { styled, UnstableFloatingActionBar } from '@elementor/ui';
2
+ import { type PropsWithChildren } from 'react';
4
3
 
5
4
  import { useBoundProp } from '../bound-prop-context';
5
+ import { FloatingActionsBar } from '../components/floating-bar';
6
6
  import { useControlActions } from './control-actions-context';
7
7
 
8
- // CSS hack to hide empty floating bars.
9
- const FloatingBarContainer = styled( 'span' )`
10
- display: contents;
11
-
12
- .MuiFloatingActionBar-popper:has( .MuiFloatingActionBar-actions:empty ) {
13
- display: none;
14
- }
15
-
16
- .MuiFloatingActionBar-popper {
17
- z-index: 1000;
18
- }
19
- `;
20
-
21
8
  type ControlActionsProps = PropsWithChildren< object >;
22
9
 
23
10
  export default function ControlActions( { children }: ControlActionsProps ) {
@@ -30,9 +17,5 @@ export default function ControlActions( { children }: ControlActionsProps ) {
30
17
 
31
18
  const menuItems = items.map( ( { MenuItem, id } ) => <MenuItem key={ id } /> );
32
19
 
33
- return (
34
- <FloatingBarContainer>
35
- <UnstableFloatingActionBar actions={ menuItems }>{ children as ReactElement }</UnstableFloatingActionBar>
36
- </FloatingBarContainer>
37
- );
20
+ return <FloatingActionsBar actions={ menuItems }>{ children }</FloatingActionsBar>;
38
21
  }
@@ -47,3 +47,44 @@ export const createControlReplacementsRegistry = () => {
47
47
 
48
48
  return { registerControlReplacement, getControlReplacements };
49
49
  };
50
+
51
+ export const SlotChildren = ( {
52
+ children,
53
+ whitelist = [],
54
+ sorted = false,
55
+ props = {},
56
+ }: {
57
+ children: React.ReactNode;
58
+ whitelist: React.FC[];
59
+ sorted?: boolean;
60
+ props?: Record< string, unknown >;
61
+ } ) => {
62
+ const filtered = (
63
+ ! whitelist.length
64
+ ? React.Children.toArray( children )
65
+ : React.Children.toArray( children ).filter(
66
+ ( child ) => React.isValidElement( child ) && whitelist.includes( child.type as React.FC )
67
+ )
68
+ ) as React.ReactElement[];
69
+
70
+ if ( sorted ) {
71
+ sort( filtered, whitelist );
72
+ }
73
+
74
+ return filtered.map( ( child, index ) => (
75
+ <React.Fragment key={ index }>{ React.cloneElement( child, props ) }</React.Fragment>
76
+ ) );
77
+ };
78
+
79
+ const sort = ( childrenArray: React.ReactElement[], whitelist: unknown[] ) => {
80
+ childrenArray.sort( ( a, b ) => {
81
+ const aIndex = whitelist.indexOf( a.type );
82
+ const bIndex = whitelist.indexOf( b.type );
83
+
84
+ if ( aIndex === -1 || bIndex === -1 ) {
85
+ return 0;
86
+ }
87
+
88
+ return aIndex - bIndex;
89
+ } );
90
+ };
@@ -1,11 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import { backgroundPropTypeUtil } from '@elementor/editor-props';
3
- import { isExperimentActive } from '@elementor/editor-v1-adapters';
4
3
  import { Grid } from '@elementor/ui';
5
4
  import { __ } from '@wordpress/i18n';
6
5
 
7
6
  import { PropKeyProvider, PropProvider, useBoundProp } from '../../bound-prop-context';
8
- import { ControlFormLabel } from '../../components/control-form-label';
9
7
  import { ControlLabel } from '../../components/control-label';
10
8
  import { createControl } from '../../create-control';
11
9
  import { ColorControl } from '../color-control';
@@ -13,7 +11,6 @@ import { BackgroundOverlayRepeaterControl } from './background-overlay/backgroun
13
11
 
14
12
  export const BackgroundControl = createControl( () => {
15
13
  const propContext = useBoundProp( backgroundPropTypeUtil );
16
- const isUsingNestedProps = isExperimentActive( 'e_v_3_30' );
17
14
 
18
15
  const colorLabel = __( 'Color', 'elementor' );
19
16
 
@@ -25,11 +22,7 @@ export const BackgroundControl = createControl( () => {
25
22
  <PropKeyProvider bind="color">
26
23
  <Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
27
24
  <Grid item xs={ 6 }>
28
- { isUsingNestedProps ? (
29
- <ControlLabel>{ colorLabel }</ControlLabel>
30
- ) : (
31
- <ControlFormLabel>{ colorLabel }</ControlFormLabel>
32
- ) }
25
+ <ControlLabel>{ colorLabel }</ControlLabel>
33
26
  </Grid>
34
27
  <Grid item xs={ 6 }>
35
28
  <ColorControl />
@@ -13,7 +13,11 @@ import { __ } from '@wordpress/i18n';
13
13
 
14
14
  import { PropKeyProvider, PropProvider, useBoundProp } from '../../../bound-prop-context';
15
15
  import { PopoverContent } from '../../../components/popover-content';
16
- import { Repeater } from '../../../components/repeater';
16
+ import { AddItemAction, Header, ItemsContainer, UnstableRepeater } from '../../../components/unstable-repeater';
17
+ import { DisableItemAction } from '../../../components/unstable-repeater/actions/disable-item-action';
18
+ import { DuplicateItemAction } from '../../../components/unstable-repeater/actions/duplicate-item-action';
19
+ import { RemoveItemAction } from '../../../components/unstable-repeater/actions/remove-item-action';
20
+ import { Item } from '../../../components/unstable-repeater/items/item';
17
21
  import { createControl } from '../../../create-control';
18
22
  import { env } from '../../../env';
19
23
  import { ColorControl } from '../../color-control';
@@ -71,23 +75,20 @@ const backgroundResolutionOptions = [
71
75
  ];
72
76
 
73
77
  export const BackgroundOverlayRepeaterControl = createControl( () => {
74
- const { propType, value: overlayValues, setValue, disabled } = useBoundProp( backgroundOverlayPropTypeUtil );
78
+ const { propType, value: backgroundValues, setValue } = useBoundProp( backgroundOverlayPropTypeUtil );
75
79
 
76
80
  return (
77
- <PropProvider propType={ propType } value={ overlayValues } setValue={ setValue } isDisabled={ () => disabled }>
78
- <Repeater
79
- openOnAdd
80
- disabled={ disabled }
81
- values={ overlayValues ?? [] }
82
- setValues={ setValue }
83
- label={ __( 'Overlay', 'elementor' ) }
84
- itemSettings={ {
85
- Icon: ItemIcon,
86
- Label: ItemLabel,
87
- Content: ItemContent,
88
- initialValues: getInitialBackgroundOverlay(),
89
- } }
90
- />
81
+ <PropProvider propType={ propType } value={ backgroundValues } setValue={ setValue }>
82
+ <UnstableRepeater initial={ getInitialBackgroundOverlay() } propTypeUtil={ backgroundOverlayPropTypeUtil }>
83
+ <Header label={ __( 'Overlay', 'elementor' ) }>
84
+ <AddItemAction newItemIndex={ 0 } />
85
+ </Header>
86
+ <ItemsContainer itemTemplate={ <Item Icon={ ItemIcon } Label={ ItemLabel } Content={ ItemContent } /> }>
87
+ <DuplicateItemAction />
88
+ <DisableItemAction />
89
+ <RemoveItemAction />
90
+ </ItemsContainer>
91
+ </UnstableRepeater>
91
92
  </PropProvider>
92
93
  );
93
94
  } );
@@ -1,7 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { type ReactNode, type RefObject, useId, useRef } from 'react';
3
3
  import { type PropKey, type PropTypeUtil, sizePropTypeUtil, type SizePropValue } from '@elementor/editor-props';
4
- import { isExperimentActive } from '@elementor/editor-v1-adapters';
5
4
  import { bindPopover, bindToggle, Grid, Popover, Stack, ToggleButton, Tooltip, usePopupState } from '@elementor/ui';
6
5
  import { __ } from '@wordpress/i18n';
7
6
 
@@ -99,7 +98,7 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
99
98
  return splitEqualValue() ?? null;
100
99
  };
101
100
 
102
- const isShowingGeneralIndicator = ! isExperimentActive( 'e_v_3_30' ) || ! popupState.isOpen;
101
+ const isShowingGeneralIndicator = ! popupState.isOpen;
103
102
 
104
103
  const isMixed = !! multiSizeValue;
105
104
 
@@ -173,18 +172,12 @@ export function EqualUnequalSizesControl< TMultiPropType extends string, TPropVa
173
172
  }
174
173
 
175
174
  const MultiSizeValueControl = ( { item, rowRef }: { item: Item; rowRef: RefObject< HTMLDivElement > } ) => {
176
- const isUsingNestedProps = isExperimentActive( 'e_v_3_30' );
177
-
178
175
  return (
179
176
  <PropKeyProvider bind={ item.bind }>
180
177
  <Grid item xs={ 6 }>
181
178
  <Grid container gap={ 0.75 } alignItems="center">
182
179
  <Grid item xs={ 12 }>
183
- { isUsingNestedProps ? (
184
- <ControlLabel>{ item.label }</ControlLabel>
185
- ) : (
186
- <ControlFormLabel>{ item.label }</ControlFormLabel>
187
- ) }
180
+ <ControlLabel>{ item.label }</ControlLabel>
188
181
  </Grid>
189
182
  <Grid item xs={ 12 }>
190
183
  <SizeControl startIcon={ item.icon } anchorRef={ rowRef } />
@@ -1,13 +1,13 @@
1
1
  import * as React from 'react';
2
2
  import { useRef } from 'react';
3
- import { type DropShadowFilterPropValue, type PropTypeUtil } from '@elementor/editor-props';
3
+ import { dropShadowFilterPropTypeUtil } from '@elementor/editor-props';
4
4
  import { Grid } from '@elementor/ui';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
7
  import { PropKeyProvider, PropProvider, useBoundProp } from '../../bound-prop-context';
8
8
  import { ControlFormLabel } from '../../components/control-form-label';
9
9
  import { PopoverGridContainer } from '../../components/popover-grid-container';
10
- import { type Unit } from '../../utils/size-control';
10
+ import { type LengthUnit } from '../../utils/size-control';
11
11
  import { ColorControl } from '../color-control';
12
12
  import { SizeControl } from '../size-control';
13
13
 
@@ -35,15 +35,13 @@ const items = [
35
35
  ];
36
36
 
37
37
  export const DropShadowItemContent = ( {
38
- propType,
39
38
  units,
40
39
  anchorEl,
41
40
  }: {
42
- propType: PropTypeUtil< 'drop-shadow', DropShadowFilterPropValue[ 'value' ] >;
43
- units: Unit[];
41
+ units: LengthUnit[];
44
42
  anchorEl?: HTMLElement | null;
45
43
  } ) => {
46
- const context = useBoundProp( propType );
44
+ const context = useBoundProp( dropShadowFilterPropTypeUtil );
47
45
  const rowRefs = [ useRef< HTMLDivElement >( null ), useRef< HTMLDivElement >( null ) ];
48
46
 
49
47
  return (
@@ -1,9 +1,9 @@
1
1
  import * as React from 'react';
2
- import { type FilterItemPropValue } from '@elementor/editor-props';
2
+ import { type DropShadowFilterPropValue, type FilterItemPropValue } from '@elementor/editor-props';
3
3
  import { Box } from '@elementor/ui';
4
4
 
5
5
  export const DropShadowItemLabel = ( { value }: { value: FilterItemPropValue } ) => {
6
- const { xAxis, yAxis, blur } = value.value;
6
+ const { xAxis, yAxis, blur } = value.value.args.value as DropShadowFilterPropValue[ 'value' ];
7
7
 
8
8
  const xValue = `${ xAxis?.value?.size ?? 0 }${ xAxis?.value?.unit ?? 'px' }`;
9
9
  const yValue = `${ yAxis?.value?.size ?? 0 }${ yAxis?.value?.unit ?? 'px' }`;