@elementor/editor-editing-panel 0.14.2 → 0.16.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 +48 -0
- package/dist/index.d.mts +29 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +939 -302
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +944 -294
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -8
- package/src/components/editing-panel.tsx +1 -1
- package/src/components/settings-tab.tsx +6 -17
- package/src/components/style-sections/position-section/position-section.tsx +15 -0
- package/src/components/style-sections/position-section/z-index-control.tsx +16 -0
- package/src/components/style-sections/size-section.tsx +14 -18
- package/src/components/style-sections/spacing-section/linked-dimensions-control.tsx +140 -0
- package/src/components/style-sections/spacing-section/spacing-section.tsx +22 -0
- package/src/components/style-sections/typography-section/font-size-control.tsx +16 -0
- package/src/components/style-sections/typography-section/font-weight-control.tsx +24 -0
- package/src/components/style-sections/typography-section/letter-spacing-control.tsx +16 -0
- package/src/components/style-sections/typography-section/text-color-control.tsx +16 -0
- package/src/{controls/control-types → components/style-sections/typography-section}/text-style-control.tsx +16 -14
- package/src/components/style-sections/typography-section/transform-control.tsx +23 -0
- package/src/components/style-sections/typography-section/typography-section.tsx +34 -0
- package/src/components/style-sections/typography-section/word-spacing-control.tsx +16 -0
- package/src/components/style-tab.tsx +30 -6
- package/src/contexts/element-context.tsx +5 -3
- package/src/contexts/style-context.tsx +8 -2
- package/src/controls/components/control-container.tsx +18 -0
- package/src/controls/components/control-toggle-button-group.tsx +59 -0
- package/src/controls/components/text-field-inner-selection.tsx +79 -0
- package/src/controls/control-replacement.ts +26 -0
- package/src/controls/control-types/color-control.tsx +24 -0
- package/src/controls/control-types/image-control.tsx +3 -18
- package/src/controls/control-types/number-control.tsx +25 -0
- package/src/controls/control-types/size-control.tsx +22 -34
- package/src/controls/control-types/text-area-control.tsx +1 -1
- package/src/controls/control-types/toggle-control.tsx +25 -0
- package/src/controls/control.tsx +50 -0
- package/src/controls/{get-control-by-type.ts → controls-registry.tsx} +13 -9
- package/src/controls/hooks/use-style-control.ts +2 -1
- package/src/controls/settings-control.tsx +8 -21
- package/src/dynamics/components/dynamic-selection-control.tsx +180 -0
- package/src/dynamics/components/dynamic-selection.tsx +144 -0
- package/src/dynamics/dynamic-control.tsx +42 -0
- package/src/dynamics/hooks/use-dynamic-tag.ts +10 -0
- package/src/dynamics/hooks/use-prop-dynamic-tags.ts +36 -0
- package/src/dynamics/init.ts +10 -0
- package/src/dynamics/sync/get-atomic-dynamic-tags.ts +14 -0
- package/src/dynamics/sync/get-elementor-config.ts +7 -0
- package/src/dynamics/types.ts +32 -0
- package/src/dynamics/utils.ts +9 -0
- package/src/hooks/use-element-type.ts +5 -0
- package/src/index.ts +3 -0
- package/src/init.ts +4 -0
- package/src/props/is-transformable.ts +14 -0
- package/src/sync/types.ts +2 -1
- package/src/sync/update-style.ts +2 -2
- package/src/types.ts +17 -0
- package/LICENSE +0 -674
- package/src/components/style-sections/typography-section.tsx +0 -15
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { AccordionSection } from '../accordion-section';
|
|
3
3
|
import { StyleControl, StyleControlProps } from '../../controls/style-control';
|
|
4
|
-
import { CollapsibleContent } from '../collapsible-content';
|
|
5
|
-
import { SizeControl, Unit } from '../../controls/control-types/size-control';
|
|
6
4
|
import { Stack } from '@elementor/ui';
|
|
7
5
|
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { Control as BaseControl } from '../../controls/control';
|
|
7
|
+
import { ControlContainer } from '../../controls/components/control-container';
|
|
8
8
|
|
|
9
9
|
export const SizeSection = () => {
|
|
10
10
|
return (
|
|
@@ -14,25 +14,21 @@ export const SizeSection = () => {
|
|
|
14
14
|
<Control bind="width" label={ __( 'Width', 'elementor' ) } />
|
|
15
15
|
<Control bind="height" label={ __( 'Height', 'elementor' ) } />
|
|
16
16
|
</Stack>
|
|
17
|
-
<
|
|
18
|
-
<Stack
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
<Control bind="minHeight" label={ __( 'Min. Height', 'elementor' ) } />
|
|
22
|
-
</Stack>
|
|
23
|
-
<Stack direction="row" gap={ 2 }>
|
|
24
|
-
<Control bind="maxWidth" label={ __( 'Max. Width', 'elementor' ) } />
|
|
25
|
-
<Control bind="maxHeight" label={ __( 'Max. Height', 'elementor' ) } />
|
|
26
|
-
</Stack>
|
|
17
|
+
<Stack gap={ 1.5 } sx={ { pt: 1.5 } }>
|
|
18
|
+
<Stack direction="row" gap={ 2 }>
|
|
19
|
+
<Control bind="minWidth" label={ __( 'Min. Width', 'elementor' ) } />
|
|
20
|
+
<Control bind="minHeight" label={ __( 'Min. Height', 'elementor' ) } />
|
|
27
21
|
</Stack>
|
|
28
|
-
|
|
22
|
+
<Stack direction="row" gap={ 2 }>
|
|
23
|
+
<Control bind="maxWidth" label={ __( 'Max. Width', 'elementor' ) } />
|
|
24
|
+
<Control bind="maxHeight" label={ __( 'Max. Height', 'elementor' ) } />
|
|
25
|
+
</Stack>
|
|
26
|
+
</Stack>
|
|
29
27
|
</Stack>
|
|
30
28
|
</AccordionSection>
|
|
31
29
|
);
|
|
32
30
|
};
|
|
33
31
|
|
|
34
|
-
const units: Unit[] = [ 'px', '%', 'em', 'rem', 'vw' ];
|
|
35
|
-
|
|
36
32
|
type ControlProps = {
|
|
37
33
|
bind: StyleControlProps[ 'bind' ];
|
|
38
34
|
label: string;
|
|
@@ -41,10 +37,10 @@ type ControlProps = {
|
|
|
41
37
|
const Control = ( { label, bind }: ControlProps ) => {
|
|
42
38
|
return (
|
|
43
39
|
<StyleControl bind={ bind }>
|
|
44
|
-
<
|
|
40
|
+
<ControlContainer direction="column">
|
|
45
41
|
<StyleControl.Label>{ label }</StyleControl.Label>
|
|
46
|
-
<
|
|
47
|
-
</
|
|
42
|
+
<BaseControl type={ 'size' } />
|
|
43
|
+
</ControlContainer>
|
|
48
44
|
</StyleControl>
|
|
49
45
|
);
|
|
50
46
|
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { PropValue } from '../../../types';
|
|
2
|
+
import { SizeControl } from '../../../controls/control-types/size-control';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ControlContainer } from '../../../controls/components/control-container';
|
|
5
|
+
import { Stack, ToggleButton } from '@elementor/ui';
|
|
6
|
+
import { DetachIcon, LinkIcon, SideBottomIcon, SideLeftIcon, SideRightIcon, SideTopIcon } from '@elementor/icons';
|
|
7
|
+
import { ControlLabel } from '../../control-label';
|
|
8
|
+
import { ControlContext, useControl } from '../../../controls/control-context';
|
|
9
|
+
import { __ } from '@wordpress/i18n';
|
|
10
|
+
|
|
11
|
+
export type Position = 'top' | 'right' | 'bottom' | 'left';
|
|
12
|
+
|
|
13
|
+
export type LinkedDimensionsValue = {
|
|
14
|
+
$$type: 'linked-dimensions';
|
|
15
|
+
value: {
|
|
16
|
+
isLinked: boolean;
|
|
17
|
+
top: PropValue;
|
|
18
|
+
right: PropValue;
|
|
19
|
+
bottom: PropValue;
|
|
20
|
+
left: PropValue;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const LinkedDimensionsControl = ( { label }: { label: string } ) => {
|
|
25
|
+
const { value, setValue } = useControl< LinkedDimensionsValue >();
|
|
26
|
+
const { top, right, bottom, left, isLinked = false } = value?.value || {};
|
|
27
|
+
|
|
28
|
+
const setLinkedValue = ( position: Position, newValue: PropValue ) => {
|
|
29
|
+
const updatedValue = {
|
|
30
|
+
isLinked,
|
|
31
|
+
top: isLinked ? newValue : top,
|
|
32
|
+
right: isLinked ? newValue : right,
|
|
33
|
+
bottom: isLinked ? newValue : bottom,
|
|
34
|
+
left: isLinked ? newValue : left,
|
|
35
|
+
[ position ]: newValue,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
setValue( {
|
|
39
|
+
$$type: 'linked-dimensions',
|
|
40
|
+
value: updatedValue,
|
|
41
|
+
} );
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const toggleLinked = () => {
|
|
45
|
+
const updatedValue = {
|
|
46
|
+
isLinked: ! isLinked,
|
|
47
|
+
top,
|
|
48
|
+
right: ! isLinked ? top : right,
|
|
49
|
+
bottom: ! isLinked ? top : bottom,
|
|
50
|
+
left: ! isLinked ? top : left,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
setValue( {
|
|
54
|
+
$$type: 'linked-dimensions',
|
|
55
|
+
value: updatedValue,
|
|
56
|
+
} );
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const LinkedIcon = isLinked ? LinkIcon : DetachIcon;
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<Stack direction="row" gap={ 2 }>
|
|
64
|
+
<ControlLabel>{ label }</ControlLabel>
|
|
65
|
+
<ToggleButton
|
|
66
|
+
aria-label={ __( 'Link Inputs', 'elementor' ) }
|
|
67
|
+
size={ 'tiny' }
|
|
68
|
+
value={ 'check' }
|
|
69
|
+
selected={ isLinked }
|
|
70
|
+
sx={ { marginLeft: 'auto' } }
|
|
71
|
+
onChange={ toggleLinked }
|
|
72
|
+
>
|
|
73
|
+
<LinkedIcon fontSize={ 'tiny' } />
|
|
74
|
+
</ToggleButton>
|
|
75
|
+
</Stack>
|
|
76
|
+
<Stack direction="row" gap={ 2 }>
|
|
77
|
+
<ControlContainer direction={ 'column' }>
|
|
78
|
+
<ControlLabel>{ __( 'Top', 'elementor' ) }</ControlLabel>
|
|
79
|
+
<Control
|
|
80
|
+
bind={ 'top' }
|
|
81
|
+
value={ top }
|
|
82
|
+
setValue={ setLinkedValue }
|
|
83
|
+
startIcon={ <SideTopIcon fontSize={ 'tiny' } /> }
|
|
84
|
+
/>
|
|
85
|
+
</ControlContainer>
|
|
86
|
+
<ControlContainer direction={ 'column' }>
|
|
87
|
+
<ControlLabel>{ __( 'Right', 'elementor' ) }</ControlLabel>
|
|
88
|
+
<Control
|
|
89
|
+
bind={ 'right' }
|
|
90
|
+
value={ right }
|
|
91
|
+
setValue={ setLinkedValue }
|
|
92
|
+
startIcon={ <SideRightIcon fontSize={ 'tiny' } /> }
|
|
93
|
+
/>
|
|
94
|
+
</ControlContainer>
|
|
95
|
+
</Stack>
|
|
96
|
+
<Stack direction="row" gap={ 2 }>
|
|
97
|
+
<ControlContainer direction={ 'column' }>
|
|
98
|
+
<ControlLabel>{ __( 'Bottom', 'elementor' ) }</ControlLabel>
|
|
99
|
+
<Control
|
|
100
|
+
bind={ 'bottom' }
|
|
101
|
+
value={ bottom }
|
|
102
|
+
setValue={ setLinkedValue }
|
|
103
|
+
startIcon={ <SideBottomIcon fontSize={ 'tiny' } /> }
|
|
104
|
+
/>
|
|
105
|
+
</ControlContainer>
|
|
106
|
+
<ControlContainer direction={ 'column' }>
|
|
107
|
+
<ControlLabel>{ __( 'Left', 'elementor' ) }</ControlLabel>
|
|
108
|
+
<Control
|
|
109
|
+
bind={ 'left' }
|
|
110
|
+
value={ left }
|
|
111
|
+
setValue={ setLinkedValue }
|
|
112
|
+
startIcon={ <SideLeftIcon fontSize={ 'tiny' } /> }
|
|
113
|
+
/>
|
|
114
|
+
</ControlContainer>
|
|
115
|
+
</Stack>
|
|
116
|
+
</>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const Control = ( {
|
|
121
|
+
bind,
|
|
122
|
+
startIcon,
|
|
123
|
+
value,
|
|
124
|
+
setValue,
|
|
125
|
+
}: {
|
|
126
|
+
bind: Position;
|
|
127
|
+
value: PropValue;
|
|
128
|
+
startIcon: React.ReactNode;
|
|
129
|
+
setValue: ( bind: Position, newValue: PropValue ) => void;
|
|
130
|
+
} ) => (
|
|
131
|
+
<ControlContext.Provider
|
|
132
|
+
value={ {
|
|
133
|
+
bind,
|
|
134
|
+
setValue: ( newValue ) => setValue( bind, newValue ),
|
|
135
|
+
value,
|
|
136
|
+
} }
|
|
137
|
+
>
|
|
138
|
+
<SizeControl startIcon={ startIcon } />
|
|
139
|
+
</ControlContext.Provider>
|
|
140
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { AccordionSection } from '../../accordion-section';
|
|
3
|
+
import { Divider, Stack } from '@elementor/ui';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { LinkedDimensionsControl } from './linked-dimensions-control';
|
|
6
|
+
import { StyleControl } from '../../../controls/style-control';
|
|
7
|
+
|
|
8
|
+
export const SpacingSection = () => {
|
|
9
|
+
return (
|
|
10
|
+
<AccordionSection title={ __( 'Spacing', 'elementor' ) }>
|
|
11
|
+
<Stack gap={ 1.5 }>
|
|
12
|
+
<StyleControl bind={ 'padding' }>
|
|
13
|
+
<LinkedDimensionsControl label={ __( 'Padding', 'elementor' ) } />
|
|
14
|
+
</StyleControl>
|
|
15
|
+
<Divider />
|
|
16
|
+
<StyleControl bind={ 'margin' }>
|
|
17
|
+
<LinkedDimensionsControl label={ __( 'Margin', 'elementor' ) } />
|
|
18
|
+
</StyleControl>
|
|
19
|
+
</Stack>
|
|
20
|
+
</AccordionSection>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { StyleControl } from '../../../controls/style-control';
|
|
3
|
+
import { SizeControl } from '../../../controls/control-types/size-control';
|
|
4
|
+
import { ControlContainer } from '../../../controls/components/control-container';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
export const FontSizeControl = () => {
|
|
8
|
+
return (
|
|
9
|
+
<StyleControl bind="font-size">
|
|
10
|
+
<ControlContainer>
|
|
11
|
+
<StyleControl.Label>{ __( 'Font Size', 'elementor' ) }</StyleControl.Label>
|
|
12
|
+
<SizeControl />
|
|
13
|
+
</ControlContainer>
|
|
14
|
+
</StyleControl>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { StyleControl } from '../../../controls/style-control';
|
|
3
|
+
import { SelectControl } from '../../../controls/control-types/select-control';
|
|
4
|
+
import { ControlContainer } from '../../../controls/components/control-container';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
const fontWeightOptions = [
|
|
8
|
+
{ label: __( 'Light - 400', 'elementor' ), value: 400 },
|
|
9
|
+
{ label: __( 'Regular - 500', 'elementor' ), value: 500 },
|
|
10
|
+
{ label: __( 'Semi Bold - 600', 'elementor' ), value: 600 },
|
|
11
|
+
{ label: __( 'Bold - 700', 'elementor' ), value: 700 },
|
|
12
|
+
{ label: __( 'Black - 900', 'elementor' ), value: 900 },
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export const FontWeightControl = () => {
|
|
16
|
+
return (
|
|
17
|
+
<StyleControl bind="fontWeight">
|
|
18
|
+
<ControlContainer>
|
|
19
|
+
<StyleControl.Label>{ __( 'Font Weight', 'elementor' ) }</StyleControl.Label>
|
|
20
|
+
<SelectControl options={ fontWeightOptions } />
|
|
21
|
+
</ControlContainer>
|
|
22
|
+
</StyleControl>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { StyleControl } from '../../../controls/style-control';
|
|
3
|
+
import { SizeControl } from '../../../controls/control-types/size-control';
|
|
4
|
+
import { ControlContainer } from '../../../controls/components/control-container';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
export const LetterSpacingControl = () => {
|
|
8
|
+
return (
|
|
9
|
+
<StyleControl bind="letter-spacing">
|
|
10
|
+
<ControlContainer>
|
|
11
|
+
<StyleControl.Label>{ __( 'Letter Spacing', 'elementor' ) }</StyleControl.Label>
|
|
12
|
+
<SizeControl />
|
|
13
|
+
</ControlContainer>
|
|
14
|
+
</StyleControl>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { StyleControl } from '../../../controls/style-control';
|
|
3
|
+
import { ControlContainer } from '../../../controls/components/control-container';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { ColorControl } from '../../../controls/control-types/color-control';
|
|
6
|
+
|
|
7
|
+
export const TextColorControl = () => {
|
|
8
|
+
return (
|
|
9
|
+
<StyleControl bind="color">
|
|
10
|
+
<ControlContainer>
|
|
11
|
+
<StyleControl.Label>{ __( 'Text Color', 'elementor' ) }</StyleControl.Label>
|
|
12
|
+
<ColorControl />
|
|
13
|
+
</ControlContainer>
|
|
14
|
+
</StyleControl>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { ToggleButton as ToggleButtonBase, ToggleButtonGroup, ToggleButtonProps } from '@elementor/ui';
|
|
3
|
+
import { ItalicIcon, StrikethroughIcon, UnderlineIcon } from '@elementor/icons';
|
|
4
|
+
import { ControlLabel } from '../../control-label';
|
|
5
|
+
import { useStyleControl } from '../../../controls/hooks/use-style-control';
|
|
5
6
|
import { __ } from '@wordpress/i18n';
|
|
7
|
+
import { ControlContainer } from '../../../controls/components/control-container';
|
|
8
|
+
|
|
9
|
+
const buttonSize = 'tiny';
|
|
6
10
|
|
|
7
11
|
export const TextStyleControl = () => {
|
|
8
12
|
const [ fontStyle, setFontStyle ] = useStyleControl< string | null >( 'fontStyle' );
|
|
@@ -11,15 +15,16 @@ export const TextStyleControl = () => {
|
|
|
11
15
|
const formats = [ fontStyle, ...( textDecoration || '' ).split( ' ' ) ];
|
|
12
16
|
|
|
13
17
|
return (
|
|
14
|
-
<
|
|
18
|
+
<ControlContainer>
|
|
15
19
|
<ControlLabel>{ __( 'Style', 'elementor' ) }</ControlLabel>
|
|
16
20
|
<ToggleButtonGroup value={ formats }>
|
|
17
21
|
<ToggleButton
|
|
18
22
|
value="italic"
|
|
19
23
|
onChange={ ( v ) => setFontStyle( fontStyle === v ? null : v ) }
|
|
20
24
|
aria-label="italic"
|
|
25
|
+
sx={ { marginLeft: 'auto' } }
|
|
21
26
|
>
|
|
22
|
-
<
|
|
27
|
+
<ItalicIcon fontSize={ buttonSize } />
|
|
23
28
|
</ToggleButton>
|
|
24
29
|
<ShorthandControl
|
|
25
30
|
value="line-through"
|
|
@@ -27,7 +32,7 @@ export const TextStyleControl = () => {
|
|
|
27
32
|
updateValues={ setTextDecoration }
|
|
28
33
|
aria-label="line-through"
|
|
29
34
|
>
|
|
30
|
-
<
|
|
35
|
+
<StrikethroughIcon fontSize={ buttonSize } />
|
|
31
36
|
</ShorthandControl>
|
|
32
37
|
<ShorthandControl
|
|
33
38
|
value="underline"
|
|
@@ -35,10 +40,10 @@ export const TextStyleControl = () => {
|
|
|
35
40
|
updateValues={ setTextDecoration }
|
|
36
41
|
aria-label="underline"
|
|
37
42
|
>
|
|
38
|
-
<
|
|
43
|
+
<UnderlineIcon fontSize={ buttonSize } />
|
|
39
44
|
</ShorthandControl>
|
|
40
45
|
</ToggleButtonGroup>
|
|
41
|
-
</
|
|
46
|
+
</ControlContainer>
|
|
42
47
|
);
|
|
43
48
|
};
|
|
44
49
|
|
|
@@ -74,17 +79,14 @@ export const ShorthandControl = ( {
|
|
|
74
79
|
);
|
|
75
80
|
};
|
|
76
81
|
|
|
77
|
-
type ControlToggleButtonProps =
|
|
78
|
-
value: string;
|
|
82
|
+
type ControlToggleButtonProps = Omit< ToggleButtonProps, 'onChange' > & {
|
|
79
83
|
onChange: ( newValue: string ) => void;
|
|
80
|
-
|
|
81
|
-
'aria-label': string;
|
|
82
|
-
} >;
|
|
84
|
+
};
|
|
83
85
|
|
|
84
86
|
const ToggleButton = ( { onChange, ...props }: ControlToggleButtonProps ) => {
|
|
85
87
|
const handleChange = ( _e: React.MouseEvent< HTMLElement >, newValue: string ) => {
|
|
86
88
|
onChange( newValue );
|
|
87
89
|
};
|
|
88
90
|
|
|
89
|
-
return <ToggleButtonBase { ...props } onChange={ handleChange } size=
|
|
91
|
+
return <ToggleButtonBase { ...props } onChange={ handleChange } size={ buttonSize } />;
|
|
90
92
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ControlContainer } from '../../../controls/components/control-container';
|
|
3
|
+
import { StyleControl } from '../../../controls/style-control';
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { ToggleControl } from '../../../controls/control-types/toggle-control';
|
|
6
|
+
import { LetterCaseIcon, LetterCaseLowerIcon, LetterCaseUpperIcon } from '@elementor/icons';
|
|
7
|
+
|
|
8
|
+
const options = [
|
|
9
|
+
{ value: 'capitalize', label: __( 'Capitalize', 'elementor' ), icon: LetterCaseIcon },
|
|
10
|
+
{ value: 'uppercase', label: __( 'Uppercase', 'elementor' ), icon: LetterCaseUpperIcon },
|
|
11
|
+
{ value: 'lowercase', label: __( 'Lowercase', 'elementor' ), icon: LetterCaseLowerIcon },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export const TransformControl = () => {
|
|
15
|
+
return (
|
|
16
|
+
<ControlContainer>
|
|
17
|
+
<StyleControl.Label>{ __( 'Transform', 'elementor' ) }</StyleControl.Label>
|
|
18
|
+
<StyleControl bind={ 'text-transform' }>
|
|
19
|
+
<ToggleControl options={ options } />
|
|
20
|
+
</StyleControl>
|
|
21
|
+
</ControlContainer>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { AccordionSection } from '../../accordion-section';
|
|
3
|
+
import { Divider, Stack } from '@elementor/ui';
|
|
4
|
+
import { TextStyleControl } from './text-style-control';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { FontSizeControl } from './font-size-control';
|
|
7
|
+
import { FontWeightControl } from './font-weight-control';
|
|
8
|
+
import { TextColorControl } from './text-color-control';
|
|
9
|
+
import { LetterSpacingControl } from './letter-spacing-control';
|
|
10
|
+
import { WordSpacingControl } from './word-spacing-control';
|
|
11
|
+
import { CollapsibleContent } from '../../collapsible-content';
|
|
12
|
+
import { TransformControl } from './transform-control';
|
|
13
|
+
|
|
14
|
+
export const TypographySection = () => {
|
|
15
|
+
return (
|
|
16
|
+
<AccordionSection title={ __( 'Typography', 'elementor' ) }>
|
|
17
|
+
<Stack gap={ 1.5 }>
|
|
18
|
+
<FontWeightControl />
|
|
19
|
+
<FontSizeControl />
|
|
20
|
+
<Divider />
|
|
21
|
+
<TextColorControl />
|
|
22
|
+
<CollapsibleContent>
|
|
23
|
+
<Stack gap={ 1.5 } sx={ { pt: 1.5 } }>
|
|
24
|
+
<LetterSpacingControl />
|
|
25
|
+
<WordSpacingControl />
|
|
26
|
+
<Divider />
|
|
27
|
+
<TextStyleControl />
|
|
28
|
+
<TransformControl />
|
|
29
|
+
</Stack>
|
|
30
|
+
</CollapsibleContent>
|
|
31
|
+
</Stack>
|
|
32
|
+
</AccordionSection>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { StyleControl } from '../../../controls/style-control';
|
|
3
|
+
import { SizeControl } from '../../../controls/control-types/size-control';
|
|
4
|
+
import { ControlContainer } from '../../../controls/components/control-container';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
export const WordSpacingControl = () => {
|
|
8
|
+
return (
|
|
9
|
+
<StyleControl bind="word-spacing">
|
|
10
|
+
<ControlContainer>
|
|
11
|
+
<StyleControl.Label>{ __( 'Word Spacing', 'elementor' ) }</StyleControl.Label>
|
|
12
|
+
<SizeControl />
|
|
13
|
+
</ControlContainer>
|
|
14
|
+
</StyleControl>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
@@ -4,20 +4,44 @@ import { useElementContext } from '../contexts/element-context';
|
|
|
4
4
|
import { useElementStyles } from '../hooks/use-element-styles';
|
|
5
5
|
import { Stack } from '@elementor/ui';
|
|
6
6
|
import { SizeSection } from './style-sections/size-section';
|
|
7
|
-
import { TypographySection } from './style-sections/typography-section';
|
|
7
|
+
import { TypographySection } from './style-sections/typography-section/typography-section';
|
|
8
|
+
import { PositionSection } from './style-sections/position-section/position-section';
|
|
9
|
+
import { StyleDefinition } from '@elementor/editor-style';
|
|
10
|
+
import { SpacingSection } from './style-sections/spacing-section/spacing-section';
|
|
11
|
+
|
|
12
|
+
const CLASSES_PROP_KEY = 'classes';
|
|
8
13
|
|
|
9
14
|
export const StyleTab = () => {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
// TODO: Handle selected style state.
|
|
13
|
-
const [ selectedStyleDef = null ] = Object.values( elementStyles || {} );
|
|
15
|
+
const styleDefinition = useStyleDefinition();
|
|
16
|
+
const classesProp = useClassesProp();
|
|
14
17
|
|
|
15
18
|
return (
|
|
16
|
-
<StyleContext selectedStyleDef={
|
|
19
|
+
<StyleContext selectedStyleDef={ styleDefinition } selectedClassesProp={ classesProp }>
|
|
17
20
|
<Stack>
|
|
18
21
|
<SizeSection />
|
|
22
|
+
<PositionSection />
|
|
19
23
|
<TypographySection />
|
|
24
|
+
<SpacingSection />
|
|
20
25
|
</Stack>
|
|
21
26
|
</StyleContext>
|
|
22
27
|
);
|
|
23
28
|
};
|
|
29
|
+
|
|
30
|
+
function useClassesProp(): string {
|
|
31
|
+
const { elementType } = useElementContext();
|
|
32
|
+
|
|
33
|
+
const prop = Object.entries( elementType.propsSchema ).find( ( [ , { type } ] ) => type.key === CLASSES_PROP_KEY );
|
|
34
|
+
|
|
35
|
+
if ( ! prop ) {
|
|
36
|
+
throw new Error( 'Element does not have a classes prop' );
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return prop[ 0 ];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function useStyleDefinition(): StyleDefinition | null {
|
|
43
|
+
const { element } = useElementContext();
|
|
44
|
+
const elementStyles = useElementStyles( element.id );
|
|
45
|
+
|
|
46
|
+
return Object.values( elementStyles || {} )[ 0 ] ?? null;
|
|
47
|
+
}
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { createContext, ReactNode, useContext } from 'react';
|
|
3
|
-
import { Element } from '../types';
|
|
3
|
+
import { Element, ElementType } from '../types';
|
|
4
4
|
|
|
5
5
|
type ContextValue = {
|
|
6
6
|
element: Element;
|
|
7
|
+
elementType: ElementType;
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
const Context = createContext< ContextValue | null >( null );
|
|
10
11
|
|
|
11
12
|
type Props = {
|
|
12
13
|
element: Element;
|
|
14
|
+
elementType: ElementType;
|
|
13
15
|
children?: ReactNode;
|
|
14
16
|
};
|
|
15
17
|
|
|
16
|
-
export function ElementContext( { children, element }: Props ) {
|
|
17
|
-
return <Context.Provider value={ { element } }>{ children }</Context.Provider>;
|
|
18
|
+
export function ElementContext( { children, element, elementType }: Props ) {
|
|
19
|
+
return <Context.Provider value={ { element, elementType } }>{ children }</Context.Provider>;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export function useElementContext() {
|
|
@@ -6,6 +6,7 @@ import { StyleDefinition, StyleVariant } from '@elementor/editor-style';
|
|
|
6
6
|
type ContextValue = {
|
|
7
7
|
selectedStyleDef: StyleDefinition | null;
|
|
8
8
|
selectedMeta: StyleVariant[ 'meta' ];
|
|
9
|
+
selectedClassesProp: string;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
const Context = createContext< ContextValue | null >( null );
|
|
@@ -13,14 +14,19 @@ const Context = createContext< ContextValue | null >( null );
|
|
|
13
14
|
type Props = {
|
|
14
15
|
children: ReactNode;
|
|
15
16
|
selectedStyleDef: StyleDefinition | null;
|
|
17
|
+
selectedClassesProp: string;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
|
-
export function StyleContext( { children, selectedStyleDef }: Props ) {
|
|
20
|
+
export function StyleContext( { children, selectedStyleDef, selectedClassesProp }: Props ) {
|
|
19
21
|
const breakpoint = useActiveBreakpoint();
|
|
20
22
|
// TODO: Handle state when we support it.
|
|
21
23
|
const selectedMeta = { breakpoint, state: null } as const;
|
|
22
24
|
|
|
23
|
-
return
|
|
25
|
+
return (
|
|
26
|
+
<Context.Provider value={ { selectedStyleDef, selectedMeta, selectedClassesProp } }>
|
|
27
|
+
{ children }
|
|
28
|
+
</Context.Provider>
|
|
29
|
+
);
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
export function useStyleContext() {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Stack, StackProps, styled } from '@elementor/ui';
|
|
3
|
+
|
|
4
|
+
const StyledStack = styled( Stack )( ( { theme, gap, direction } ) => ( {
|
|
5
|
+
'> :only-child': {
|
|
6
|
+
width: '100%',
|
|
7
|
+
},
|
|
8
|
+
'&:where( :has( > :nth-child( 2 ):last-child ) ) > :where( * )': {
|
|
9
|
+
width: direction === 'column' ? '100%' : `calc( 50% - ${ theme.spacing( gap / 2 ) })`,
|
|
10
|
+
},
|
|
11
|
+
'&:where( :has( > :nth-child( 3 ):last-child ) ) > :where( * )': {
|
|
12
|
+
width: direction === 'column' ? '100%' : `calc( 33.3333% - ${ theme.spacing( gap * 2 ) } / 3)`,
|
|
13
|
+
},
|
|
14
|
+
} ) );
|
|
15
|
+
|
|
16
|
+
export const ControlContainer = ( props: StackProps ) => (
|
|
17
|
+
<StyledStack gap={ 1 } direction="row" alignItems="center" justifyContent="space-between" { ...props } />
|
|
18
|
+
);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { JSX } from 'react';
|
|
3
|
+
import { StackProps, styled, ToggleButton, ToggleButtonGroup } from '@elementor/ui';
|
|
4
|
+
|
|
5
|
+
export type ToggleButtonGroupItem< TValue > = {
|
|
6
|
+
value: TValue;
|
|
7
|
+
label: string;
|
|
8
|
+
icon: JSX.ElementType;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const StyledToggleButtonGroup = styled( ToggleButtonGroup )`
|
|
12
|
+
${ ( { justify } ) => `justify-content: ${ justify };` }
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
type ExclusiveValue< TValue > = TValue | null;
|
|
16
|
+
type NonExclusiveValue< TValue > = TValue[];
|
|
17
|
+
|
|
18
|
+
type Props< TValue > = {
|
|
19
|
+
justify?: StackProps[ 'justifyContent' ];
|
|
20
|
+
size?: 'tiny' | 'small' | 'medium' | 'large';
|
|
21
|
+
items: ToggleButtonGroupItem< TValue >[];
|
|
22
|
+
} & (
|
|
23
|
+
| {
|
|
24
|
+
exclusive?: false;
|
|
25
|
+
value: NonExclusiveValue< TValue >;
|
|
26
|
+
onChange: ( value: NonExclusiveValue< TValue > ) => void;
|
|
27
|
+
}
|
|
28
|
+
| {
|
|
29
|
+
exclusive: true;
|
|
30
|
+
value: ExclusiveValue< TValue >;
|
|
31
|
+
onChange: ( value: ExclusiveValue< TValue > ) => void;
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export const ControlToggleButtonGroup = < TValue, >( {
|
|
36
|
+
justify = 'end',
|
|
37
|
+
size = 'tiny',
|
|
38
|
+
value,
|
|
39
|
+
onChange,
|
|
40
|
+
items,
|
|
41
|
+
exclusive = false,
|
|
42
|
+
}: Props< TValue > ) => {
|
|
43
|
+
const handleChange = (
|
|
44
|
+
_: React.MouseEvent< HTMLElement >,
|
|
45
|
+
newValue: typeof exclusive extends true ? ExclusiveValue< TValue > : NonExclusiveValue< TValue >
|
|
46
|
+
) => {
|
|
47
|
+
onChange( newValue as never );
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<StyledToggleButtonGroup justify={ justify } value={ value } onChange={ handleChange } exclusive={ exclusive }>
|
|
52
|
+
{ items.map( ( { label, value: buttonValue, icon: Icon } ) => (
|
|
53
|
+
<ToggleButton key={ buttonValue } value={ buttonValue } aria-label={ label } size={ size }>
|
|
54
|
+
<Icon fontSize={ size } />
|
|
55
|
+
</ToggleButton>
|
|
56
|
+
) ) }
|
|
57
|
+
</StyledToggleButtonGroup>
|
|
58
|
+
);
|
|
59
|
+
};
|