@elementor/editor-editing-panel 1.44.0 → 1.46.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 +62 -0
- package/dist/index.d.mts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +867 -765
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +740 -636
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -13
- package/src/components/css-classes/css-class-menu.tsx +6 -8
- package/src/components/css-classes/css-class-selector.tsx +17 -11
- package/src/components/settings-tab.tsx +25 -2
- package/src/components/style-indicator.tsx +19 -15
- package/src/components/style-sections/border-section/border-field.tsx +4 -6
- package/src/components/style-sections/border-section/border-radius-field.tsx +12 -9
- package/src/components/style-sections/effects-section/effects-section.tsx +6 -0
- package/src/components/style-sections/layout-section/align-content-field.tsx +10 -14
- package/src/components/style-sections/layout-section/align-items-field.tsx +13 -17
- package/src/components/style-sections/layout-section/align-self-child-field.tsx +13 -17
- package/src/components/style-sections/layout-section/flex-direction-field.tsx +13 -17
- package/src/components/style-sections/layout-section/flex-order-field.tsx +31 -36
- package/src/components/style-sections/layout-section/flex-size-field.tsx +67 -69
- package/src/components/style-sections/layout-section/justify-content-field.tsx +10 -14
- package/src/components/style-sections/layout-section/layout-section.tsx +2 -2
- package/src/components/style-sections/layout-section/opacity-control-field.tsx +25 -0
- package/src/components/style-sections/layout-section/utils/rotated-icon.tsx +1 -1
- package/src/components/style-sections/layout-section/wrap-field.tsx +13 -17
- package/src/components/style-sections/position-section/dimensions-field.tsx +39 -21
- package/src/components/style-sections/position-section/offset-field.tsx +5 -2
- package/src/components/style-sections/position-section/position-section.tsx +6 -6
- package/src/components/style-sections/size-section/object-position-field.tsx +2 -24
- package/src/components/style-sections/size-section/size-section.tsx +52 -37
- package/src/components/style-sections/spacing-section/spacing-section.tsx +1 -1
- package/src/components/style-sections/typography-section/column-gap-field.tsx +5 -2
- package/src/components/style-sections/typography-section/font-size-field.tsx +5 -2
- package/src/components/style-sections/typography-section/letter-spacing-field.tsx +5 -2
- package/src/components/style-sections/typography-section/line-height-field.tsx +5 -2
- package/src/components/style-sections/typography-section/text-alignment-field.tsx +12 -9
- package/src/components/style-sections/typography-section/text-stroke-field.tsx +4 -6
- package/src/components/style-sections/typography-section/typography-section.tsx +4 -2
- package/src/components/style-sections/typography-section/word-spacing-field.tsx +5 -2
- package/src/controls-registry/controls-registry.tsx +30 -10
- package/src/controls-registry/styles-field.tsx +1 -3
- package/src/dynamics/components/background-control-dynamic-tag.tsx +48 -0
- package/src/dynamics/components/dynamic-selection-control.tsx +10 -18
- package/src/dynamics/components/dynamic-selection.tsx +58 -77
- package/src/dynamics/hooks/use-prop-dynamic-action.tsx +1 -1
- package/src/dynamics/init.ts +21 -0
- package/src/hooks/use-styles-field.ts +9 -3
- package/src/hooks/use-styles-fields.ts +4 -4
- package/src/index.ts +1 -0
- package/src/popover-action.tsx +3 -5
- package/src/provider-colors-registry.ts +20 -0
- package/src/styles-inheritance/components/infotip/label-chip.tsx +4 -5
- package/src/styles-inheritance/components/styles-inheritance-indicator.tsx +32 -40
- package/src/styles-inheritance/components/styles-inheritance-infotip.tsx +1 -5
- package/src/styles-inheritance/components/styles-inheritance-section-indicators.tsx +29 -44
- package/src/styles-inheritance/components/ui-providers.tsx +18 -0
- package/src/styles-inheritance/hooks/use-normalized-inheritance-chain-items.tsx +1 -17
- package/src/styles-inheritance/types.ts +0 -2
- package/src/styles-inheritance/utils.ts +17 -1
- package/src/utils/get-styles-provider-color.ts +28 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { SizeControl } from '@elementor/editor-controls';
|
|
3
4
|
import { Grid } from '@elementor/ui';
|
|
4
5
|
import { __ } from '@wordpress/i18n';
|
|
@@ -7,14 +8,16 @@ import { StylesField } from '../../../controls-registry/styles-field';
|
|
|
7
8
|
import { ControlLabel } from '../../control-label';
|
|
8
9
|
|
|
9
10
|
export const ColumnGapField = () => {
|
|
11
|
+
const rowRef: MutableRefObject< HTMLElement | undefined > = useRef();
|
|
12
|
+
|
|
10
13
|
return (
|
|
11
14
|
<StylesField bind="column-gap">
|
|
12
|
-
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
15
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={ rowRef }>
|
|
13
16
|
<Grid item xs={ 6 }>
|
|
14
17
|
<ControlLabel>{ __( 'Column gap', 'elementor' ) }</ControlLabel>
|
|
15
18
|
</Grid>
|
|
16
19
|
<Grid item xs={ 6 }>
|
|
17
|
-
<SizeControl />
|
|
20
|
+
<SizeControl anchorRef={ rowRef } />
|
|
18
21
|
</Grid>
|
|
19
22
|
</Grid>
|
|
20
23
|
</StylesField>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { SizeControl } from '@elementor/editor-controls';
|
|
3
4
|
import { Grid } from '@elementor/ui';
|
|
4
5
|
import { __ } from '@wordpress/i18n';
|
|
@@ -7,14 +8,16 @@ import { StylesField } from '../../../controls-registry/styles-field';
|
|
|
7
8
|
import { ControlLabel } from '../../control-label';
|
|
8
9
|
|
|
9
10
|
export const FontSizeField = () => {
|
|
11
|
+
const rowRef: MutableRefObject< HTMLElement | undefined > = useRef();
|
|
12
|
+
|
|
10
13
|
return (
|
|
11
14
|
<StylesField bind="font-size">
|
|
12
|
-
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
15
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={ rowRef }>
|
|
13
16
|
<Grid item xs={ 6 }>
|
|
14
17
|
<ControlLabel>{ __( 'Font size', 'elementor' ) }</ControlLabel>
|
|
15
18
|
</Grid>
|
|
16
19
|
<Grid item xs={ 6 }>
|
|
17
|
-
<SizeControl />
|
|
20
|
+
<SizeControl anchorRef={ rowRef } />
|
|
18
21
|
</Grid>
|
|
19
22
|
</Grid>
|
|
20
23
|
</StylesField>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { SizeControl } from '@elementor/editor-controls';
|
|
3
4
|
import { Grid } from '@elementor/ui';
|
|
4
5
|
import { __ } from '@wordpress/i18n';
|
|
@@ -7,14 +8,16 @@ import { StylesField } from '../../../controls-registry/styles-field';
|
|
|
7
8
|
import { ControlLabel } from '../../control-label';
|
|
8
9
|
|
|
9
10
|
export const LetterSpacingField = () => {
|
|
11
|
+
const rowRef: MutableRefObject< HTMLElement | undefined > = useRef();
|
|
12
|
+
|
|
10
13
|
return (
|
|
11
14
|
<StylesField bind="letter-spacing">
|
|
12
|
-
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
15
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={ rowRef }>
|
|
13
16
|
<Grid item xs={ 6 }>
|
|
14
17
|
<ControlLabel>{ __( 'Letter spacing', 'elementor' ) }</ControlLabel>
|
|
15
18
|
</Grid>
|
|
16
19
|
<Grid item xs={ 6 }>
|
|
17
|
-
<SizeControl />
|
|
20
|
+
<SizeControl anchorRef={ rowRef } />
|
|
18
21
|
</Grid>
|
|
19
22
|
</Grid>
|
|
20
23
|
</StylesField>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { SizeControl } from '@elementor/editor-controls';
|
|
3
4
|
import { Grid } from '@elementor/ui';
|
|
4
5
|
import { __ } from '@wordpress/i18n';
|
|
@@ -7,14 +8,16 @@ import { StylesField } from '../../../controls-registry/styles-field';
|
|
|
7
8
|
import { ControlLabel } from '../../control-label';
|
|
8
9
|
|
|
9
10
|
export const LineHeightField = () => {
|
|
11
|
+
const rowRef: MutableRefObject< HTMLElement | undefined > = useRef();
|
|
12
|
+
|
|
10
13
|
return (
|
|
11
14
|
<StylesField bind="line-height">
|
|
12
|
-
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
15
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={ rowRef }>
|
|
13
16
|
<Grid item xs={ 6 }>
|
|
14
17
|
<ControlLabel>{ __( 'Line height', 'elementor' ) }</ControlLabel>
|
|
15
18
|
</Grid>
|
|
16
19
|
<Grid item xs={ 6 }>
|
|
17
|
-
<SizeControl />
|
|
20
|
+
<SizeControl anchorRef={ rowRef } />
|
|
18
21
|
</Grid>
|
|
19
22
|
</Grid>
|
|
20
23
|
</StylesField>
|
|
@@ -5,6 +5,7 @@ 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 { UiProviders } from '../../../styles-inheritance/components/ui-providers';
|
|
8
9
|
import { ControlLabel } from '../../control-label';
|
|
9
10
|
|
|
10
11
|
type Alignments = 'start' | 'center' | 'end' | 'justify';
|
|
@@ -41,15 +42,17 @@ const options: ToggleButtonGroupItem< Alignments >[] = [
|
|
|
41
42
|
|
|
42
43
|
export const TextAlignmentField = () => {
|
|
43
44
|
return (
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
<Grid
|
|
47
|
-
<
|
|
45
|
+
<UiProviders>
|
|
46
|
+
<StylesField bind={ 'text-align' }>
|
|
47
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
48
|
+
<Grid item xs={ 6 }>
|
|
49
|
+
<ControlLabel>{ __( 'Text align', 'elementor' ) }</ControlLabel>
|
|
50
|
+
</Grid>
|
|
51
|
+
<Grid item xs={ 6 } display="flex" justifyContent="end">
|
|
52
|
+
<ToggleControl options={ options } />
|
|
53
|
+
</Grid>
|
|
48
54
|
</Grid>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
</Grid>
|
|
52
|
-
</Grid>
|
|
53
|
-
</StylesField>
|
|
55
|
+
</StylesField>
|
|
56
|
+
</UiProviders>
|
|
54
57
|
);
|
|
55
58
|
};
|
|
@@ -2,7 +2,6 @@ import * as React from 'react';
|
|
|
2
2
|
import { StrokeControl } from '@elementor/editor-controls';
|
|
3
3
|
import { __ } from '@wordpress/i18n';
|
|
4
4
|
|
|
5
|
-
import { useStyle } from '../../../contexts/style-context';
|
|
6
5
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
7
6
|
import { useStylesField } from '../../../hooks/use-styles-field';
|
|
8
7
|
import { AddOrRemoveContent } from '../../add-or-remove-content';
|
|
@@ -26,18 +25,17 @@ const initTextStroke = {
|
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
export const TextStrokeField = () => {
|
|
29
|
-
const { canEdit } =
|
|
30
|
-
const [ textStroke, setTextStroke ] = useStylesField( 'stroke' );
|
|
28
|
+
const { value, setValue, canEdit } = useStylesField( 'stroke' );
|
|
31
29
|
|
|
32
30
|
const addTextStroke = () => {
|
|
33
|
-
|
|
31
|
+
setValue( initTextStroke );
|
|
34
32
|
};
|
|
35
33
|
|
|
36
34
|
const removeTextStroke = () => {
|
|
37
|
-
|
|
35
|
+
setValue( null );
|
|
38
36
|
};
|
|
39
37
|
|
|
40
|
-
const hasTextStroke = Boolean(
|
|
38
|
+
const hasTextStroke = Boolean( value );
|
|
41
39
|
|
|
42
40
|
return (
|
|
43
41
|
<StylesField bind={ 'stroke' }>
|
|
@@ -23,9 +23,11 @@ import { TransformField } from './transform-field';
|
|
|
23
23
|
import { WordSpacingField } from './word-spacing-field';
|
|
24
24
|
|
|
25
25
|
export const TypographySection = () => {
|
|
26
|
-
const
|
|
27
|
-
const isVersion330Active = isExperimentActive( 'e_v_3_30' );
|
|
26
|
+
const { value: columnCount } = useStylesField< NumberPropValue >( 'column-count' );
|
|
28
27
|
const hasMultiColumns = !! ( columnCount?.value && columnCount?.value > 1 );
|
|
28
|
+
|
|
29
|
+
const isVersion330Active = isExperimentActive( 'e_v_3_30' );
|
|
30
|
+
|
|
29
31
|
return (
|
|
30
32
|
<SectionContent>
|
|
31
33
|
<FontFamilyField />
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type MutableRefObject, useRef } from 'react';
|
|
2
3
|
import { SizeControl } from '@elementor/editor-controls';
|
|
3
4
|
import { Grid } from '@elementor/ui';
|
|
4
5
|
import { __ } from '@wordpress/i18n';
|
|
@@ -7,14 +8,16 @@ import { StylesField } from '../../../controls-registry/styles-field';
|
|
|
7
8
|
import { ControlLabel } from '../../control-label';
|
|
8
9
|
|
|
9
10
|
export const WordSpacingField = () => {
|
|
11
|
+
const rowRef: MutableRefObject< HTMLElement | undefined > = useRef();
|
|
12
|
+
|
|
10
13
|
return (
|
|
11
14
|
<StylesField bind="word-spacing">
|
|
12
|
-
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
15
|
+
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap" ref={ rowRef }>
|
|
13
16
|
<Grid item xs={ 6 }>
|
|
14
17
|
<ControlLabel>{ __( 'Word spacing', 'elementor' ) }</ControlLabel>
|
|
15
18
|
</Grid>
|
|
16
19
|
<Grid item xs={ 6 }>
|
|
17
|
-
<SizeControl />
|
|
20
|
+
<SizeControl anchorRef={ rowRef } />
|
|
18
21
|
</Grid>
|
|
19
22
|
</Grid>
|
|
20
23
|
</StylesField>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ControlComponent,
|
|
3
3
|
ImageControl,
|
|
4
|
+
KeyValueControl,
|
|
4
5
|
LinkControl,
|
|
6
|
+
RepeatableControl,
|
|
5
7
|
SelectControl,
|
|
6
8
|
SizeControl,
|
|
7
9
|
SvgMediaControl,
|
|
@@ -11,19 +13,35 @@ import {
|
|
|
11
13
|
UrlControl,
|
|
12
14
|
} from '@elementor/editor-controls';
|
|
13
15
|
import { type ControlLayout } from '@elementor/editor-elements';
|
|
16
|
+
import {
|
|
17
|
+
booleanPropTypeUtil,
|
|
18
|
+
imagePropTypeUtil,
|
|
19
|
+
imageSrcPropTypeUtil,
|
|
20
|
+
keyValuePropTypeUtil,
|
|
21
|
+
linkPropTypeUtil,
|
|
22
|
+
type PropTypeUtil,
|
|
23
|
+
sizePropTypeUtil,
|
|
24
|
+
stringPropTypeUtil,
|
|
25
|
+
} from '@elementor/editor-props';
|
|
14
26
|
|
|
15
|
-
type ControlRegistry = Record<
|
|
27
|
+
type ControlRegistry = Record<
|
|
28
|
+
string,
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
{ component: ControlComponent; layout: ControlLayout; propTypeUtil?: PropTypeUtil< string, any > }
|
|
31
|
+
>;
|
|
16
32
|
|
|
17
33
|
const controlTypes = {
|
|
18
|
-
image: { component: ImageControl, layout: 'full' },
|
|
19
|
-
'svg-media': { component: SvgMediaControl, layout: 'full' },
|
|
20
|
-
text: { component: TextControl, layout: 'full' },
|
|
21
|
-
textarea: { component: TextAreaControl, layout: 'full' },
|
|
22
|
-
size: { component: SizeControl, layout: 'two-columns' },
|
|
23
|
-
select: { component: SelectControl, layout: 'two-columns' },
|
|
24
|
-
link: { component: LinkControl, layout: 'full' },
|
|
25
|
-
url: { component: UrlControl, layout: 'full' },
|
|
26
|
-
switch: { component: SwitchControl, layout: 'two-columns' },
|
|
34
|
+
image: { component: ImageControl, layout: 'full', propTypeUtil: imagePropTypeUtil },
|
|
35
|
+
'svg-media': { component: SvgMediaControl, layout: 'full', propTypeUtil: imageSrcPropTypeUtil },
|
|
36
|
+
text: { component: TextControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
37
|
+
textarea: { component: TextAreaControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
38
|
+
size: { component: SizeControl, layout: 'two-columns', propTypeUtil: sizePropTypeUtil },
|
|
39
|
+
select: { component: SelectControl, layout: 'two-columns', propTypeUtil: stringPropTypeUtil },
|
|
40
|
+
link: { component: LinkControl, layout: 'full', propTypeUtil: linkPropTypeUtil },
|
|
41
|
+
url: { component: UrlControl, layout: 'full', propTypeUtil: stringPropTypeUtil },
|
|
42
|
+
switch: { component: SwitchControl, layout: 'two-columns', propTypeUtil: booleanPropTypeUtil },
|
|
43
|
+
repeatable: { component: RepeatableControl, layout: 'full', propTypeUtil: undefined },
|
|
44
|
+
'key-value': { component: KeyValueControl, layout: 'full', propTypeUtil: keyValuePropTypeUtil },
|
|
27
45
|
} as const satisfies ControlRegistry;
|
|
28
46
|
|
|
29
47
|
export type ControlType = keyof typeof controlTypes;
|
|
@@ -35,3 +53,5 @@ export type ControlTypes = {
|
|
|
35
53
|
export const getControl = ( type: ControlType ) => controlTypes[ type ]?.component;
|
|
36
54
|
|
|
37
55
|
export const getDefaultLayout = ( type: ControlType ) => controlTypes[ type ].layout;
|
|
56
|
+
|
|
57
|
+
export const getPropTypeUtil = ( type: ControlType ) => controlTypes[ type ]?.propTypeUtil;
|
|
@@ -3,7 +3,6 @@ import { ControlAdornmentsProvider, PropKeyProvider, PropProvider } from '@eleme
|
|
|
3
3
|
import { type PropKey, type PropValue } from '@elementor/editor-props';
|
|
4
4
|
import { getStylesSchema } from '@elementor/editor-styles';
|
|
5
5
|
|
|
6
|
-
import { useStyle } from '../contexts/style-context';
|
|
7
6
|
import { useStylesField } from '../hooks/use-styles-field';
|
|
8
7
|
import { StylesInheritanceIndicator } from '../styles-inheritance/components/styles-inheritance-indicator';
|
|
9
8
|
import { createTopLevelOjectType } from './create-top-level-object-type';
|
|
@@ -15,8 +14,7 @@ export type StylesFieldProps = {
|
|
|
15
14
|
};
|
|
16
15
|
|
|
17
16
|
export const StylesField = ( { bind, placeholder, children }: StylesFieldProps ) => {
|
|
18
|
-
const
|
|
19
|
-
const { canEdit } = useStyle();
|
|
17
|
+
const { value, setValue, canEdit } = useStylesField( bind );
|
|
20
18
|
|
|
21
19
|
const stylesSchema = getStylesSchema();
|
|
22
20
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { PropKeyProvider, PropProvider, useBoundProp } from '@elementor/editor-controls';
|
|
3
|
+
import {
|
|
4
|
+
backgroundImageOverlayPropTypeUtil,
|
|
5
|
+
type BackgroundOverlayImagePropType,
|
|
6
|
+
type BackgroundOverlayPropType,
|
|
7
|
+
type ObjectPropType,
|
|
8
|
+
type UnionPropType,
|
|
9
|
+
} from '@elementor/editor-props';
|
|
10
|
+
import { DatabaseIcon } from '@elementor/icons';
|
|
11
|
+
|
|
12
|
+
import { useDynamicTag } from '../hooks/use-dynamic-tag';
|
|
13
|
+
|
|
14
|
+
// Since this is injected, the initial prop provider does not dig into the nested structure of the value.
|
|
15
|
+
// We need to synthetically create a type that matches the expected structure of the value.
|
|
16
|
+
|
|
17
|
+
export const BackgroundControlDynamicTagIcon = () => <DatabaseIcon fontSize="tiny" />;
|
|
18
|
+
|
|
19
|
+
export const BackgroundControlDynamicTagLabel = ( { value }: { value: BackgroundOverlayPropType } ) => {
|
|
20
|
+
const context = useBoundProp( backgroundImageOverlayPropTypeUtil );
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<PropProvider { ...context } value={ value.value }>
|
|
24
|
+
<PropKeyProvider bind="image">
|
|
25
|
+
<Wrapper rawValue={ value.value } />
|
|
26
|
+
</PropKeyProvider>
|
|
27
|
+
</PropProvider>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const Wrapper = ( { rawValue }: { rawValue: BackgroundOverlayPropType[ 'value' ] } ) => {
|
|
32
|
+
const { propType } = useBoundProp< BackgroundOverlayPropType, UnionPropType >();
|
|
33
|
+
|
|
34
|
+
const imageOverlayPropType = propType.prop_types[ 'background-image-overlay' ] as ObjectPropType;
|
|
35
|
+
return (
|
|
36
|
+
<PropProvider propType={ imageOverlayPropType.shape.image } value={ rawValue } setValue={ () => void 0 }>
|
|
37
|
+
<PropKeyProvider bind="src">
|
|
38
|
+
<Content rawValue={ rawValue.image } />
|
|
39
|
+
</PropKeyProvider>
|
|
40
|
+
</PropProvider>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const Content = ( { rawValue }: { rawValue: BackgroundOverlayImagePropType } ) => {
|
|
45
|
+
const src = rawValue.value.src;
|
|
46
|
+
const dynamicTag = useDynamicTag( src.value.name || '' );
|
|
47
|
+
return <React.Fragment>{ dynamicTag?.label }</React.Fragment>;
|
|
48
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ControlFormLabel, useBoundProp } from '@elementor/editor-controls';
|
|
3
3
|
import type { Control, ControlsSection } from '@elementor/editor-elements';
|
|
4
|
-
import { PopoverHeader } from '@elementor/editor-ui';
|
|
4
|
+
import { PopoverHeader, PopoverScrollableContent } from '@elementor/editor-ui';
|
|
5
5
|
import { DatabaseIcon, SettingsIcon, XIcon } from '@elementor/icons';
|
|
6
6
|
import {
|
|
7
7
|
bindPopover,
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
Divider,
|
|
11
11
|
Grid,
|
|
12
12
|
IconButton,
|
|
13
|
-
Paper,
|
|
14
13
|
Popover,
|
|
15
14
|
Stack,
|
|
16
15
|
Tab,
|
|
@@ -81,12 +80,7 @@ export const DynamicSelectionControl = () => {
|
|
|
81
80
|
{ ...bindPopover( selectionPopoverState ) }
|
|
82
81
|
>
|
|
83
82
|
<Stack>
|
|
84
|
-
<
|
|
85
|
-
title={ __( 'Dynamic tags', 'elementor' ) }
|
|
86
|
-
onClose={ selectionPopoverState.close }
|
|
87
|
-
icon={ <DatabaseIcon fontSize={ SIZE } /> }
|
|
88
|
-
/>
|
|
89
|
-
<DynamicSelection onSelect={ selectionPopoverState.close } />
|
|
83
|
+
<DynamicSelection close={ selectionPopoverState.close } />
|
|
90
84
|
</Stack>
|
|
91
85
|
</Popover>
|
|
92
86
|
</Box>
|
|
@@ -113,14 +107,12 @@ export const DynamicSettingsPopover = ( { dynamicTag }: { dynamicTag: DynamicTag
|
|
|
113
107
|
anchorOrigin={ { vertical: 'bottom', horizontal: 'center' } }
|
|
114
108
|
{ ...bindPopover( popupState ) }
|
|
115
109
|
>
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
<DynamicSettings controls={ dynamicTag.atomic_controls } />
|
|
123
|
-
</Paper>
|
|
110
|
+
<PopoverHeader
|
|
111
|
+
title={ dynamicTag.label }
|
|
112
|
+
onClose={ popupState.close }
|
|
113
|
+
icon={ <DatabaseIcon fontSize={ SIZE } /> }
|
|
114
|
+
/>
|
|
115
|
+
<DynamicSettings controls={ dynamicTag.atomic_controls } />
|
|
124
116
|
</Popover>
|
|
125
117
|
</>
|
|
126
118
|
);
|
|
@@ -136,7 +128,7 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
|
|
|
136
128
|
}
|
|
137
129
|
|
|
138
130
|
return (
|
|
139
|
-
|
|
131
|
+
<PopoverScrollableContent>
|
|
140
132
|
<Tabs size="small" variant="fullWidth" { ...getTabsProps() }>
|
|
141
133
|
{ tabs.map( ( { value }, index ) => (
|
|
142
134
|
<Tab key={ index } label={ value.label } sx={ { px: 1, py: 0.5 } } { ...getTabProps( index ) } />
|
|
@@ -158,7 +150,7 @@ const DynamicSettings = ( { controls }: { controls: DynamicTag[ 'atomic_controls
|
|
|
158
150
|
</TabPanel>
|
|
159
151
|
);
|
|
160
152
|
} ) }
|
|
161
|
-
|
|
153
|
+
</PopoverScrollableContent>
|
|
162
154
|
);
|
|
163
155
|
};
|
|
164
156
|
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
1
|
import { Fragment, useState } from 'react';
|
|
2
|
+
import * as React from 'react';
|
|
3
3
|
import { useBoundProp } from '@elementor/editor-controls';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
Divider,
|
|
8
|
-
InputAdornment,
|
|
9
|
-
Link,
|
|
10
|
-
MenuItem,
|
|
11
|
-
MenuList,
|
|
12
|
-
MenuSubheader,
|
|
13
|
-
Stack,
|
|
14
|
-
TextField,
|
|
15
|
-
Typography,
|
|
16
|
-
} from '@elementor/ui';
|
|
4
|
+
import { PopoverHeader, PopoverMenuList, PopoverSearch } from '@elementor/editor-ui';
|
|
5
|
+
import { DatabaseIcon } from '@elementor/icons';
|
|
6
|
+
import { Box, Divider, Link, Stack, Typography, useTheme } from '@elementor/ui';
|
|
17
7
|
import { __ } from '@wordpress/i18n';
|
|
18
8
|
|
|
19
9
|
import { usePersistDynamicValue } from '../../hooks/use-persist-dynamic-value';
|
|
@@ -31,7 +21,7 @@ type OptionEntry = [ string, Option[] ];
|
|
|
31
21
|
const SIZE = 'tiny';
|
|
32
22
|
|
|
33
23
|
type DynamicSelectionProps = {
|
|
34
|
-
|
|
24
|
+
close: () => void;
|
|
35
25
|
};
|
|
36
26
|
|
|
37
27
|
type NoResultsProps = {
|
|
@@ -39,9 +29,10 @@ type NoResultsProps = {
|
|
|
39
29
|
onClear?: () => void;
|
|
40
30
|
};
|
|
41
31
|
|
|
42
|
-
export const DynamicSelection = ( {
|
|
32
|
+
export const DynamicSelection = ( { close: closePopover }: DynamicSelectionProps ) => {
|
|
43
33
|
const [ searchValue, setSearchValue ] = useState( '' );
|
|
44
34
|
const { groups: dynamicGroups } = getAtomicDynamicTags() || {};
|
|
35
|
+
const theme = useTheme();
|
|
45
36
|
|
|
46
37
|
const { value: anyValue } = useBoundProp();
|
|
47
38
|
const { bind, value: dynamicValue, setValue } = useBoundProp( dynamicPropTypeUtil );
|
|
@@ -54,79 +45,69 @@ export const DynamicSelection = ( { onSelect }: DynamicSelectionProps ) => {
|
|
|
54
45
|
|
|
55
46
|
const hasNoDynamicTags = ! options.length && ! searchValue.trim();
|
|
56
47
|
|
|
57
|
-
const handleSearch = (
|
|
58
|
-
setSearchValue(
|
|
48
|
+
const handleSearch = ( value: string ) => {
|
|
49
|
+
setSearchValue( value );
|
|
59
50
|
};
|
|
60
51
|
|
|
61
|
-
const handleSetDynamicTag = ( value: string
|
|
52
|
+
const handleSetDynamicTag = ( value: string ) => {
|
|
62
53
|
if ( ! isCurrentValueDynamic ) {
|
|
63
54
|
updatePropValueHistory( anyValue );
|
|
64
55
|
}
|
|
65
56
|
|
|
66
|
-
|
|
57
|
+
const selectedOption = options.flatMap( ( [ , items ] ) => items ).find( ( item ) => item.value === value );
|
|
58
|
+
|
|
59
|
+
setValue( { name: value, settings: { label: selectedOption?.label } } );
|
|
67
60
|
|
|
68
|
-
|
|
61
|
+
closePopover();
|
|
69
62
|
};
|
|
70
63
|
|
|
64
|
+
const virtualizedItems = options.flatMap( ( [ category, items ] ) => [
|
|
65
|
+
{
|
|
66
|
+
type: 'category' as const,
|
|
67
|
+
value: category,
|
|
68
|
+
label: dynamicGroups?.[ category ]?.title || category,
|
|
69
|
+
},
|
|
70
|
+
...items.map( ( item ) => ( {
|
|
71
|
+
type: 'item' as const,
|
|
72
|
+
value: item.value,
|
|
73
|
+
label: item.label,
|
|
74
|
+
} ) ),
|
|
75
|
+
] );
|
|
76
|
+
|
|
71
77
|
return (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
<>
|
|
79
|
+
<PopoverHeader
|
|
80
|
+
title={ __( 'Dynamic tags', 'elementor' ) }
|
|
81
|
+
onClose={ closePopover }
|
|
82
|
+
icon={ <DatabaseIcon fontSize={ SIZE } /> }
|
|
83
|
+
/>
|
|
84
|
+
<Stack>
|
|
85
|
+
{ hasNoDynamicTags ? (
|
|
86
|
+
<NoDynamicTags />
|
|
87
|
+
) : (
|
|
88
|
+
<Fragment>
|
|
89
|
+
<PopoverSearch
|
|
81
90
|
value={ searchValue }
|
|
82
|
-
|
|
91
|
+
onSearch={ handleSearch }
|
|
83
92
|
placeholder={ __( 'Search dynamic tags…', 'elementor' ) }
|
|
84
|
-
InputProps={ {
|
|
85
|
-
startAdornment: (
|
|
86
|
-
<InputAdornment position="start">
|
|
87
|
-
<SearchIcon fontSize={ SIZE } />
|
|
88
|
-
</InputAdornment>
|
|
89
|
-
),
|
|
90
|
-
} }
|
|
91
93
|
/>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
key={ value }
|
|
110
|
-
selected={ isSelected }
|
|
111
|
-
// eslint-disable-next-line jsx-a11y/no-autofocus
|
|
112
|
-
autoFocus={ isSelected }
|
|
113
|
-
sx={ { px: 3.5, typography: 'caption' } }
|
|
114
|
-
onClick={ () => handleSetDynamicTag( value, tagLabel ) }
|
|
115
|
-
>
|
|
116
|
-
{ tagLabel }
|
|
117
|
-
</MenuItem>
|
|
118
|
-
);
|
|
119
|
-
} ) }
|
|
120
|
-
</Fragment>
|
|
121
|
-
) ) }
|
|
122
|
-
</MenuList>
|
|
123
|
-
) : (
|
|
124
|
-
<NoResults searchValue={ searchValue } onClear={ () => setSearchValue( '' ) } />
|
|
125
|
-
) }
|
|
126
|
-
</Box>
|
|
127
|
-
</Fragment>
|
|
128
|
-
) }
|
|
129
|
-
</Stack>
|
|
94
|
+
<Divider />
|
|
95
|
+
<PopoverMenuList
|
|
96
|
+
items={ virtualizedItems }
|
|
97
|
+
onSelect={ handleSetDynamicTag }
|
|
98
|
+
onClose={ closePopover }
|
|
99
|
+
selectedValue={ dynamicValue?.name }
|
|
100
|
+
itemStyle={ ( item ) =>
|
|
101
|
+
item.type === 'item' ? { paddingInlineStart: theme.spacing( 3.5 ) } : {}
|
|
102
|
+
}
|
|
103
|
+
noResultsComponent={
|
|
104
|
+
<NoResults searchValue={ searchValue } onClear={ () => setSearchValue( '' ) } />
|
|
105
|
+
}
|
|
106
|
+
/>
|
|
107
|
+
</Fragment>
|
|
108
|
+
) }
|
|
109
|
+
</Stack>
|
|
110
|
+
</>
|
|
130
111
|
);
|
|
131
112
|
};
|
|
132
113
|
|
|
@@ -173,7 +154,7 @@ const NoDynamicTags = () => (
|
|
|
173
154
|
{ __( 'Streamline your workflow with dynamic tags', 'elementor' ) }
|
|
174
155
|
</Typography>
|
|
175
156
|
<Typography align="center" variant="caption">
|
|
176
|
-
{ __( '
|
|
157
|
+
{ __( "You'll need Elementor Pro to use this feature.", 'elementor' ) }
|
|
177
158
|
</Typography>
|
|
178
159
|
</Stack>
|
|
179
160
|
</Box>
|
|
@@ -16,6 +16,6 @@ export const usePropDynamicAction = (): PopoverActionProps => {
|
|
|
16
16
|
visible,
|
|
17
17
|
icon: DatabaseIcon,
|
|
18
18
|
title: __( 'Dynamic tags', 'elementor' ),
|
|
19
|
-
|
|
19
|
+
content: ( { close } ) => <DynamicSelection close={ close } />,
|
|
20
20
|
};
|
|
21
21
|
};
|
package/src/dynamics/init.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { settingsTransformersRegistry, styleTransformersRegistry } from '@elementor/editor-canvas';
|
|
2
|
+
import { injectIntoRepeaterItemIcon, injectIntoRepeaterItemLabel } from '@elementor/editor-controls';
|
|
3
|
+
import { type BackgroundOverlayPropType, type PropValue } from '@elementor/editor-props';
|
|
4
|
+
import { type InjectedComponent } from '@elementor/locations';
|
|
2
5
|
|
|
3
6
|
import { registerControlReplacement } from '../control-replacement';
|
|
4
7
|
import { controlActionsMenu } from '../controls-actions';
|
|
8
|
+
import {
|
|
9
|
+
BackgroundControlDynamicTagIcon,
|
|
10
|
+
BackgroundControlDynamicTagLabel,
|
|
11
|
+
} from './components/background-control-dynamic-tag';
|
|
5
12
|
import { DynamicSelectionControl } from './components/dynamic-selection-control';
|
|
6
13
|
import { dynamicTransformer } from './dynamic-transformer';
|
|
7
14
|
import { usePropDynamicAction } from './hooks/use-prop-dynamic-action';
|
|
@@ -15,6 +22,20 @@ export const init = () => {
|
|
|
15
22
|
condition: ( { value } ) => isDynamicPropValue( value ),
|
|
16
23
|
} );
|
|
17
24
|
|
|
25
|
+
injectIntoRepeaterItemLabel( {
|
|
26
|
+
id: 'dynamic-background-image',
|
|
27
|
+
condition: ( { value } ) =>
|
|
28
|
+
isDynamicPropValue( ( value as BackgroundOverlayPropType ).value?.image?.value?.src ),
|
|
29
|
+
component: BackgroundControlDynamicTagLabel as InjectedComponent< { value: PropValue } >,
|
|
30
|
+
} );
|
|
31
|
+
|
|
32
|
+
injectIntoRepeaterItemIcon( {
|
|
33
|
+
id: 'dynamic-background-image',
|
|
34
|
+
condition: ( { value } ) =>
|
|
35
|
+
isDynamicPropValue( ( value as BackgroundOverlayPropType ).value?.image?.value?.src ),
|
|
36
|
+
component: BackgroundControlDynamicTagIcon,
|
|
37
|
+
} );
|
|
38
|
+
|
|
18
39
|
registerPopoverAction( {
|
|
19
40
|
id: 'dynamic-tags',
|
|
20
41
|
useProps: usePropDynamicAction,
|