@elementor/editor-editing-panel 1.9.0 → 1.11.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 +105 -0
- package/dist/index.d.mts +1 -35
- package/dist/index.d.ts +1 -35
- package/dist/index.js +996 -1059
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +905 -970
- package/dist/index.mjs.map +1 -1
- package/package.json +18 -14
- package/src/components/css-classes/css-class-item.tsx +130 -0
- package/src/components/css-classes/css-class-menu.tsx +151 -0
- package/src/components/{css-class-selector.tsx → css-classes/css-class-selector.tsx} +34 -160
- package/src/components/style-sections/layout-section/display-field.tsx +9 -1
- package/src/components/style-sections/layout-section/flex-order-field.tsx +5 -5
- package/src/components/style-sections/layout-section/flex-size-field.tsx +1 -1
- package/src/components/style-sections/layout-section/gap-control-field.tsx +0 -2
- package/src/components/style-sections/position-section/dimensions-field.tsx +1 -1
- package/src/components/style-sections/position-section/position-section.tsx +1 -1
- package/src/components/style-sections/typography-section/font-weight-field.tsx +9 -5
- package/src/components/style-sections/typography-section/text-alignment-field.tsx +16 -8
- package/src/components/style-sections/typography-section/transform-field.tsx +12 -3
- package/src/components/style-tab.tsx +1 -1
- package/src/contexts/style-context.tsx +36 -5
- package/src/controls-registry/control.tsx +3 -12
- package/src/controls-registry/controls-registry.tsx +3 -1
- package/src/controls-registry/settings-field.tsx +8 -1
- package/src/dynamics/components/dynamic-selection.tsx +1 -1
- package/src/dynamics/dynamic-control.tsx +1 -1
- package/src/dynamics/types.ts +2 -2
- package/src/dynamics/utils.ts +2 -2
- package/src/errors.ts +22 -0
- package/src/hooks/use-persist-dynamic-value.ts +1 -1
- package/src/hooks/use-styles-fields.ts +151 -9
- package/src/hooks/use-unapply-class.ts +4 -0
- package/src/index.ts +1 -2
- package/src/init.ts +2 -4
- package/src/sync/types.ts +4 -3
- package/src/components/collapsible-field.tsx +0 -36
- package/src/components/conditional-tooltip-wrapper.tsx +0 -58
- package/src/components/css-class-menu.tsx +0 -125
- package/src/components/editable-field.tsx +0 -166
- package/src/contexts/css-class-item-context.tsx +0 -31
- package/src/css-classes.ts +0 -45
- package/src/hooks/use-session-storage.ts +0 -46
- package/src/sync/enqueue-font.ts +0 -7
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type StringPropValue } from '@elementor/editor-props';
|
|
3
|
+
import { useSessionStorage } from '@elementor/session';
|
|
3
4
|
import { Stack } from '@elementor/ui';
|
|
4
5
|
|
|
5
6
|
import { useStyle } from '../../../contexts/style-context';
|
|
6
|
-
import { useSessionStorage } from '../../../hooks/use-session-storage';
|
|
7
7
|
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
8
8
|
import { useStylesFields } from '../../../hooks/use-styles-fields';
|
|
9
9
|
import { DimensionsField } from './dimensions-field';
|
|
@@ -6,11 +6,15 @@ import { __ } from '@wordpress/i18n';
|
|
|
6
6
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
7
7
|
|
|
8
8
|
const fontWeightOptions = [
|
|
9
|
-
{ label: __( '
|
|
10
|
-
{ label: __( '
|
|
11
|
-
{ label: __( '
|
|
12
|
-
{ label: __( '
|
|
13
|
-
{ label: __( '
|
|
9
|
+
{ value: '100', label: __( '100 - Thin', 'elementor' ) },
|
|
10
|
+
{ value: '200', label: __( '200 - Extra Light', 'elementor' ) },
|
|
11
|
+
{ value: '300', label: __( '300 - Light', 'elementor' ) },
|
|
12
|
+
{ value: '400', label: __( '400 - Normal', 'elementor' ) },
|
|
13
|
+
{ value: '500', label: __( '500 - Medium', 'elementor' ) },
|
|
14
|
+
{ value: '600', label: __( '600 - Semi Bold', 'elementor' ) },
|
|
15
|
+
{ value: '700', label: __( '700 - Bold', 'elementor' ) },
|
|
16
|
+
{ value: '800', label: __( '800 - Extra Bold', 'elementor' ) },
|
|
17
|
+
{ value: '900', label: __( '900 - Black', 'elementor' ) },
|
|
14
18
|
];
|
|
15
19
|
|
|
16
20
|
export const FontWeightField = () => {
|
|
@@ -1,33 +1,41 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
3
|
import { AlignCenterIcon, AlignJustifiedIcon, AlignLeftIcon, AlignRightIcon } from '@elementor/icons';
|
|
4
|
-
import { Grid } from '@elementor/ui';
|
|
4
|
+
import { Grid, withDirection } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
7
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
|
+
import { RotatedIcon } from '../layout-section/utils/rotated-icon';
|
|
8
9
|
|
|
9
|
-
type Alignments = '
|
|
10
|
+
type Alignments = 'start' | 'center' | 'end' | 'justify';
|
|
11
|
+
|
|
12
|
+
const StartIcon = withDirection( AlignLeftIcon );
|
|
13
|
+
const EndIcon = withDirection( AlignRightIcon );
|
|
10
14
|
|
|
11
15
|
const options: ToggleButtonGroupItem< Alignments >[] = [
|
|
12
16
|
{
|
|
13
|
-
value: '
|
|
14
|
-
label: __( '
|
|
15
|
-
renderContent: (
|
|
17
|
+
value: 'start',
|
|
18
|
+
label: __( 'Start', 'elementor' ),
|
|
19
|
+
renderContent: () => <RotatedIcon icon={ StartIcon } size="tiny" />,
|
|
20
|
+
showTooltip: true,
|
|
16
21
|
},
|
|
17
22
|
{
|
|
18
23
|
value: 'center',
|
|
19
24
|
label: __( 'Center', 'elementor' ),
|
|
20
25
|
renderContent: ( { size } ) => <AlignCenterIcon fontSize={ size } />,
|
|
26
|
+
showTooltip: true,
|
|
21
27
|
},
|
|
22
28
|
{
|
|
23
|
-
value: '
|
|
24
|
-
label: __( '
|
|
25
|
-
renderContent: (
|
|
29
|
+
value: 'end',
|
|
30
|
+
label: __( 'End', 'elementor' ),
|
|
31
|
+
renderContent: () => <RotatedIcon icon={ EndIcon } size="tiny" />,
|
|
32
|
+
showTooltip: true,
|
|
26
33
|
},
|
|
27
34
|
{
|
|
28
35
|
value: 'justify',
|
|
29
36
|
label: __( 'Justify', 'elementor' ),
|
|
30
37
|
renderContent: ( { size } ) => <AlignJustifiedIcon fontSize={ size } />,
|
|
38
|
+
showTooltip: true,
|
|
31
39
|
},
|
|
32
40
|
];
|
|
33
41
|
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ControlLabel, type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-controls';
|
|
3
|
-
import { LetterCaseIcon, LetterCaseLowerIcon, LetterCaseUpperIcon } from '@elementor/icons';
|
|
3
|
+
import { LetterCaseIcon, LetterCaseLowerIcon, LetterCaseUpperIcon, MinusIcon } from '@elementor/icons';
|
|
4
4
|
import { Grid } from '@elementor/ui';
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
7
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
8
8
|
|
|
9
|
-
type Transforms = 'capitalize' | 'uppercase' | 'lowercase';
|
|
9
|
+
type Transforms = 'none' | 'capitalize' | 'uppercase' | 'lowercase';
|
|
10
10
|
|
|
11
11
|
const options: ToggleButtonGroupItem< Transforms >[] = [
|
|
12
|
+
{
|
|
13
|
+
value: 'none',
|
|
14
|
+
label: __( 'None', 'elementor' ),
|
|
15
|
+
renderContent: ( { size } ) => <MinusIcon fontSize={ size } />,
|
|
16
|
+
showTooltip: true,
|
|
17
|
+
},
|
|
12
18
|
{
|
|
13
19
|
value: 'capitalize',
|
|
14
20
|
label: __( 'Capitalize', 'elementor' ),
|
|
15
21
|
renderContent: ( { size } ) => <LetterCaseIcon fontSize={ size } />,
|
|
22
|
+
showTooltip: true,
|
|
16
23
|
},
|
|
17
24
|
{
|
|
18
25
|
value: 'uppercase',
|
|
19
26
|
label: __( 'Uppercase', 'elementor' ),
|
|
20
27
|
renderContent: ( { size } ) => <LetterCaseUpperIcon fontSize={ size } />,
|
|
28
|
+
showTooltip: true,
|
|
21
29
|
},
|
|
22
30
|
{
|
|
23
31
|
value: 'lowercase',
|
|
24
32
|
label: __( 'Lowercase', 'elementor' ),
|
|
25
33
|
renderContent: ( { size } ) => <LetterCaseLowerIcon fontSize={ size } />,
|
|
34
|
+
showTooltip: true,
|
|
26
35
|
},
|
|
27
36
|
];
|
|
28
37
|
|
|
@@ -30,7 +39,7 @@ export const TransformField = () => (
|
|
|
30
39
|
<StylesField bind={ 'text-transform' }>
|
|
31
40
|
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
32
41
|
<Grid item xs={ 6 }>
|
|
33
|
-
<ControlLabel>{ __( 'Transform', 'elementor' ) }</ControlLabel>
|
|
42
|
+
<ControlLabel>{ __( 'Text Transform', 'elementor' ) }</ControlLabel>
|
|
34
43
|
</Grid>
|
|
35
44
|
<Grid item xs={ 6 } display="flex" justifyContent="end">
|
|
36
45
|
<ToggleControl options={ options } />
|
|
@@ -11,7 +11,7 @@ import { __ } from '@wordpress/i18n';
|
|
|
11
11
|
import { ClassesPropProvider } from '../contexts/classes-prop-context';
|
|
12
12
|
import { useElement } from '../contexts/element-context';
|
|
13
13
|
import { StyleProvider } from '../contexts/style-context';
|
|
14
|
-
import { CssClassSelector } from './css-class-selector';
|
|
14
|
+
import { CssClassSelector } from './css-classes/css-class-selector';
|
|
15
15
|
import { Section } from './section';
|
|
16
16
|
import { SectionsList } from './sections-list';
|
|
17
17
|
import { BackgroundSection } from './style-sections/background-section/background-section';
|
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { createContext, type Dispatch, type PropsWithChildren, useContext } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type StyleDefinition,
|
|
5
|
+
type StyleDefinitionID,
|
|
6
|
+
type StyleDefinitionState,
|
|
7
|
+
type StyleDefinitionVariant,
|
|
8
|
+
} from '@elementor/editor-styles';
|
|
9
|
+
import { type StylesProvider, stylesRepository } from '@elementor/editor-styles-repository';
|
|
10
|
+
|
|
11
|
+
import { StylesProviderNotFoundError } from '../errors';
|
|
4
12
|
|
|
5
13
|
type ContextValue = {
|
|
6
|
-
id: StyleDefinition[ 'id' ] | null;
|
|
7
14
|
setId: Dispatch< StyleDefinition[ 'id' ] | null >;
|
|
8
15
|
meta: StyleDefinitionVariant[ 'meta' ];
|
|
9
16
|
setMetaState: Dispatch< StyleDefinitionState >;
|
|
17
|
+
} & ( ContextValueWithProvider | ContextValueWithoutProvider );
|
|
18
|
+
|
|
19
|
+
type ContextValueWithProvider = {
|
|
20
|
+
id: StyleDefinitionID;
|
|
21
|
+
provider: StylesProvider;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type ContextValueWithoutProvider = {
|
|
25
|
+
id: null;
|
|
26
|
+
provider: null;
|
|
10
27
|
};
|
|
11
28
|
|
|
12
29
|
const Context = createContext< ContextValue | null >( null );
|
|
13
30
|
|
|
14
|
-
type Props = PropsWithChildren< ContextValue >;
|
|
31
|
+
type Props = PropsWithChildren< Omit< ContextValue, 'provider' > >;
|
|
32
|
+
|
|
33
|
+
export function StyleProvider( { children, ...props }: Props ) {
|
|
34
|
+
const provider = props.id === null ? null : getProviderByStyleId( props.id );
|
|
15
35
|
|
|
16
|
-
|
|
17
|
-
|
|
36
|
+
if ( props.id && ! provider ) {
|
|
37
|
+
throw new StylesProviderNotFoundError( { context: { styleId: props.id } } );
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return <Context.Provider value={ { ...props, provider } as ContextValue }>{ children }</Context.Provider>;
|
|
18
41
|
}
|
|
19
42
|
|
|
20
43
|
export function useStyle() {
|
|
@@ -26,3 +49,11 @@ export function useStyle() {
|
|
|
26
49
|
|
|
27
50
|
return context;
|
|
28
51
|
}
|
|
52
|
+
|
|
53
|
+
function getProviderByStyleId( styleId: StyleDefinitionID ) {
|
|
54
|
+
const styleProvider = stylesRepository.getProviders().find( ( provider ) => {
|
|
55
|
+
return provider.actions.get().find( ( style ) => style.id === styleId );
|
|
56
|
+
} );
|
|
57
|
+
|
|
58
|
+
return styleProvider ?? null;
|
|
59
|
+
}
|
|
@@ -1,18 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { ComponentProps } from 'react';
|
|
3
|
-
import { createError } from '@elementor/utils';
|
|
4
3
|
|
|
4
|
+
import { ControlTypeNotFoundError } from '../errors';
|
|
5
5
|
import { type ControlType, type ControlTypes, getControlByType } from './controls-registry';
|
|
6
6
|
|
|
7
|
-
export type ControlTypeErrorContext = {
|
|
8
|
-
type: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const ControlTypeError = createError< ControlTypeErrorContext >( {
|
|
12
|
-
code: 'CONTROL_TYPE_NOT_FOUND',
|
|
13
|
-
message: `Control type not found.`,
|
|
14
|
-
} );
|
|
15
|
-
|
|
16
7
|
type IsRequired< T, K extends keyof T > = object extends Pick< T, K > ? false : true;
|
|
17
8
|
|
|
18
9
|
type AnyPropertyRequired< T > = {
|
|
@@ -35,8 +26,8 @@ export const Control = < T extends ControlType >( { props, type }: ControlProps<
|
|
|
35
26
|
const ControlByType = getControlByType( type );
|
|
36
27
|
|
|
37
28
|
if ( ! ControlByType ) {
|
|
38
|
-
throw new
|
|
39
|
-
context: { type },
|
|
29
|
+
throw new ControlTypeNotFoundError( {
|
|
30
|
+
context: { controlType: type },
|
|
40
31
|
} );
|
|
41
32
|
}
|
|
42
33
|
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
LinkControl,
|
|
5
5
|
SelectControl,
|
|
6
6
|
SizeControl,
|
|
7
|
+
SvgMediaControl,
|
|
7
8
|
TextAreaControl,
|
|
8
9
|
TextControl,
|
|
9
10
|
UrlControl,
|
|
@@ -15,7 +16,8 @@ type ControlRegistry = Record< string, { component: ControlComponent; layout: Co
|
|
|
15
16
|
|
|
16
17
|
const controlTypes = {
|
|
17
18
|
image: { component: ImageControl, layout: 'full' },
|
|
18
|
-
|
|
19
|
+
'svg-media': { component: SvgMediaControl, layout: 'full' },
|
|
20
|
+
text: { component: TextControl, layout: 'full' },
|
|
19
21
|
textarea: { component: TextAreaControl, layout: 'full' },
|
|
20
22
|
size: { component: SizeControl, layout: 'two-columns' },
|
|
21
23
|
select: { component: SelectControl, layout: 'two-columns' },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { PropKeyProvider, PropProvider } from '@elementor/editor-controls';
|
|
3
3
|
import { updateElementSettings, useElementSetting } from '@elementor/editor-elements';
|
|
4
|
-
import { type PropKey, type PropValue } from '@elementor/editor-props';
|
|
4
|
+
import { type LinkPropValue, type PropKey, type PropValue } from '@elementor/editor-props';
|
|
5
5
|
|
|
6
6
|
import { useElement } from '../contexts/element-context';
|
|
7
7
|
import { createTopLevelOjectType } from './create-top-level-object-type';
|
|
@@ -15,10 +15,17 @@ export const SettingsField = ( { bind, children }: Props ) => {
|
|
|
15
15
|
const { element, elementType } = useElement();
|
|
16
16
|
|
|
17
17
|
const settingsValue = useElementSetting< PropValue >( element.id, bind );
|
|
18
|
+
|
|
19
|
+
const linkValue = useElementSetting< PropValue >( element.id, 'link' ) as LinkPropValue;
|
|
20
|
+
|
|
18
21
|
const value = { [ bind ]: settingsValue };
|
|
19
22
|
|
|
20
23
|
const propType = createTopLevelOjectType( { schema: elementType.propsSchema } );
|
|
21
24
|
|
|
25
|
+
if ( bind === 'tag' && linkValue?.value && 'div-block' === elementType.key ) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
const setValue = ( newValue: Record< string, PropValue > ) => {
|
|
23
30
|
updateElementSettings( {
|
|
24
31
|
id: element.id,
|
|
@@ -6,7 +6,7 @@ import { createTopLevelOjectType } from '../controls-registry/create-top-level-o
|
|
|
6
6
|
import { useDynamicTag } from './hooks/use-dynamic-tag';
|
|
7
7
|
import { dynamicPropTypeUtil, type DynamicPropValue } from './utils';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
type DynamicControlProps = React.PropsWithChildren< {
|
|
10
10
|
bind: PropKey;
|
|
11
11
|
} >;
|
|
12
12
|
|
package/src/dynamics/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type ControlItem
|
|
2
|
-
import { type TransformablePropType, type TransformablePropValue } from '@elementor/editor-props';
|
|
1
|
+
import { type ControlItem } from '@elementor/editor-elements';
|
|
2
|
+
import { type PropsSchema, type TransformablePropType, type TransformablePropValue } from '@elementor/editor-props';
|
|
3
3
|
|
|
4
4
|
export type ExtendedWindow = Window & {
|
|
5
5
|
elementor?: {
|
package/src/dynamics/utils.ts
CHANGED
|
@@ -9,9 +9,9 @@ import { z } from '@elementor/schema';
|
|
|
9
9
|
|
|
10
10
|
import { type DynamicPropType } from './types';
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const DYNAMIC_PROP_TYPE_KEY = 'dynamic';
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const isDynamicPropType = ( prop: TransformablePropType ): prop is DynamicPropType =>
|
|
15
15
|
prop.key === DYNAMIC_PROP_TYPE_KEY;
|
|
16
16
|
|
|
17
17
|
export const getDynamicPropType = ( propType: PropType ): DynamicPropType | null => {
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type StyleDefinitionID } from '@elementor/editor-styles';
|
|
2
|
+
import { createError } from '@elementor/utils';
|
|
3
|
+
|
|
4
|
+
export const ControlTypeNotFoundError = createError< { controlType: string } >( {
|
|
5
|
+
code: 'control_type_not_found',
|
|
6
|
+
message: 'Control type not found.',
|
|
7
|
+
} );
|
|
8
|
+
|
|
9
|
+
export const StylesProviderNotFoundError = createError< { styleId: StyleDefinitionID } >( {
|
|
10
|
+
code: 'provider_not_found',
|
|
11
|
+
message: 'Styles provider not found.',
|
|
12
|
+
} );
|
|
13
|
+
|
|
14
|
+
export const StylesProviderCannotUpdatePropsError = createError< { providerKey: string } >( {
|
|
15
|
+
code: 'provider_cannot_update_props',
|
|
16
|
+
message: "Styles provider doesn't support updating props.",
|
|
17
|
+
} );
|
|
18
|
+
|
|
19
|
+
export const StyleNotFoundUnderProviderError = createError< { styleId: StyleDefinitionID; providerKey: string } >( {
|
|
20
|
+
code: 'style_not_found_under_provider',
|
|
21
|
+
message: 'Style not found under the provider.',
|
|
22
|
+
} );
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type PropValue } from '@elementor/editor-props';
|
|
2
|
+
import { useSessionStorage } from '@elementor/session';
|
|
2
3
|
|
|
3
4
|
import { useElement } from '../contexts/element-context';
|
|
4
5
|
import { type DynamicPropValue } from '../dynamics/types';
|
|
5
|
-
import { useSessionStorage } from './use-session-storage';
|
|
6
6
|
|
|
7
7
|
export const usePersistDynamicValue = < T extends DynamicPropValue | PropValue >( propKey: string ) => {
|
|
8
8
|
const { element } = useElement();
|
|
@@ -1,43 +1,185 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useMemo, useReducer } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
createElementStyle,
|
|
4
|
+
type CreateElementStyleArgs,
|
|
5
|
+
deleteElementStyle,
|
|
6
|
+
type ElementID,
|
|
7
|
+
getElementLabel,
|
|
8
|
+
} from '@elementor/editor-elements';
|
|
2
9
|
import type { Props } from '@elementor/editor-props';
|
|
10
|
+
import { getVariantByMeta, type StyleDefinition, type StyleDefinitionVariant } from '@elementor/editor-styles';
|
|
11
|
+
import { type StylesProvider } from '@elementor/editor-styles-repository';
|
|
12
|
+
import { LOCAL_STYLES_RESERVED_LABEL } from '@elementor/editor-styles-repository';
|
|
13
|
+
import { undoable } from '@elementor/editor-v1-adapters';
|
|
3
14
|
import { __ } from '@wordpress/i18n';
|
|
4
15
|
|
|
5
16
|
import { useClassesProp } from '../contexts/classes-prop-context';
|
|
6
17
|
import { useElement } from '../contexts/element-context';
|
|
7
18
|
import { useStyle } from '../contexts/style-context';
|
|
19
|
+
import { StyleNotFoundUnderProviderError, StylesProviderCannotUpdatePropsError } from '../errors';
|
|
8
20
|
|
|
9
21
|
export function useStylesFields< T extends Props >( propNames: ( keyof T & string )[] ) {
|
|
10
22
|
const { element } = useElement();
|
|
11
|
-
const { id, meta } = useStyle();
|
|
23
|
+
const { id, meta, provider } = useStyle();
|
|
12
24
|
const classesProp = useClassesProp();
|
|
13
25
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
const undoableUpdateStyle = useUndoableUpdateStyle();
|
|
27
|
+
const undoableCreateElementStyle = useUndoableCreateElementStyle();
|
|
28
|
+
|
|
29
|
+
const [ , reRender ] = useReducer( ( p ) => ! p, false );
|
|
30
|
+
|
|
31
|
+
useEffect( () => provider?.subscribe( reRender ), [ provider ] );
|
|
32
|
+
|
|
33
|
+
const value = getProps< T >( {
|
|
34
|
+
elementId: element.id,
|
|
35
|
+
styleId: id,
|
|
36
|
+
provider,
|
|
17
37
|
meta,
|
|
18
38
|
propNames,
|
|
19
39
|
} );
|
|
20
40
|
|
|
21
41
|
const setValue = ( props: T ) => {
|
|
22
42
|
if ( id === null ) {
|
|
23
|
-
|
|
43
|
+
undoableCreateElementStyle( {
|
|
24
44
|
elementId: element.id,
|
|
25
45
|
classesProp,
|
|
26
46
|
meta,
|
|
27
47
|
props,
|
|
28
|
-
label: __( 'local', 'elementor' ),
|
|
29
48
|
} );
|
|
30
49
|
|
|
31
50
|
return;
|
|
32
51
|
}
|
|
33
52
|
|
|
34
|
-
|
|
53
|
+
undoableUpdateStyle( {
|
|
35
54
|
elementId: element.id,
|
|
36
55
|
styleId: id,
|
|
37
|
-
|
|
56
|
+
provider,
|
|
38
57
|
meta,
|
|
58
|
+
props,
|
|
39
59
|
} );
|
|
40
60
|
};
|
|
41
61
|
|
|
42
62
|
return [ value, setValue ] as const;
|
|
43
63
|
}
|
|
64
|
+
|
|
65
|
+
type GetPropsArgs = {
|
|
66
|
+
provider: StylesProvider | null;
|
|
67
|
+
styleId: StyleDefinition[ 'id' ] | null;
|
|
68
|
+
elementId: ElementID;
|
|
69
|
+
meta: StyleDefinitionVariant[ 'meta' ];
|
|
70
|
+
propNames: string[];
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
type NullableValues< T extends Props > = {
|
|
74
|
+
[ K in keyof T ]: T[ K ] | null;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
function getProps< T extends Props >( { styleId, elementId, provider, meta, propNames }: GetPropsArgs ) {
|
|
78
|
+
if ( ! provider || ! styleId ) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const style = provider.actions.getById?.( styleId, { elementId } );
|
|
83
|
+
|
|
84
|
+
if ( ! style ) {
|
|
85
|
+
throw new StyleNotFoundUnderProviderError( { context: { styleId, providerKey: provider.key } } );
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const variant = getVariantByMeta( style, meta );
|
|
89
|
+
|
|
90
|
+
return Object.fromEntries(
|
|
91
|
+
propNames.map( ( key ) => [ key, variant?.props[ key ] ?? null ] )
|
|
92
|
+
) as NullableValues< T >;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
type UndoableCreateElementStyleArgs = Omit< CreateElementStyleArgs, 'label' >;
|
|
96
|
+
|
|
97
|
+
function useUndoableCreateElementStyle() {
|
|
98
|
+
return useMemo( () => {
|
|
99
|
+
return undoable(
|
|
100
|
+
{
|
|
101
|
+
do: ( payload: UndoableCreateElementStyleArgs ) => {
|
|
102
|
+
return createElementStyle( {
|
|
103
|
+
...payload,
|
|
104
|
+
label: LOCAL_STYLES_RESERVED_LABEL,
|
|
105
|
+
} );
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
undo: ( { elementId }, styleId ) => {
|
|
109
|
+
deleteElementStyle( elementId, styleId );
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
redo: ( payload, styleId ) => {
|
|
113
|
+
return createElementStyle( {
|
|
114
|
+
...payload,
|
|
115
|
+
styleId,
|
|
116
|
+
label: LOCAL_STYLES_RESERVED_LABEL,
|
|
117
|
+
} );
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
title: ( { elementId } ) => getElementLabel( elementId ),
|
|
122
|
+
subtitle: __( 'Style edited', 'elementor' ),
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
}, [] );
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
type UndoableUpdateStyleArgs = {
|
|
129
|
+
elementId: ElementID;
|
|
130
|
+
styleId: StyleDefinition[ 'id' ];
|
|
131
|
+
provider: StylesProvider;
|
|
132
|
+
meta: StyleDefinitionVariant[ 'meta' ];
|
|
133
|
+
props: Props;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
function useUndoableUpdateStyle() {
|
|
137
|
+
return useMemo( () => {
|
|
138
|
+
return undoable(
|
|
139
|
+
{
|
|
140
|
+
do: ( { elementId, styleId, provider, meta, props }: UndoableUpdateStyleArgs ) => {
|
|
141
|
+
if ( ! provider.actions.updateProps ) {
|
|
142
|
+
throw new StylesProviderCannotUpdatePropsError( {
|
|
143
|
+
context: { providerKey: provider.key },
|
|
144
|
+
} );
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const style = provider.actions.getById( styleId, { elementId } );
|
|
148
|
+
|
|
149
|
+
const prevProps = getCurrentProps( style, meta );
|
|
150
|
+
|
|
151
|
+
provider.actions.updateProps(
|
|
152
|
+
{
|
|
153
|
+
id: styleId,
|
|
154
|
+
meta,
|
|
155
|
+
props,
|
|
156
|
+
},
|
|
157
|
+
{ elementId }
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
return prevProps;
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
undo: ( { elementId, styleId, meta, provider }, prevProps ) => {
|
|
164
|
+
provider.actions.updateProps?.( { id: styleId, meta, props: prevProps }, { elementId } );
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
title: ( { elementId } ) => getElementLabel( elementId ),
|
|
169
|
+
subtitle: __( 'Style edited', 'elementor' ),
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
}, [] );
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getCurrentProps( style: StyleDefinition | null, meta: StyleDefinitionVariant[ 'meta' ] ) {
|
|
176
|
+
if ( ! style ) {
|
|
177
|
+
return {};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const variant = getVariantByMeta( style, meta );
|
|
181
|
+
|
|
182
|
+
const props = variant?.props ?? {};
|
|
183
|
+
|
|
184
|
+
return structuredClone( props );
|
|
185
|
+
}
|
|
@@ -3,9 +3,11 @@ import { type ClassesPropValue } from '@elementor/editor-props';
|
|
|
3
3
|
|
|
4
4
|
import { useClassesProp } from '../contexts/classes-prop-context';
|
|
5
5
|
import { useElement } from '../contexts/element-context';
|
|
6
|
+
import { useStyle } from '../contexts/style-context';
|
|
6
7
|
|
|
7
8
|
export const useUnapplyClass = ( classId: string ) => {
|
|
8
9
|
const { element } = useElement();
|
|
10
|
+
const { setId: setStyleId } = useStyle();
|
|
9
11
|
const classesProp = useClassesProp();
|
|
10
12
|
|
|
11
13
|
const classes = useElementSetting< ClassesPropValue >( element.id, classesProp );
|
|
@@ -21,5 +23,7 @@ export const useUnapplyClass = ( classId: string ) => {
|
|
|
21
23
|
},
|
|
22
24
|
},
|
|
23
25
|
} );
|
|
26
|
+
|
|
27
|
+
setStyleId( null );
|
|
24
28
|
};
|
|
25
29
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export { useBoundProp } from '@elementor/editor-controls';
|
|
2
2
|
export type { PopoverActionProps } from './popover-action';
|
|
3
3
|
export { replaceControl } from './control-replacement';
|
|
4
|
-
export {
|
|
5
|
-
export { injectIntoClassSelectorActions } from './components/css-class-selector';
|
|
4
|
+
export { injectIntoClassSelectorActions } from './components/css-classes/css-class-selector';
|
|
6
5
|
export { usePanelActions, usePanelStatus } from './panel';
|
|
7
6
|
|
|
8
7
|
import init from './init';
|
package/src/init.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { injectIntoLogic } from '@elementor/editor';
|
|
2
2
|
import { __registerPanel as registerPanel } from '@elementor/editor-panels';
|
|
3
|
-
import {
|
|
3
|
+
import { blockCommand } from '@elementor/editor-v1-adapters';
|
|
4
4
|
|
|
5
5
|
import { EditingPanelHooks } from './components/editing-panel-hooks';
|
|
6
|
-
import { initCssClasses } from './css-classes';
|
|
7
6
|
import { init as initDynamics } from './dynamics/init';
|
|
8
7
|
import { panel } from './panel';
|
|
9
8
|
import { isAtomicWidgetSelected } from './sync/is-atomic-widget-selected';
|
|
@@ -19,11 +18,10 @@ export default function init() {
|
|
|
19
18
|
|
|
20
19
|
// TODO: Move it from here once we have dynamic package.
|
|
21
20
|
initDynamics();
|
|
22
|
-
initCssClasses();
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
const blockV1Panel = () => {
|
|
26
|
-
|
|
24
|
+
blockCommand( {
|
|
27
25
|
command: 'panel/editor/open',
|
|
28
26
|
condition: isAtomicWidgetSelected,
|
|
29
27
|
} );
|
package/src/sync/types.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { type ControlItem, type
|
|
1
|
+
import { type ControlItem, type V1Element } from '@elementor/editor-elements';
|
|
2
|
+
import { type PropsSchema } from '@elementor/editor-props';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
type SupportedFonts = 'system' | 'googlefonts' | 'customfonts';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
type EnqueueFont = ( fontFamily: string, context?: 'preview' | 'editor' ) => void;
|
|
6
7
|
|
|
7
8
|
export type ExtendedWindow = Window & {
|
|
8
9
|
elementor?: {
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { useState } from 'react';
|
|
3
|
-
import { MinusIcon, PlusIcon } from '@elementor/icons';
|
|
4
|
-
import { Collapse, IconButton, Stack } from '@elementor/ui';
|
|
5
|
-
import { __ } from '@wordpress/i18n';
|
|
6
|
-
|
|
7
|
-
type CollapsibleFieldProps = React.PropsWithChildren< {
|
|
8
|
-
label: React.ReactNode;
|
|
9
|
-
defaultOpen?: boolean;
|
|
10
|
-
} >;
|
|
11
|
-
|
|
12
|
-
export const CollapsibleField = ( { label, children, defaultOpen = false }: CollapsibleFieldProps ) => {
|
|
13
|
-
const [ open, setOpen ] = useState( defaultOpen );
|
|
14
|
-
|
|
15
|
-
const handleToggle = () => {
|
|
16
|
-
setOpen( ( prevOpen ) => ! prevOpen );
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<Stack gap={ 1.5 }>
|
|
21
|
-
<Stack direction="row" justifyContent="space-between" alignItems="center" sx={ { py: 0.5 } }>
|
|
22
|
-
{ label }
|
|
23
|
-
<IconButton
|
|
24
|
-
onClick={ handleToggle }
|
|
25
|
-
size="tiny"
|
|
26
|
-
aria-label={ open ? __( 'Close', 'elementor' ) : __( 'Expand', 'elementor' ) }
|
|
27
|
-
>
|
|
28
|
-
{ open ? <MinusIcon fontSize="tiny" /> : <PlusIcon fontSize="tiny" /> }
|
|
29
|
-
</IconButton>
|
|
30
|
-
</Stack>
|
|
31
|
-
<Collapse in={ open } unmountOnExit>
|
|
32
|
-
{ children }
|
|
33
|
-
</Collapse>
|
|
34
|
-
</Stack>
|
|
35
|
-
);
|
|
36
|
-
};
|