@elementor/editor-editing-panel 1.4.0 → 1.5.0
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/CHANGELOG.md +28 -1
- package/dist/index.js +592 -626
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +526 -560
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/components/conditional-tooltip-wrapper.tsx +13 -7
- package/src/components/css-class-selector.tsx +1 -3
- package/src/components/style-sections/background-section/background-section.tsx +4 -9
- package/src/components/style-sections/layout-section/layout-section.tsx +12 -0
- package/src/components/style-sections/position-section/position-field.tsx +6 -2
- package/src/components/style-sections/position-section/position-section.tsx +51 -30
- package/src/dynamics/components/dynamic-selection-control.tsx +3 -5
- package/src/dynamics/components/dynamic-selection.tsx +6 -6
- package/src/dynamics/dynamic-control.tsx +2 -3
- package/src/hooks/use-computed-style.ts +29 -0
- package/src/hooks/use-persist-dynamic-value.ts +11 -0
- package/src/hooks/use-session-storage.ts +46 -0
- package/src/hooks/use-styles-field.ts +8 -44
- package/src/hooks/use-styles-fields.ts +32 -0
- package/src/components/style-sections/background-section/background-color-field.tsx +0 -21
- package/src/hooks/use-prop-value-history.ts +0 -45
- package/src/hooks/use-style-prop-history.ts +0 -75
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-editing-panel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -40,14 +40,14 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@elementor/editor": "0.17.2",
|
|
43
|
-
"@elementor/editor-controls": "0.
|
|
43
|
+
"@elementor/editor-controls": "0.4.0",
|
|
44
44
|
"@elementor/editor-elements": "0.3.3",
|
|
45
45
|
"@elementor/menus": "0.1.2",
|
|
46
46
|
"@elementor/editor-props": "0.5.0",
|
|
47
47
|
"@elementor/editor-panels": "0.10.2",
|
|
48
48
|
"@elementor/editor-responsive": "0.12.4",
|
|
49
49
|
"@elementor/editor-styles": "0.3.2",
|
|
50
|
-
"@elementor/editor-styles-repository": "0.
|
|
50
|
+
"@elementor/editor-styles-repository": "0.3.0",
|
|
51
51
|
"@elementor/editor-v1-adapters": "0.8.5",
|
|
52
52
|
"@elementor/icons": "^1.20.0",
|
|
53
53
|
"@elementor/schema": "0.1.2",
|
|
@@ -32,21 +32,27 @@ export const ConditionalTooltipWrapper = ( { maxWidth, title }: ConditionalToolt
|
|
|
32
32
|
if ( isOverflown ) {
|
|
33
33
|
return (
|
|
34
34
|
<Tooltip title={ title } placement="top">
|
|
35
|
-
<Content maxWidth={ maxWidth } ref={ elRef }
|
|
35
|
+
<Content maxWidth={ maxWidth } ref={ elRef }>
|
|
36
|
+
{ title }
|
|
37
|
+
</Content>
|
|
36
38
|
</Tooltip>
|
|
37
39
|
);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
return
|
|
42
|
+
return (
|
|
43
|
+
<Content maxWidth={ maxWidth } ref={ elRef }>
|
|
44
|
+
{ title }
|
|
45
|
+
</Content>
|
|
46
|
+
);
|
|
41
47
|
};
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
type ContentProps = React.PropsWithChildren< Omit< ConditionalTooltipWrapperProps, 'title' > >;
|
|
50
|
+
|
|
51
|
+
const Content = React.forwardRef( ( { maxWidth, ...tooltipProps }: ContentProps, ref ) => (
|
|
44
52
|
<Box
|
|
45
53
|
ref={ ref }
|
|
46
54
|
position="relative"
|
|
47
55
|
sx={ { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth } }
|
|
48
|
-
{ ...
|
|
49
|
-
|
|
50
|
-
{ title }
|
|
51
|
-
</Box>
|
|
56
|
+
{ ...tooltipProps }
|
|
57
|
+
/>
|
|
52
58
|
) );
|
|
@@ -102,9 +102,7 @@ function useOptions() {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
function useAppliedOptions( options: Option[], appliedIds: StyleDefinitionID[] ) {
|
|
105
|
-
const applied = appliedIds
|
|
106
|
-
.map( ( id ) => options.find( ( option ) => option.value === id ) )
|
|
107
|
-
.filter( ( option ) => !! option );
|
|
105
|
+
const applied = options.filter( ( option ) => appliedIds.includes( option.value ) );
|
|
108
106
|
|
|
109
107
|
const hasElementsProviderStyleApplied = applied.some(
|
|
110
108
|
( option ) => option.provider === ELEMENTS_STYLES_PROVIDER_KEY
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { Stack } from '@elementor/ui';
|
|
2
|
+
import { BackgroundControl } from '@elementor/editor-controls';
|
|
4
3
|
|
|
5
4
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
6
|
-
import { BackgroundColorField } from './background-color-field';
|
|
7
5
|
|
|
8
6
|
export const BackgroundSection = () => {
|
|
9
7
|
return (
|
|
10
|
-
<
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
</StylesField>
|
|
14
|
-
<BackgroundColorField />
|
|
15
|
-
</Stack>
|
|
8
|
+
<StylesField bind="background">
|
|
9
|
+
<BackgroundControl />
|
|
10
|
+
</StylesField>
|
|
16
11
|
);
|
|
17
12
|
};
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ControlLabel } from '@elementor/editor-controls';
|
|
3
|
+
import { useParentElement } from '@elementor/editor-elements';
|
|
3
4
|
import { type StringPropValue } from '@elementor/editor-props';
|
|
4
5
|
import { Divider, Stack } from '@elementor/ui';
|
|
5
6
|
import { __ } from '@wordpress/i18n';
|
|
6
7
|
|
|
8
|
+
import { useElement } from '../../../contexts/element-context';
|
|
9
|
+
import { useComputedStyle } from '../../../hooks/use-computed-style';
|
|
7
10
|
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
8
11
|
import { AlignItemsField } from './align-items-field';
|
|
9
12
|
import { AlignSelfChild } from './align-self-child-field';
|
|
@@ -17,11 +20,15 @@ import { WrapField } from './wrap-field';
|
|
|
17
20
|
|
|
18
21
|
export const LayoutSection = () => {
|
|
19
22
|
const [ display ] = useStylesField< StringPropValue >( 'display' );
|
|
23
|
+
const { element } = useElement();
|
|
24
|
+
const parent = useParentElement( element.id );
|
|
25
|
+
const parentStyle = useComputedStyle( parent?.id || null );
|
|
20
26
|
|
|
21
27
|
return (
|
|
22
28
|
<Stack gap={ 2 }>
|
|
23
29
|
<DisplayField />
|
|
24
30
|
{ 'flex' === display?.value && <FlexFields /> }
|
|
31
|
+
{ 'flex' === parentStyle?.display && <FlexChildFields /> }
|
|
25
32
|
</Stack>
|
|
26
33
|
);
|
|
27
34
|
};
|
|
@@ -34,6 +41,11 @@ const FlexFields = () => (
|
|
|
34
41
|
<Divider />
|
|
35
42
|
<GapControlField />
|
|
36
43
|
<WrapField />
|
|
44
|
+
</>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const FlexChildFields = () => (
|
|
48
|
+
<>
|
|
37
49
|
<Divider />
|
|
38
50
|
<ControlLabel>{ __( 'Flex child', 'elementor' ) }</ControlLabel>
|
|
39
51
|
<AlignSelfChild />
|
|
@@ -12,7 +12,11 @@ const positionOptions = [
|
|
|
12
12
|
{ label: __( 'Fixed', 'elementor' ), value: 'fixed' },
|
|
13
13
|
];
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
type Props = {
|
|
16
|
+
onChange?: ( newValue: string | null, previousValue: string | null | undefined ) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const PositionField = ( { onChange }: Props ) => {
|
|
16
20
|
return (
|
|
17
21
|
<StylesField bind="position">
|
|
18
22
|
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
@@ -20,7 +24,7 @@ export const PositionField = () => {
|
|
|
20
24
|
<ControlLabel>{ __( 'Position', 'elementor' ) }</ControlLabel>
|
|
21
25
|
</Grid>
|
|
22
26
|
<Grid item xs={ 6 }>
|
|
23
|
-
<SelectControl options={ positionOptions } />
|
|
27
|
+
<SelectControl options={ positionOptions } onChange={ onChange } />
|
|
24
28
|
</Grid>
|
|
25
29
|
</Grid>
|
|
26
30
|
</StylesField>
|
|
@@ -1,25 +1,65 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import type { PropValue, StringPropValue } from '@elementor/editor-props';
|
|
2
|
+
import { type StringPropValue } from '@elementor/editor-props';
|
|
4
3
|
import { Stack } from '@elementor/ui';
|
|
5
4
|
|
|
6
|
-
import {
|
|
5
|
+
import { useStyle } from '../../../contexts/style-context';
|
|
6
|
+
import { useSessionStorage } from '../../../hooks/use-session-storage';
|
|
7
7
|
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
8
|
+
import { useStylesFields } from '../../../hooks/use-styles-fields';
|
|
8
9
|
import { DimensionsField } from './dimensions-field';
|
|
9
10
|
import { PositionField } from './position-field';
|
|
10
11
|
import { ZIndexField } from './z-index-field';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
type DimensionValue =
|
|
14
|
+
| {
|
|
15
|
+
$$type: 'size';
|
|
16
|
+
value: number;
|
|
17
|
+
}
|
|
18
|
+
| undefined
|
|
19
|
+
| null;
|
|
20
|
+
|
|
21
|
+
type DimensionsValues = {
|
|
22
|
+
top: DimensionValue;
|
|
23
|
+
bottom: DimensionValue;
|
|
24
|
+
left: DimensionValue;
|
|
25
|
+
right: DimensionValue;
|
|
26
|
+
};
|
|
13
27
|
|
|
14
28
|
export const PositionSection = () => {
|
|
15
29
|
const [ positionValue ] = useStylesField< StringPropValue >( 'position' );
|
|
16
|
-
|
|
30
|
+
const [ dimensionsValues, setDimensionsValues ] = useStylesFields< DimensionsValues >( [
|
|
31
|
+
'top',
|
|
32
|
+
'bottom',
|
|
33
|
+
'left',
|
|
34
|
+
'right',
|
|
35
|
+
] );
|
|
36
|
+
|
|
37
|
+
const [ dimensionsValuesFromHistory, updateDimensionsHistory, clearDimensionsHistory ] = usePersistDimensions();
|
|
38
|
+
|
|
39
|
+
const onPositionChange = ( newPosition: string | null, previousPosition: string | null | undefined ) => {
|
|
40
|
+
if ( newPosition === 'static' ) {
|
|
41
|
+
if ( dimensionsValues ) {
|
|
42
|
+
updateDimensionsHistory( dimensionsValues );
|
|
43
|
+
setDimensionsValues( {
|
|
44
|
+
top: undefined,
|
|
45
|
+
bottom: undefined,
|
|
46
|
+
left: undefined,
|
|
47
|
+
right: undefined,
|
|
48
|
+
} );
|
|
49
|
+
}
|
|
50
|
+
} else if ( previousPosition === 'static' ) {
|
|
51
|
+
if ( dimensionsValuesFromHistory ) {
|
|
52
|
+
setDimensionsValues( dimensionsValuesFromHistory );
|
|
53
|
+
clearDimensionsHistory();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
17
57
|
|
|
18
58
|
const isNotStatic = positionValue && positionValue?.value !== 'static';
|
|
19
59
|
|
|
20
60
|
return (
|
|
21
61
|
<Stack gap={ 1.5 }>
|
|
22
|
-
<PositionField />
|
|
62
|
+
<PositionField onChange={ onPositionChange } />
|
|
23
63
|
{ isNotStatic ? (
|
|
24
64
|
<>
|
|
25
65
|
<DimensionsField />
|
|
@@ -30,29 +70,10 @@ export const PositionSection = () => {
|
|
|
30
70
|
);
|
|
31
71
|
};
|
|
32
72
|
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
( newPositionValue: PropValue, previousPosition: PropValue ) => {
|
|
38
|
-
if ( ! dimensionsHistory ) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const { saveStylePropsHistory, updateStylePropsFromHistory, clearCurrentStyleProps } = dimensionsHistory;
|
|
43
|
-
|
|
44
|
-
if ( newPositionValue === 'static' ) {
|
|
45
|
-
saveStylePropsHistory();
|
|
46
|
-
clearCurrentStyleProps();
|
|
47
|
-
} else if ( previousPosition === 'static' ) {
|
|
48
|
-
updateStylePropsFromHistory();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
previousPosition = newPositionValue;
|
|
52
|
-
},
|
|
53
|
-
[ dimensionsHistory ]
|
|
54
|
-
);
|
|
73
|
+
const usePersistDimensions = () => {
|
|
74
|
+
const { id: styleDefID, meta } = useStyle();
|
|
75
|
+
const styleVariantPath = `styles/${ styleDefID }/${ meta.breakpoint || 'desktop' }/${ meta.state || 'null' }`;
|
|
76
|
+
const dimensionsPath = `${ styleVariantPath }/dimensions`;
|
|
55
77
|
|
|
56
|
-
|
|
57
|
-
registerChangeListener?.( onPositionChange );
|
|
78
|
+
return useSessionStorage< DimensionsValues >( dimensionsPath );
|
|
58
79
|
};
|
|
@@ -24,7 +24,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
24
24
|
|
|
25
25
|
import { Control as BaseControl } from '../../controls-registry/control';
|
|
26
26
|
import { type ControlType, getControlByType } from '../../controls-registry/controls-registry';
|
|
27
|
-
import {
|
|
27
|
+
import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
|
|
28
28
|
import { DynamicControl } from '../dynamic-control';
|
|
29
29
|
import { useDynamicTag } from '../hooks/use-dynamic-tag';
|
|
30
30
|
import { type DynamicTag } from '../types';
|
|
@@ -36,7 +36,7 @@ const SIZE = 'tiny';
|
|
|
36
36
|
export const DynamicSelectionControl = () => {
|
|
37
37
|
const { setValue: setAnyValue } = useBoundProp();
|
|
38
38
|
const { bind, value } = useBoundProp( dynamicPropTypeUtil );
|
|
39
|
-
const
|
|
39
|
+
const [ propValueFromHistory ] = usePersistDynamicValue( bind );
|
|
40
40
|
const { name: tagName = '' } = value;
|
|
41
41
|
|
|
42
42
|
const selectionPopoverId = useId();
|
|
@@ -45,9 +45,7 @@ export const DynamicSelectionControl = () => {
|
|
|
45
45
|
const dynamicTag = useDynamicTag( bind, tagName );
|
|
46
46
|
|
|
47
47
|
const removeDynamicTag = () => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
setAnyValue( propValue ?? null );
|
|
48
|
+
setAnyValue( propValueFromHistory ?? null );
|
|
51
49
|
};
|
|
52
50
|
|
|
53
51
|
if ( ! dynamicTag ) {
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from '@elementor/ui';
|
|
18
18
|
import { __ } from '@wordpress/i18n';
|
|
19
19
|
|
|
20
|
-
import {
|
|
20
|
+
import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
|
|
21
21
|
import { usePropDynamicTags } from '../hooks/use-prop-dynamic-tags';
|
|
22
22
|
import { getAtomicDynamicTags } from '../sync/get-atomic-dynamic-tags';
|
|
23
23
|
import { dynamicPropTypeUtil } from '../utils';
|
|
@@ -40,11 +40,11 @@ export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
|
|
|
40
40
|
const { groups: dynamicGroups } = getAtomicDynamicTags() || {};
|
|
41
41
|
|
|
42
42
|
const { value: anyValue } = useBoundProp();
|
|
43
|
-
const { bind, value:
|
|
43
|
+
const { bind, value: dynamicValue, setValue } = useBoundProp( dynamicPropTypeUtil );
|
|
44
44
|
|
|
45
|
-
const
|
|
45
|
+
const [ , updatePropValueHistory ] = usePersistDynamicValue( bind );
|
|
46
46
|
|
|
47
|
-
const isCurrentValueDynamic = !!
|
|
47
|
+
const isCurrentValueDynamic = !! dynamicValue;
|
|
48
48
|
|
|
49
49
|
const options = useFilteredOptions( bind, searchValue );
|
|
50
50
|
|
|
@@ -54,7 +54,7 @@ export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
|
|
|
54
54
|
|
|
55
55
|
const handleSetDynamicTag = ( value: string ) => {
|
|
56
56
|
if ( ! isCurrentValueDynamic ) {
|
|
57
|
-
updatePropValueHistory(
|
|
57
|
+
updatePropValueHistory( anyValue );
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
setValue( { name: value, settings: {} } );
|
|
@@ -90,7 +90,7 @@ export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
|
|
|
90
90
|
{ dynamicGroups?.[ category ]?.title || category }
|
|
91
91
|
</ListSubheader>
|
|
92
92
|
{ items.map( ( { value, label: tagLabel } ) => {
|
|
93
|
-
const isSelected = isCurrentValueDynamic && value ===
|
|
93
|
+
const isSelected = isCurrentValueDynamic && value === dynamicValue?.name;
|
|
94
94
|
|
|
95
95
|
return (
|
|
96
96
|
<MenuItem
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { BoundPropProvider, useBoundProp } from '@elementor/editor-controls';
|
|
3
|
-
import {
|
|
3
|
+
import { type PropKey, type PropValue } from '@elementor/editor-props';
|
|
4
4
|
|
|
5
5
|
import { useDynamicTag } from './hooks/use-dynamic-tag';
|
|
6
6
|
import { dynamicPropTypeUtil } from './utils';
|
|
@@ -27,8 +27,7 @@ export const DynamicControl = ( { bind, children }: DynamicControlProps ) => {
|
|
|
27
27
|
name,
|
|
28
28
|
settings: {
|
|
29
29
|
...settings,
|
|
30
|
-
|
|
31
|
-
[ bind ]: isTransformable( newValue ) ? newValue.value : newValue,
|
|
30
|
+
[ bind ]: newValue,
|
|
32
31
|
},
|
|
33
32
|
} );
|
|
34
33
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { __privateUseListenTo as useListenTo, commandEndEvent, windowEvent } from '@elementor/editor-v1-adapters';
|
|
2
|
+
|
|
3
|
+
import { type ExtendedWindow } from '../sync/types';
|
|
4
|
+
|
|
5
|
+
export function useComputedStyle( elementId: string | null ) {
|
|
6
|
+
return useListenTo(
|
|
7
|
+
[
|
|
8
|
+
windowEvent( 'elementor/device-mode/change' ),
|
|
9
|
+
commandEndEvent( 'document/elements/reset-style' ),
|
|
10
|
+
commandEndEvent( 'document/elements/settings' ),
|
|
11
|
+
commandEndEvent( 'document/elements/paste-style' ),
|
|
12
|
+
],
|
|
13
|
+
() => {
|
|
14
|
+
if ( ! elementId ) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const extendedWindow: ExtendedWindow = window;
|
|
19
|
+
const element = extendedWindow.elementor?.getContainer?.( elementId );
|
|
20
|
+
|
|
21
|
+
if ( ! element?.view?.el ) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const resp = window.getComputedStyle( element.view.el );
|
|
26
|
+
return resp;
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type PropValue } from '@elementor/editor-props';
|
|
2
|
+
|
|
3
|
+
import { useElement } from '../contexts/element-context';
|
|
4
|
+
import { type DynamicPropValue } from '../dynamics/types';
|
|
5
|
+
import { useSessionStorage } from './use-session-storage';
|
|
6
|
+
|
|
7
|
+
export const usePersistDynamicValue = < T extends DynamicPropValue | PropValue >( propKey: string ) => {
|
|
8
|
+
const { element } = useElement();
|
|
9
|
+
const prefixedKey = `dynamic/non-dynamic-values-history/${ element.id }/${ propKey }`;
|
|
10
|
+
return useSessionStorage< T >( prefixedKey );
|
|
11
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { getSessionStorageItem, removeSessionStorageItem, setSessionStorageItem } from '@elementor/utils';
|
|
3
|
+
|
|
4
|
+
export const useSessionStorage = < T >( key: string ) => {
|
|
5
|
+
const prefixedKey = `elementor/${ key }`;
|
|
6
|
+
|
|
7
|
+
const [ value, setValue ] = useState< T | null >();
|
|
8
|
+
|
|
9
|
+
useEffect( () => {
|
|
10
|
+
return subscribeToSessionStorage< T | null >( prefixedKey, ( newValue ) => {
|
|
11
|
+
setValue( newValue ?? null );
|
|
12
|
+
} );
|
|
13
|
+
}, [ prefixedKey ] );
|
|
14
|
+
|
|
15
|
+
const saveValue = ( newValue: T ) => {
|
|
16
|
+
setSessionStorageItem( prefixedKey, newValue );
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const removeValue = () => {
|
|
20
|
+
removeSessionStorageItem( prefixedKey );
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
return [ value, saveValue, removeValue ] as const;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const subscribeToSessionStorage = < T >( key: string, subscriber: ( value: T ) => void ) => {
|
|
27
|
+
subscriber( getSessionStorageItem( key ) as T );
|
|
28
|
+
|
|
29
|
+
const abortController = new AbortController();
|
|
30
|
+
|
|
31
|
+
window.addEventListener(
|
|
32
|
+
'storage',
|
|
33
|
+
( e ) => {
|
|
34
|
+
if ( e.key !== key || e.storageArea !== sessionStorage ) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
subscriber( getSessionStorageItem( key ) as T );
|
|
39
|
+
},
|
|
40
|
+
{ signal: abortController.signal }
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return () => {
|
|
44
|
+
abortController.abort();
|
|
45
|
+
};
|
|
46
|
+
};
|
|
@@ -1,53 +1,17 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
-
import { updateStyle, useElementStyleProp } from '@elementor/editor-elements';
|
|
3
1
|
import type { PropKey, PropValue } from '@elementor/editor-props';
|
|
4
|
-
import { __ } from '@wordpress/i18n';
|
|
5
2
|
|
|
6
|
-
import {
|
|
7
|
-
import { useElement } from '../contexts/element-context';
|
|
8
|
-
import { useStyle } from '../contexts/style-context';
|
|
3
|
+
import { useStylesFields } from './use-styles-fields';
|
|
9
4
|
|
|
10
|
-
export
|
|
11
|
-
propName:
|
|
12
|
-
): [
|
|
13
|
-
T | null,
|
|
14
|
-
( newValue: T ) => void,
|
|
15
|
-
( callback: ( newValue: T | null, previousValue: T | null ) => void ) => void,
|
|
16
|
-
] => {
|
|
17
|
-
const { element } = useElement();
|
|
18
|
-
const { id, meta } = useStyle();
|
|
19
|
-
const classesProp = useClassesProp();
|
|
20
|
-
const previousValue = useRef< T | null >( null );
|
|
21
|
-
const onChangeCallbacks = useRef< Set< ( newValue: T | null, previousValue: T | null ) => void > >( new Set() );
|
|
5
|
+
export function useStylesField< T extends PropValue >( propName: PropKey ): [ T | null, ( newValue: T ) => void ] {
|
|
6
|
+
const [ values, setValues ] = useStylesFields< { [ k: typeof propName ]: T } >( [ propName ] );
|
|
22
7
|
|
|
23
|
-
const value =
|
|
24
|
-
elementID: element.id,
|
|
25
|
-
styleDefID: id,
|
|
26
|
-
meta,
|
|
27
|
-
propName,
|
|
28
|
-
} );
|
|
8
|
+
const value = values?.[ propName ] ?? null;
|
|
29
9
|
|
|
30
10
|
const setValue = ( newValue: T ) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
styleDefID: id,
|
|
34
|
-
props: { [ propName ]: newValue },
|
|
35
|
-
meta,
|
|
36
|
-
bind: classesProp,
|
|
37
|
-
label: __( 'local', 'elementor' ),
|
|
11
|
+
setValues( {
|
|
12
|
+
[ propName ]: newValue,
|
|
38
13
|
} );
|
|
39
14
|
};
|
|
40
15
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
useEffect( () => {
|
|
46
|
-
onChangeCallbacks.current.forEach( ( cb ) => {
|
|
47
|
-
cb( value, previousValue.current );
|
|
48
|
-
} );
|
|
49
|
-
previousValue.current = value;
|
|
50
|
-
}, [ value ] );
|
|
51
|
-
|
|
52
|
-
return [ value, setValue, registerChangeListener ];
|
|
53
|
-
};
|
|
16
|
+
return [ value, setValue ];
|
|
17
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { updateStyle, useElementStyleProps } from '@elementor/editor-elements';
|
|
2
|
+
import type { Props } from '@elementor/editor-props';
|
|
3
|
+
import { __ } from '@wordpress/i18n';
|
|
4
|
+
|
|
5
|
+
import { useClassesProp } from '../contexts/classes-prop-context';
|
|
6
|
+
import { useElement } from '../contexts/element-context';
|
|
7
|
+
import { useStyle } from '../contexts/style-context';
|
|
8
|
+
|
|
9
|
+
export function useStylesFields< T extends Props >( propNames: ( keyof T & string )[] ) {
|
|
10
|
+
const { element } = useElement();
|
|
11
|
+
const { id, meta } = useStyle();
|
|
12
|
+
const classesProp = useClassesProp();
|
|
13
|
+
|
|
14
|
+
const value = useElementStyleProps( {
|
|
15
|
+
elementID: element.id,
|
|
16
|
+
styleDefID: id,
|
|
17
|
+
meta,
|
|
18
|
+
propNames,
|
|
19
|
+
} );
|
|
20
|
+
|
|
21
|
+
const setValue = ( newValues: T ) => {
|
|
22
|
+
updateStyle( {
|
|
23
|
+
elementID: element.id,
|
|
24
|
+
styleDefID: id,
|
|
25
|
+
props: newValues,
|
|
26
|
+
meta,
|
|
27
|
+
bind: classesProp,
|
|
28
|
+
label: __( 'local', 'elementor' ),
|
|
29
|
+
} );
|
|
30
|
+
};
|
|
31
|
+
return [ value, setValue ] as const;
|
|
32
|
+
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { ColorControl, ControlLabel } from '@elementor/editor-controls';
|
|
3
|
-
import { Grid } from '@elementor/ui';
|
|
4
|
-
import { __ } from '@wordpress/i18n';
|
|
5
|
-
|
|
6
|
-
import { StylesField } from '../../../controls-registry/styles-field';
|
|
7
|
-
|
|
8
|
-
export const BackgroundColorField = () => {
|
|
9
|
-
return (
|
|
10
|
-
<StylesField bind="background-color">
|
|
11
|
-
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
12
|
-
<Grid item xs={ 6 }>
|
|
13
|
-
<ControlLabel>{ __( 'Color', 'elementor' ) }</ControlLabel>
|
|
14
|
-
</Grid>
|
|
15
|
-
<Grid item xs={ 6 }>
|
|
16
|
-
<ColorControl />
|
|
17
|
-
</Grid>
|
|
18
|
-
</Grid>
|
|
19
|
-
</StylesField>
|
|
20
|
-
);
|
|
21
|
-
};
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { useCallback, useMemo } from 'react';
|
|
2
|
-
import { getSessionStorageItem, setSessionStorageItem } from '@elementor/utils';
|
|
3
|
-
|
|
4
|
-
import { useElement } from '../contexts/element-context';
|
|
5
|
-
|
|
6
|
-
export const PROPS_VALUES_HISTORY_PREFIX = 'elementor/editor-editing-panel/prop-value-history';
|
|
7
|
-
|
|
8
|
-
export const usePropValueHistory = () => {
|
|
9
|
-
const { element } = useElement();
|
|
10
|
-
const elementKey = `${ PROPS_VALUES_HISTORY_PREFIX }/${ element.id }`;
|
|
11
|
-
|
|
12
|
-
const getElementPropsHistory = useCallback( () => {
|
|
13
|
-
return getSessionStorageItem< Record< string, unknown > >( elementKey );
|
|
14
|
-
}, [ elementKey ] );
|
|
15
|
-
|
|
16
|
-
const getPropValue = useCallback(
|
|
17
|
-
< T >( propKey: string ) => {
|
|
18
|
-
const elementPropValues = getElementPropsHistory();
|
|
19
|
-
return ( elementPropValues?.[ propKey ] ?? null ) as T | null;
|
|
20
|
-
},
|
|
21
|
-
[ getElementPropsHistory ]
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
const setPropValue = useCallback(
|
|
25
|
-
( propKey: string, propValue: unknown ) => {
|
|
26
|
-
const elementPropValues = getElementPropsHistory();
|
|
27
|
-
const updatedElementPropValues = { ...elementPropValues, [ propKey ]: propValue };
|
|
28
|
-
setSessionStorageItem( elementKey, updatedElementPropValues );
|
|
29
|
-
},
|
|
30
|
-
[ getElementPropsHistory, elementKey ]
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
const removeProp = useCallback(
|
|
34
|
-
( propKey: string ) => {
|
|
35
|
-
const elementPropValues = getElementPropsHistory();
|
|
36
|
-
const updatedElementPropValues = Object.fromEntries(
|
|
37
|
-
Object.entries( elementPropValues || {} ).filter( ( [ key ] ) => key !== propKey )
|
|
38
|
-
);
|
|
39
|
-
setSessionStorageItem( elementKey, updatedElementPropValues );
|
|
40
|
-
},
|
|
41
|
-
[ getElementPropsHistory, elementKey ]
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
return useMemo( () => ( { getPropValue, setPropValue, removeProp } ), [ getPropValue, removeProp, setPropValue ] );
|
|
45
|
-
};
|