@elementor/editor-controls 3.33.0-98 → 3.35.0-324
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.d.mts +276 -85
- package/dist/index.d.ts +276 -85
- package/dist/index.js +2491 -1783
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2304 -1592
- package/dist/index.mjs.map +1 -1
- package/package.json +31 -17
- package/src/bound-prop-context/prop-context.tsx +7 -1
- package/src/bound-prop-context/use-bound-prop.ts +19 -5
- package/src/components/autocomplete.tsx +34 -3
- package/src/components/conditional-control-infotip.tsx +64 -0
- package/src/components/{unstable-repeater → control-repeater}/actions/disable-item-action.tsx +2 -2
- package/src/components/{unstable-repeater → control-repeater}/actions/duplicate-item-action.tsx +10 -4
- package/src/components/{unstable-repeater → control-repeater}/actions/remove-item-action.tsx +2 -2
- package/src/components/control-repeater/context/item-context.tsx +8 -0
- package/src/components/{unstable-repeater → control-repeater}/context/repeater-context.tsx +24 -15
- package/src/components/control-repeater/control-repeater.tsx +29 -0
- package/src/components/{unstable-repeater → control-repeater}/index.ts +1 -2
- package/src/components/{unstable-repeater → control-repeater}/items/edit-item-popover.tsx +6 -20
- package/src/components/control-repeater/items/item.tsx +75 -0
- package/src/components/{unstable-repeater → control-repeater}/items/items-container.tsx +8 -13
- package/src/components/{unstable-repeater → control-repeater}/locations.ts +0 -4
- package/src/components/{unstable-repeater → control-repeater}/types.ts +1 -2
- package/src/components/control-toggle-button-group.tsx +79 -69
- package/src/components/enable-unfiltered-modal.tsx +1 -26
- package/src/components/icon-buttons/clear-icon-button.tsx +23 -0
- package/src/components/inline-editor-toolbar.tsx +137 -0
- package/src/components/inline-editor.tsx +111 -0
- package/src/components/item-selector.tsx +10 -4
- package/src/components/{unstable-repeater/header/header.tsx → repeater/repeater-header.tsx} +4 -12
- package/src/components/repeater/repeater-popover.tsx +19 -0
- package/src/components/repeater/repeater-tag.tsx +16 -0
- package/src/components/repeater/repeater.tsx +405 -0
- package/src/components/{sortable.tsx → repeater/sortable.tsx} +1 -1
- package/src/components/size-control/size-input.tsx +20 -14
- package/src/components/size-control/text-field-inner-selection.tsx +15 -2
- package/src/control-adornments/control-adornments-context.tsx +5 -4
- package/src/control-replacements.tsx +12 -47
- package/src/controls/background-control/background-control.tsx +43 -12
- package/src/controls/background-control/background-gradient-color-control.tsx +5 -8
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-position.tsx +18 -13
- package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx +25 -16
- package/src/controls/box-shadow-repeater-control.tsx +38 -21
- package/src/controls/color-control.tsx +3 -1
- package/src/controls/date-time-control.tsx +108 -0
- package/src/controls/filter-control/drop-shadow/drop-shadow-item-content.tsx +1 -0
- package/src/controls/filter-control/drop-shadow/drop-shadow-item-label.tsx +10 -6
- package/src/controls/filter-control/filter-content.tsx +1 -1
- package/src/controls/filter-control/filter-repeater-control.tsx +24 -21
- package/src/controls/filter-control/single-size/single-size-item-content.tsx +1 -1
- package/src/controls/filter-control/single-size/single-size-item-label.tsx +2 -1
- package/src/controls/font-family-control/font-family-control.tsx +66 -55
- package/src/controls/html-tag-control.tsx +90 -0
- package/src/controls/image-media-control.tsx +2 -2
- package/src/controls/inline-editing-control.tsx +18 -0
- package/src/controls/key-value-control.tsx +8 -2
- package/src/controls/link-control.tsx +23 -123
- package/src/controls/query-control.tsx +168 -0
- package/src/controls/repeatable-control.tsx +62 -27
- package/src/controls/select-control-wrapper.tsx +57 -0
- package/src/controls/select-control.tsx +9 -5
- package/src/controls/selection-size-control.tsx +13 -2
- package/src/controls/size-control.tsx +43 -25
- package/src/controls/svg-media-control.tsx +33 -10
- package/src/controls/text-area-control.tsx +5 -1
- package/src/controls/text-control.tsx +5 -0
- package/src/controls/toggle-control.tsx +11 -2
- package/src/controls/transform-control/functions/axis-row.tsx +1 -0
- package/src/controls/transform-control/transform-icon.tsx +2 -2
- package/src/controls/transform-control/transform-label.tsx +15 -32
- package/src/controls/transform-control/transform-repeater-control.tsx +42 -36
- package/src/controls/transform-control/{transform-base-control.tsx → transform-settings-control.tsx} +2 -2
- package/src/controls/transform-control/use-transform-tabs-history.tsx +1 -1
- package/src/controls/transition-control/data.ts +16 -1
- package/src/controls/transition-control/trainsition-events.ts +2 -2
- package/src/controls/transition-control/transition-repeater-control.tsx +137 -13
- package/src/controls/transition-control/transition-selector.tsx +37 -14
- package/src/controls/url-control.tsx +21 -16
- package/src/create-control.tsx +3 -2
- package/src/hooks/use-filtered-items-list.ts +3 -2
- package/src/hooks/use-repeatable-control-context.ts +3 -0
- package/src/hooks/use-sync-external-state.tsx +0 -1
- package/src/index.ts +21 -5
- package/src/utils/convert-toggle-options-to-atomic.tsx +33 -0
- package/src/utils/escape-html-attr.ts +11 -0
- package/src/components/css-code-editor/css-editor.styles.ts +0 -52
- package/src/components/css-code-editor/css-editor.tsx +0 -142
- package/src/components/css-code-editor/css-validation.ts +0 -75
- package/src/components/css-code-editor/resize-handle.tsx +0 -55
- package/src/components/css-code-editor/visual-content-change-protection.ts +0 -69
- package/src/components/repeater.tsx +0 -343
- package/src/components/unstable-repeater/items/item.tsx +0 -77
- package/src/components/unstable-repeater/unstable-repeater.tsx +0 -26
- /package/src/components/{unstable-repeater → control-repeater}/actions/tooltip-add-item-action.tsx +0 -0
|
@@ -3,53 +3,36 @@ import type { TransformFunctionsItemPropValue } from '@elementor/editor-props';
|
|
|
3
3
|
import { Box } from '@elementor/ui';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
|
|
6
|
+
import { CUSTOM_SIZE_LABEL } from '../size-control';
|
|
6
7
|
import { defaultValues, TransformFunctionKeys } from './initial-values';
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
-
Object.values( value )
|
|
9
|
+
const formatLabel = ( value: TransformFunctionsItemPropValue[ 'value' ], functionType: keyof typeof defaultValues ) => {
|
|
10
|
+
return Object.values( value )
|
|
10
11
|
.map( ( axis ) => {
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
if ( functionType === 'scale' ) {
|
|
13
|
+
return axis?.value || defaultValues[ functionType ];
|
|
14
|
+
}
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const transformScaleValue = ( value: TransformFunctionsItemPropValue[ 'value' ] ) =>
|
|
19
|
-
Object.values( value )
|
|
20
|
-
.map( ( axis ) => axis?.value || defaultValues.scale )
|
|
21
|
-
.join( ', ' );
|
|
22
|
-
|
|
23
|
-
const transformRotateValue = ( value: TransformFunctionsItemPropValue[ 'value' ] ) =>
|
|
24
|
-
Object.values( value )
|
|
25
|
-
.map( ( axis ) => {
|
|
26
|
-
const size = axis?.value?.size ?? defaultValues.rotate.size;
|
|
27
|
-
const unit = axis?.value?.unit ?? defaultValues.rotate.unit;
|
|
16
|
+
const defaults = defaultValues[ functionType ];
|
|
17
|
+
const size = axis?.value?.size ?? defaults.size;
|
|
18
|
+
const unit = axis?.value?.unit ?? defaults.unit;
|
|
28
19
|
|
|
29
|
-
return `${ size }${ unit }`;
|
|
30
|
-
} )
|
|
31
|
-
.join( ', ' );
|
|
32
|
-
const transformSkewValue = ( value: TransformFunctionsItemPropValue[ 'value' ] ) =>
|
|
33
|
-
Object.values( value )
|
|
34
|
-
.map( ( axis ) => {
|
|
35
|
-
const size = axis?.value?.size ?? defaultValues.skew.size;
|
|
36
|
-
const unit = axis?.value?.unit ?? defaultValues.skew.unit;
|
|
37
|
-
|
|
38
|
-
return `${ size }${ unit }`;
|
|
20
|
+
return unit === 'custom' ? size || CUSTOM_SIZE_LABEL : `${ size }${ unit }`;
|
|
39
21
|
} )
|
|
40
22
|
.join( ', ' );
|
|
23
|
+
};
|
|
41
24
|
|
|
42
25
|
export const TransformLabel = ( props: { value: TransformFunctionsItemPropValue } ) => {
|
|
43
26
|
const { $$type, value } = props.value;
|
|
44
27
|
switch ( $$type ) {
|
|
45
28
|
case TransformFunctionKeys.move:
|
|
46
|
-
return <Label label={ __( 'Move', 'elementor' ) } value={
|
|
29
|
+
return <Label label={ __( 'Move', 'elementor' ) } value={ formatLabel( value, 'move' ) } />;
|
|
47
30
|
case TransformFunctionKeys.scale:
|
|
48
|
-
return <Label label={ __( 'Scale', 'elementor' ) } value={
|
|
31
|
+
return <Label label={ __( 'Scale', 'elementor' ) } value={ formatLabel( value, 'scale' ) } />;
|
|
49
32
|
case TransformFunctionKeys.rotate:
|
|
50
|
-
return <Label label={ __( 'Rotate', 'elementor' ) } value={
|
|
33
|
+
return <Label label={ __( 'Rotate', 'elementor' ) } value={ formatLabel( value, 'rotate' ) } />;
|
|
51
34
|
case TransformFunctionKeys.skew:
|
|
52
|
-
return <Label label={ __( 'Skew', 'elementor' ) } value={
|
|
35
|
+
return <Label label={ __( 'Skew', 'elementor' ) } value={ formatLabel( value, 'skew' ) } />;
|
|
53
36
|
default:
|
|
54
37
|
return '';
|
|
55
38
|
}
|
|
@@ -2,28 +2,22 @@ import * as React from 'react';
|
|
|
2
2
|
import { useRef } from 'react';
|
|
3
3
|
import { type PropType, transformFunctionsPropTypeUtil, transformPropTypeUtil } from '@elementor/editor-props';
|
|
4
4
|
import { AdjustmentsIcon, InfoCircleFilledIcon } from '@elementor/icons';
|
|
5
|
-
import { bindTrigger, Box, IconButton, type PopupState, Typography, usePopupState } from '@elementor/ui';
|
|
5
|
+
import { bindTrigger, Box, IconButton, type PopupState, Tooltip, Typography, usePopupState } from '@elementor/ui';
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
7
|
|
|
8
8
|
import { PropKeyProvider, PropProvider, useBoundProp } from '../../bound-prop-context';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
UnstableRepeater,
|
|
15
|
-
} from '../../components/unstable-repeater';
|
|
16
|
-
import { DisableItemAction } from '../../components/unstable-repeater/actions/disable-item-action';
|
|
17
|
-
import { RemoveItemAction } from '../../components/unstable-repeater/actions/remove-item-action';
|
|
18
|
-
import { EditItemPopover } from '../../components/unstable-repeater/items/edit-item-popover';
|
|
19
|
-
import { injectIntoRepeaterHeaderActions } from '../../components/unstable-repeater/locations';
|
|
9
|
+
import { ControlRepeater, Item, ItemsContainer, TooltipAddItemAction } from '../../components/control-repeater';
|
|
10
|
+
import { DisableItemAction } from '../../components/control-repeater/actions/disable-item-action';
|
|
11
|
+
import { RemoveItemAction } from '../../components/control-repeater/actions/remove-item-action';
|
|
12
|
+
import { EditItemPopover } from '../../components/control-repeater/items/edit-item-popover';
|
|
13
|
+
import { RepeaterHeader } from '../../components/repeater/repeater-header';
|
|
20
14
|
import { ControlAdornments } from '../../control-adornments/control-adornments';
|
|
21
15
|
import { createControl } from '../../create-control';
|
|
22
16
|
import { initialRotateValue, initialScaleValue, initialSkewValue, initialTransformValue } from './initial-values';
|
|
23
|
-
import { TransformBaseControl } from './transform-base-control';
|
|
24
17
|
import { TransformContent } from './transform-content';
|
|
25
18
|
import { TransformIcon } from './transform-icon';
|
|
26
19
|
import { TransformLabel } from './transform-label';
|
|
20
|
+
import { TransformSettingsControl } from './transform-settings-control';
|
|
27
21
|
|
|
28
22
|
const SIZE = 'tiny';
|
|
29
23
|
|
|
@@ -32,19 +26,11 @@ export const TransformRepeaterControl = createControl( () => {
|
|
|
32
26
|
const headerRef = useRef< HTMLDivElement >( null );
|
|
33
27
|
const popupState = usePopupState( { variant: 'popover' } );
|
|
34
28
|
|
|
35
|
-
const repeaterBindKey = 'transform-functions';
|
|
36
|
-
|
|
37
|
-
injectIntoRepeaterHeaderActions( {
|
|
38
|
-
id: 'transform-base-control',
|
|
39
|
-
component: () => <TransformBasePopoverTrigger popupState={ popupState } repeaterBindKey={ repeaterBindKey } />,
|
|
40
|
-
options: { overwrite: true },
|
|
41
|
-
} );
|
|
42
|
-
|
|
43
29
|
return (
|
|
44
30
|
<PropProvider { ...context }>
|
|
45
|
-
<
|
|
46
|
-
<PropKeyProvider bind={
|
|
47
|
-
<Repeater headerRef={ headerRef } propType={ context.propType } />
|
|
31
|
+
<TransformSettingsControl popupState={ popupState } anchorRef={ headerRef } />
|
|
32
|
+
<PropKeyProvider bind={ 'transform-functions' }>
|
|
33
|
+
<Repeater headerRef={ headerRef } propType={ context.propType } popupState={ popupState } />
|
|
48
34
|
</PropKeyProvider>
|
|
49
35
|
</PropProvider>
|
|
50
36
|
);
|
|
@@ -63,10 +49,18 @@ const ToolTip = (
|
|
|
63
49
|
</Box>
|
|
64
50
|
);
|
|
65
51
|
|
|
66
|
-
const Repeater = ( {
|
|
52
|
+
const Repeater = ( {
|
|
53
|
+
headerRef,
|
|
54
|
+
propType,
|
|
55
|
+
popupState,
|
|
56
|
+
}: {
|
|
57
|
+
headerRef: React.RefObject< HTMLDivElement >;
|
|
58
|
+
propType: PropType;
|
|
59
|
+
popupState: PopupState;
|
|
60
|
+
} ) => {
|
|
67
61
|
const transformFunctionsContext = useBoundProp( transformFunctionsPropTypeUtil );
|
|
68
62
|
const availableValues = [ initialTransformValue, initialScaleValue, initialRotateValue, initialSkewValue ];
|
|
69
|
-
const { value: transformValues } = transformFunctionsContext;
|
|
63
|
+
const { value: transformValues, bind } = transformFunctionsContext;
|
|
70
64
|
|
|
71
65
|
const getInitialValue = () => {
|
|
72
66
|
return availableValues.find( ( value ) => ! transformValues?.some( ( item ) => item.$$type === value.$$type ) );
|
|
@@ -76,30 +70,39 @@ const Repeater = ( { headerRef, propType }: { headerRef: React.RefObject< HTMLDi
|
|
|
76
70
|
|
|
77
71
|
return (
|
|
78
72
|
<PropProvider { ...transformFunctionsContext }>
|
|
79
|
-
<
|
|
73
|
+
<ControlRepeater
|
|
80
74
|
initial={ getInitialValue() ?? initialTransformValue }
|
|
81
75
|
propTypeUtil={ transformFunctionsPropTypeUtil }
|
|
82
76
|
>
|
|
83
|
-
<
|
|
77
|
+
<RepeaterHeader
|
|
84
78
|
label={ __( 'Transform', 'elementor' ) }
|
|
85
79
|
adornment={ () => <ControlAdornments customContext={ { path: [ 'transform' ], propType } } /> }
|
|
86
80
|
ref={ headerRef }
|
|
87
81
|
>
|
|
82
|
+
<TransformBasePopoverTrigger popupState={ popupState } repeaterBindKey={ bind } />
|
|
88
83
|
<TooltipAddItemAction
|
|
89
84
|
disabled={ shouldDisableAddItem }
|
|
90
85
|
tooltipContent={ ToolTip }
|
|
91
86
|
enableTooltip={ shouldDisableAddItem }
|
|
92
87
|
ariaLabel={ 'transform' }
|
|
93
88
|
/>
|
|
94
|
-
</
|
|
95
|
-
<ItemsContainer
|
|
96
|
-
<
|
|
97
|
-
|
|
89
|
+
</RepeaterHeader>
|
|
90
|
+
<ItemsContainer>
|
|
91
|
+
<Item
|
|
92
|
+
Icon={ TransformIcon }
|
|
93
|
+
Label={ TransformLabel }
|
|
94
|
+
actions={
|
|
95
|
+
<>
|
|
96
|
+
<DisableItemAction />
|
|
97
|
+
<RemoveItemAction />
|
|
98
|
+
</>
|
|
99
|
+
}
|
|
100
|
+
/>
|
|
98
101
|
</ItemsContainer>
|
|
99
102
|
<EditItemPopover>
|
|
100
103
|
<TransformContent />
|
|
101
104
|
</EditItemPopover>
|
|
102
|
-
</
|
|
105
|
+
</ControlRepeater>
|
|
103
106
|
</PropProvider>
|
|
104
107
|
);
|
|
105
108
|
};
|
|
@@ -112,10 +115,13 @@ const TransformBasePopoverTrigger = ( {
|
|
|
112
115
|
repeaterBindKey: string;
|
|
113
116
|
} ) => {
|
|
114
117
|
const { bind } = useBoundProp();
|
|
118
|
+
const titleLabel = __( 'Transform settings', 'elementor' );
|
|
115
119
|
|
|
116
120
|
return bind !== repeaterBindKey ? null : (
|
|
117
|
-
<
|
|
118
|
-
<
|
|
119
|
-
|
|
121
|
+
<Tooltip title={ titleLabel } placement="top">
|
|
122
|
+
<IconButton size={ SIZE } aria-label={ titleLabel } { ...bindTrigger( popupState ) }>
|
|
123
|
+
<AdjustmentsIcon fontSize={ SIZE } />
|
|
124
|
+
</IconButton>
|
|
125
|
+
</Tooltip>
|
|
120
126
|
);
|
|
121
127
|
};
|
package/src/controls/transform-control/{transform-base-control.tsx → transform-settings-control.tsx}
RENAMED
|
@@ -11,7 +11,7 @@ import { TransformOriginControl } from './transform-base-controls/transform-orig
|
|
|
11
11
|
|
|
12
12
|
const SIZE = 'tiny';
|
|
13
13
|
|
|
14
|
-
export const
|
|
14
|
+
export const TransformSettingsControl = ( {
|
|
15
15
|
popupState,
|
|
16
16
|
anchorRef,
|
|
17
17
|
}: {
|
|
@@ -38,7 +38,7 @@ export const TransformBaseControl = ( {
|
|
|
38
38
|
{ ...popupProps }
|
|
39
39
|
>
|
|
40
40
|
<PopoverHeader
|
|
41
|
-
title={ __( '
|
|
41
|
+
title={ __( 'Transform settings', 'elementor' ) }
|
|
42
42
|
onClose={ popupState.close }
|
|
43
43
|
icon={ <AdjustmentsIcon fontSize={ SIZE } /> }
|
|
44
44
|
/>
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import { useTabs } from '@elementor/ui';
|
|
14
14
|
|
|
15
15
|
import { useBoundProp } from '../../bound-prop-context';
|
|
16
|
-
import { useRepeaterContext } from '../../components/
|
|
16
|
+
import { useRepeaterContext } from '../../components/control-repeater/context/repeater-context';
|
|
17
17
|
import { type TransformFunction, TransformFunctionKeys } from './initial-values';
|
|
18
18
|
|
|
19
19
|
type InitialTransformValues = {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { type KeyValuePropValue, type SizePropValue } from '@elementor/editor-props';
|
|
1
2
|
import { __ } from '@wordpress/i18n';
|
|
2
3
|
|
|
3
4
|
export type TransitionProperty = {
|
|
4
5
|
label: string;
|
|
5
6
|
value: string;
|
|
6
7
|
unavailable?: boolean;
|
|
8
|
+
isDisabled?: boolean;
|
|
7
9
|
};
|
|
8
10
|
|
|
9
11
|
export type TransitionCategory = {
|
|
@@ -12,7 +14,20 @@ export type TransitionCategory = {
|
|
|
12
14
|
properties: TransitionProperty[];
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
export
|
|
17
|
+
export type TransitionValue = {
|
|
18
|
+
selection: KeyValuePropValue;
|
|
19
|
+
size: SizePropValue;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type TransitionItem = {
|
|
23
|
+
$$type: 'selection-size';
|
|
24
|
+
value: {
|
|
25
|
+
$$type: 'key-value';
|
|
26
|
+
value: TransitionValue;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const initialTransitionValue: TransitionValue = {
|
|
16
31
|
selection: {
|
|
17
32
|
$$type: 'key-value',
|
|
18
33
|
value: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getSelectedElements } from '@elementor/editor-elements';
|
|
2
|
-
import {
|
|
2
|
+
import { trackEvent } from '@elementor/mixpanel';
|
|
3
3
|
|
|
4
4
|
import { eventBus } from '../../services/event-bus';
|
|
5
5
|
import { type initialTransitionValue } from './data';
|
|
@@ -19,7 +19,7 @@ export function subscribeToTransitionEvent() {
|
|
|
19
19
|
const value = payload?.itemValue?.selection?.value?.value?.value;
|
|
20
20
|
const selectedElements = getSelectedElements();
|
|
21
21
|
const widgetType = selectedElements[ 0 ]?.type ?? null;
|
|
22
|
-
|
|
22
|
+
trackEvent( {
|
|
23
23
|
transition_type: value ?? 'unknown',
|
|
24
24
|
...transitionRepeaterMixpanelEvent,
|
|
25
25
|
widget_type: widgetType,
|
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
createArrayPropUtils,
|
|
5
|
+
type KeyValuePropValue,
|
|
6
|
+
selectionSizePropTypeUtil,
|
|
7
|
+
type SelectionSizePropValue,
|
|
8
|
+
} from '@elementor/editor-props';
|
|
4
9
|
import { type StyleDefinitionState } from '@elementor/editor-styles';
|
|
5
10
|
import { InfoCircleFilledIcon } from '@elementor/icons';
|
|
6
11
|
import { Alert, AlertTitle, Box, Typography } from '@elementor/ui';
|
|
7
12
|
import { __ } from '@wordpress/i18n';
|
|
8
13
|
|
|
14
|
+
import { useBoundProp } from '../../bound-prop-context';
|
|
15
|
+
import { type Item, type RepeatablePropValue } from '../../components/control-repeater/types';
|
|
9
16
|
import { createControl } from '../../create-control';
|
|
10
17
|
import { RepeatableControl } from '../repeatable-control';
|
|
11
18
|
import { SelectionSizeControl } from '../selection-size-control';
|
|
12
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
initialTransitionValue,
|
|
21
|
+
type TransitionItem,
|
|
22
|
+
transitionProperties,
|
|
23
|
+
type TransitionProperty,
|
|
24
|
+
type TransitionValue,
|
|
25
|
+
} from './data';
|
|
13
26
|
import { subscribeToTransitionEvent } from './trainsition-events';
|
|
14
|
-
import { TransitionSelector } from './transition-selector';
|
|
27
|
+
import { getTransitionPropertyByValue, TransitionSelector } from './transition-selector';
|
|
15
28
|
|
|
16
29
|
const DURATION_CONFIG = {
|
|
17
30
|
variant: 'time',
|
|
@@ -19,9 +32,34 @@ const DURATION_CONFIG = {
|
|
|
19
32
|
defaultUnit: 'ms',
|
|
20
33
|
};
|
|
21
34
|
|
|
35
|
+
const childArrayPropTypeUtil = createArrayPropUtils(
|
|
36
|
+
selectionSizePropTypeUtil.key,
|
|
37
|
+
selectionSizePropTypeUtil.schema,
|
|
38
|
+
'transition'
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
subscribeToTransitionEvent();
|
|
42
|
+
|
|
43
|
+
const areAllPropertiesUsed = ( value: SelectionSizePropValue[] = [] ) => {
|
|
44
|
+
return value?.length
|
|
45
|
+
? transitionProperties.every( ( category ) => {
|
|
46
|
+
return category.properties.every( ( property ) => {
|
|
47
|
+
return (
|
|
48
|
+
property.isDisabled ||
|
|
49
|
+
!! value?.find( ( item ) => {
|
|
50
|
+
return (
|
|
51
|
+
( item.value?.selection?.value as KeyValuePropValue )?.value?.value === property.value
|
|
52
|
+
);
|
|
53
|
+
} )
|
|
54
|
+
);
|
|
55
|
+
} );
|
|
56
|
+
} )
|
|
57
|
+
: false;
|
|
58
|
+
};
|
|
59
|
+
|
|
22
60
|
// this config needs to be loaded at runtime/render since it's the transitionProperties object will be mutated by the pro plugin.
|
|
23
61
|
// See: https://elementor.atlassian.net/browse/ED-20285
|
|
24
|
-
const getSelectionSizeProps = ( recentlyUsedList: string[] ) => {
|
|
62
|
+
const getSelectionSizeProps = ( recentlyUsedList: string[], disabledItems?: string[] ) => {
|
|
25
63
|
return {
|
|
26
64
|
selectionLabel: __( 'Type', 'elementor' ),
|
|
27
65
|
sizeLabel: __( 'Duration', 'elementor' ),
|
|
@@ -29,8 +67,10 @@ const getSelectionSizeProps = ( recentlyUsedList: string[] ) => {
|
|
|
29
67
|
component: TransitionSelector,
|
|
30
68
|
props: {
|
|
31
69
|
recentlyUsedList,
|
|
70
|
+
disabledItems,
|
|
32
71
|
},
|
|
33
72
|
},
|
|
73
|
+
isRepeaterControl: true,
|
|
34
74
|
sizeConfigMap: {
|
|
35
75
|
...transitionProperties.reduce(
|
|
36
76
|
( acc, category ) => {
|
|
@@ -45,13 +85,69 @@ const getSelectionSizeProps = ( recentlyUsedList: string[] ) => {
|
|
|
45
85
|
};
|
|
46
86
|
};
|
|
47
87
|
|
|
48
|
-
|
|
88
|
+
const isItemDisabled = ( item: TransitionItem[ 'value' ] ) => {
|
|
89
|
+
const property = getTransitionPropertyByValue( item.value.selection.value?.value );
|
|
90
|
+
|
|
91
|
+
return ! property ? false : !! property.isDisabled;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const getChildControlConfig = ( recentlyUsedList: string[], disabledItems?: string[] ) => {
|
|
49
95
|
return {
|
|
50
96
|
propTypeUtil: selectionSizePropTypeUtil,
|
|
51
97
|
component: SelectionSizeControl as unknown as React.ComponentType< Record< string, unknown > >,
|
|
52
|
-
props: getSelectionSizeProps( recentlyUsedList ),
|
|
98
|
+
props: getSelectionSizeProps( recentlyUsedList, disabledItems ),
|
|
99
|
+
isItemDisabled: isItemDisabled as ( item: Item< RepeatablePropValue > ) => boolean,
|
|
53
100
|
};
|
|
54
|
-
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const isPropertyUsed = ( value: SelectionSizePropValue[], property: TransitionProperty ) => {
|
|
104
|
+
return ( value ?? [] ).some( ( item ) => {
|
|
105
|
+
return ( item?.value?.selection?.value as KeyValuePropValue )?.value?.value === property.value;
|
|
106
|
+
} );
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const getDisabledItemLabels = ( values: SelectionSizePropValue[] = [] ) => {
|
|
110
|
+
const disabledLabels: string[] = ( values || [] ).map(
|
|
111
|
+
( item ) => ( item.value?.selection as KeyValuePropValue )?.value?.key?.value
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
transitionProperties.forEach( ( category ) => {
|
|
115
|
+
const disabledProperties = category.properties
|
|
116
|
+
.filter( ( property ) => property.isDisabled && ! disabledLabels.includes( property.label ) )
|
|
117
|
+
.map( ( property ) => property.label );
|
|
118
|
+
|
|
119
|
+
disabledLabels.push( ...disabledProperties );
|
|
120
|
+
} );
|
|
121
|
+
|
|
122
|
+
return disabledLabels;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const getInitialValue = ( values: SelectionSizePropValue[] = [] ): TransitionValue => {
|
|
126
|
+
if ( ! values?.length ) {
|
|
127
|
+
return initialTransitionValue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for ( const category of transitionProperties ) {
|
|
131
|
+
for ( const property of category.properties ) {
|
|
132
|
+
if ( isPropertyUsed( values, property ) ) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
...initialTransitionValue,
|
|
138
|
+
selection: {
|
|
139
|
+
$$type: 'key-value',
|
|
140
|
+
value: {
|
|
141
|
+
key: { value: property.label, $$type: 'string' },
|
|
142
|
+
value: { value: property.value, $$type: 'string' },
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return initialTransitionValue;
|
|
150
|
+
};
|
|
55
151
|
|
|
56
152
|
const disableAddItemTooltipContent = (
|
|
57
153
|
<Alert
|
|
@@ -71,8 +167,6 @@ const disableAddItemTooltipContent = (
|
|
|
71
167
|
</Alert>
|
|
72
168
|
);
|
|
73
169
|
|
|
74
|
-
subscribeToTransitionEvent();
|
|
75
|
-
|
|
76
170
|
export const TransitionRepeaterControl = createControl(
|
|
77
171
|
( {
|
|
78
172
|
recentlyUsedListGetter,
|
|
@@ -84,10 +178,40 @@ export const TransitionRepeaterControl = createControl(
|
|
|
84
178
|
const currentStyleIsNormal = currentStyleState === null;
|
|
85
179
|
const [ recentlyUsedList, setRecentlyUsedList ] = useState< string[] >( [] );
|
|
86
180
|
|
|
181
|
+
const { value, setValue } = useBoundProp( childArrayPropTypeUtil );
|
|
182
|
+
const disabledItems = useMemo( () => getDisabledItemLabels( value ), [ value ] );
|
|
183
|
+
|
|
184
|
+
const allowedTransitionSet = useMemo( () => {
|
|
185
|
+
const set = new Set< string >();
|
|
186
|
+
transitionProperties.forEach( ( category ) => {
|
|
187
|
+
category.properties.forEach( ( prop ) => set.add( prop.value ) );
|
|
188
|
+
} );
|
|
189
|
+
return set;
|
|
190
|
+
}, [] );
|
|
191
|
+
|
|
192
|
+
useEffect( () => {
|
|
193
|
+
if ( ! value || value.length === 0 ) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const sanitized = value.filter( ( item ) => {
|
|
198
|
+
const selectionValue = ( item?.value?.selection?.value as KeyValuePropValue )?.value?.value ?? '';
|
|
199
|
+
return allowedTransitionSet.has( selectionValue );
|
|
200
|
+
} );
|
|
201
|
+
|
|
202
|
+
if ( sanitized.length !== value.length ) {
|
|
203
|
+
setValue( sanitized );
|
|
204
|
+
}
|
|
205
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
206
|
+
}, [ allowedTransitionSet ] );
|
|
207
|
+
|
|
87
208
|
useEffect( () => {
|
|
88
209
|
recentlyUsedListGetter().then( setRecentlyUsedList );
|
|
89
210
|
}, [ recentlyUsedListGetter ] );
|
|
90
211
|
|
|
212
|
+
const allPropertiesUsed = useMemo( () => areAllPropertiesUsed( value ), [ value ] );
|
|
213
|
+
const isAddItemDisabled = ! currentStyleIsNormal || allPropertiesUsed;
|
|
214
|
+
|
|
91
215
|
return (
|
|
92
216
|
<RepeatableControl
|
|
93
217
|
label={ __( 'Transitions', 'elementor' ) }
|
|
@@ -96,11 +220,11 @@ export const TransitionRepeaterControl = createControl(
|
|
|
96
220
|
placeholder={ __( 'Empty Transition', 'elementor' ) }
|
|
97
221
|
showDuplicate={ false }
|
|
98
222
|
showToggle={ true }
|
|
99
|
-
initialValues={
|
|
100
|
-
childControlConfig={ getChildControlConfig( recentlyUsedList ) }
|
|
223
|
+
initialValues={ getInitialValue( value ) }
|
|
224
|
+
childControlConfig={ getChildControlConfig( recentlyUsedList, disabledItems ) }
|
|
101
225
|
propKey="transition"
|
|
102
226
|
addItemTooltipProps={ {
|
|
103
|
-
disabled:
|
|
227
|
+
disabled: isAddItemDisabled,
|
|
104
228
|
enableTooltip: ! currentStyleIsNormal,
|
|
105
229
|
tooltipContent: disableAddItemTooltipContent,
|
|
106
230
|
} }
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useRef } from 'react';
|
|
3
|
-
import { keyValuePropTypeUtil } from '@elementor/editor-props';
|
|
3
|
+
import { keyValuePropTypeUtil, type KeyValuePropValue, type StringPropValue } from '@elementor/editor-props';
|
|
4
4
|
import { ChevronDownIcon, VariationsIcon } from '@elementor/icons';
|
|
5
5
|
import { bindPopover, bindTrigger, Box, Popover, UnstableTag, usePopupState } from '@elementor/ui';
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
7
|
|
|
8
8
|
import { useBoundProp } from '../../bound-prop-context';
|
|
9
9
|
import { ItemSelector } from '../../components/item-selector';
|
|
10
|
+
import ControlActions from '../../control-actions/control-actions';
|
|
10
11
|
import { transitionProperties, transitionsItemsList } from './data';
|
|
11
12
|
|
|
12
13
|
const toTransitionSelectorValue = ( label: string ) => {
|
|
@@ -23,16 +24,35 @@ const toTransitionSelectorValue = ( label: string ) => {
|
|
|
23
24
|
return null;
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
export function getTransitionPropertyByValue( item?: StringPropValue | null ) {
|
|
28
|
+
if ( ! item?.value ) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
27
32
|
for ( const category of transitionProperties ) {
|
|
28
|
-
const property
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
for ( const property of category.properties ) {
|
|
34
|
+
if ( property.value === item.value ) {
|
|
35
|
+
return property;
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
}
|
|
39
|
+
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const includeCurrentValueInOptions = ( value: KeyValuePropValue[ 'value' ], disabledItems: string[] ) => {
|
|
44
|
+
return disabledItems.filter( ( item ) => {
|
|
45
|
+
return item !== value.key.value;
|
|
46
|
+
} );
|
|
33
47
|
};
|
|
34
48
|
|
|
35
|
-
export const TransitionSelector = ( {
|
|
49
|
+
export const TransitionSelector = ( {
|
|
50
|
+
recentlyUsedList = [],
|
|
51
|
+
disabledItems = [],
|
|
52
|
+
}: {
|
|
53
|
+
recentlyUsedList: string[];
|
|
54
|
+
disabledItems?: string[];
|
|
55
|
+
} ) => {
|
|
36
56
|
const { value, setValue } = useBoundProp( keyValuePropTypeUtil );
|
|
37
57
|
const {
|
|
38
58
|
key: { value: transitionLabel },
|
|
@@ -42,7 +62,7 @@ export const TransitionSelector = ( { recentlyUsedList = [] }: { recentlyUsedLis
|
|
|
42
62
|
|
|
43
63
|
const getItemList = () => {
|
|
44
64
|
const recentItems = recentlyUsedList
|
|
45
|
-
.map( ( item ) =>
|
|
65
|
+
.map( ( item ) => getTransitionPropertyByValue( { value: item, $$type: 'string' } )?.label )
|
|
46
66
|
.filter( ( item ) => !! item ) as string[];
|
|
47
67
|
const filteredItems = transitionsItemsList.map( ( category ) => {
|
|
48
68
|
return {
|
|
@@ -89,13 +109,15 @@ export const TransitionSelector = ( { recentlyUsedList = [] }: { recentlyUsedLis
|
|
|
89
109
|
|
|
90
110
|
return (
|
|
91
111
|
<Box ref={ defaultRef }>
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
<ControlActions>
|
|
113
|
+
<UnstableTag
|
|
114
|
+
variant="outlined"
|
|
115
|
+
label={ transitionLabel }
|
|
116
|
+
endIcon={ <ChevronDownIcon fontSize="tiny" /> }
|
|
117
|
+
{ ...bindTrigger( popoverState ) }
|
|
118
|
+
fullWidth
|
|
119
|
+
/>
|
|
120
|
+
</ControlActions>
|
|
99
121
|
<Popover
|
|
100
122
|
disablePortal
|
|
101
123
|
disableScrollLock
|
|
@@ -113,6 +135,7 @@ export const TransitionSelector = ( { recentlyUsedList = [] }: { recentlyUsedLis
|
|
|
113
135
|
sectionWidth={ 268 }
|
|
114
136
|
title={ __( 'Transition Property', 'elementor' ) }
|
|
115
137
|
icon={ VariationsIcon as React.ElementType< { fontSize: string } > }
|
|
138
|
+
disabledItems={ includeCurrentValueInOptions( value, disabledItems ) }
|
|
116
139
|
/>
|
|
117
140
|
</Popover>
|
|
118
141
|
</Box>
|
|
@@ -6,20 +6,25 @@ import { useBoundProp } from '../bound-prop-context';
|
|
|
6
6
|
import ControlActions from '../control-actions/control-actions';
|
|
7
7
|
import { createControl } from '../create-control';
|
|
8
8
|
|
|
9
|
-
export const UrlControl = createControl(
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export const UrlControl = createControl(
|
|
10
|
+
( { placeholder, ariaLabel }: { placeholder?: string; ariaLabel?: string } ) => {
|
|
11
|
+
const { value, setValue, disabled } = useBoundProp( urlPropTypeUtil );
|
|
12
|
+
const handleChange = ( event: React.ChangeEvent< HTMLInputElement > ) => setValue( event.target.value );
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
return (
|
|
15
|
+
<ControlActions>
|
|
16
|
+
<TextField
|
|
17
|
+
size="tiny"
|
|
18
|
+
fullWidth
|
|
19
|
+
value={ value ?? '' }
|
|
20
|
+
disabled={ disabled }
|
|
21
|
+
onChange={ handleChange }
|
|
22
|
+
placeholder={ placeholder }
|
|
23
|
+
inputProps={ {
|
|
24
|
+
...( ariaLabel ? { 'aria-label': ariaLabel } : {} ),
|
|
25
|
+
} }
|
|
26
|
+
/>
|
|
27
|
+
</ControlActions>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
);
|
package/src/create-control.tsx
CHANGED
|
@@ -15,11 +15,12 @@ export type ControlComponent< TComponent extends AnyComponentType = AnyComponent
|
|
|
15
15
|
|
|
16
16
|
export function createControl< T extends AnyComponentType >( Control: T ) {
|
|
17
17
|
return ( ( props: ComponentProps< T > ) => {
|
|
18
|
-
const
|
|
18
|
+
const { ControlToRender, OriginalControl, isReplaced } = useControlReplacement( Control );
|
|
19
|
+
const controlProps = isReplaced ? { ...props, OriginalControl } : props;
|
|
19
20
|
|
|
20
21
|
return (
|
|
21
22
|
<ErrorBoundary fallback={ null }>
|
|
22
|
-
<
|
|
23
|
+
<ControlToRender { ...controlProps } />
|
|
23
24
|
</ErrorBoundary>
|
|
24
25
|
);
|
|
25
26
|
} ) as ControlComponent< T >;
|