@elementor/editor-editing-panel 1.24.0 → 1.28.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 +102 -0
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +448 -309
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +426 -287
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -10
- package/src/components/css-classes/css-class-item.tsx +8 -10
- package/src/components/css-classes/css-class-menu.tsx +60 -12
- package/src/components/css-classes/css-class-selector.tsx +28 -27
- package/src/components/editing-panel-tabs.tsx +1 -8
- package/src/components/multi-combobox.tsx +3 -0
- package/src/components/style-indicator.tsx +23 -0
- package/src/components/style-sections/border-section/border-radius-field.tsx +4 -5
- package/src/components/style-sections/border-section/border-width-field.tsx +2 -3
- package/src/components/style-sections/layout-section/display-field.tsx +34 -28
- package/src/components/style-sections/layout-section/flex-size-field.tsx +28 -18
- package/src/components/style-sections/layout-section/layout-section.tsx +14 -2
- package/src/components/style-sections/typography-section/text-alignment-field.tsx +5 -6
- package/src/components/style-tab.tsx +2 -19
- package/src/contexts/style-context.tsx +2 -2
- package/src/controls-registry/control-type-container.tsx +2 -2
- package/src/controls-registry/styles-field.tsx +9 -2
- package/src/dynamics/dynamic-transformer.ts +61 -0
- package/src/dynamics/errors.ts +6 -0
- package/src/dynamics/init.ts +6 -0
- package/src/dynamics/types.ts +17 -0
- package/src/hooks/use-active-style-def-id.ts +36 -0
- package/src/hooks/use-styles-fields.ts +7 -7
- package/src/index.ts +1 -3
- package/src/init.ts +1 -1
- package/src/styles-inheritance/create-snapshots-manager.ts +16 -9
- package/src/styles-inheritance/create-styles-inheritance.ts +8 -4
- package/src/styles-inheritance/styles-inheritance-indicator.tsx +13 -31
- package/src/styles-inheritance/types.ts +7 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-editing-panel",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,16 +39,17 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "0.18.
|
|
43
|
-
"@elementor/editor-
|
|
42
|
+
"@elementor/editor": "0.18.6",
|
|
43
|
+
"@elementor/editor-canvas": "0.18.0",
|
|
44
|
+
"@elementor/editor-controls": "0.25.0",
|
|
44
45
|
"@elementor/editor-current-user": "0.3.0",
|
|
45
|
-
"@elementor/editor-elements": "0.
|
|
46
|
-
"@elementor/editor-panels": "0.14.
|
|
47
|
-
"@elementor/editor-props": "0.
|
|
48
|
-
"@elementor/editor-responsive": "0.13.
|
|
49
|
-
"@elementor/editor-styles": "0.6.
|
|
50
|
-
"@elementor/editor-styles-repository": "0.8.
|
|
51
|
-
"@elementor/editor-ui": "0.
|
|
46
|
+
"@elementor/editor-elements": "0.8.1",
|
|
47
|
+
"@elementor/editor-panels": "0.14.1",
|
|
48
|
+
"@elementor/editor-props": "0.12.0",
|
|
49
|
+
"@elementor/editor-responsive": "0.13.4",
|
|
50
|
+
"@elementor/editor-styles": "0.6.6",
|
|
51
|
+
"@elementor/editor-styles-repository": "0.8.4",
|
|
52
|
+
"@elementor/editor-ui": "0.7.1",
|
|
52
53
|
"@elementor/editor-v1-adapters": "0.11.0",
|
|
53
54
|
"@elementor/icons": "1.37.0",
|
|
54
55
|
"@elementor/locations": "0.7.7",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type ReactElement, useState } from 'react';
|
|
3
|
-
import { stylesRepository } from '@elementor/editor-styles-repository';
|
|
3
|
+
import { stylesRepository, validateStyleLabel } from '@elementor/editor-styles-repository';
|
|
4
4
|
import { EditableField, EllipsisWithTooltip, useEditable } from '@elementor/editor-ui';
|
|
5
5
|
import { DotsVerticalIcon } from '@elementor/icons';
|
|
6
6
|
import {
|
|
@@ -21,8 +21,8 @@ import { CssClassMenu } from './css-class-menu';
|
|
|
21
21
|
|
|
22
22
|
type CssClassItemProps = {
|
|
23
23
|
id: string | null;
|
|
24
|
+
provider: string | null;
|
|
24
25
|
label: string;
|
|
25
|
-
provider: string;
|
|
26
26
|
isActive: boolean;
|
|
27
27
|
color: ChipOwnProps[ 'color' ];
|
|
28
28
|
icon: ReactElement | null;
|
|
@@ -36,8 +36,8 @@ const CHIP_SIZE = 'tiny';
|
|
|
36
36
|
|
|
37
37
|
export function CssClassItem( {
|
|
38
38
|
id,
|
|
39
|
-
label,
|
|
40
39
|
provider,
|
|
40
|
+
label,
|
|
41
41
|
isActive,
|
|
42
42
|
color: colorProp,
|
|
43
43
|
icon,
|
|
@@ -64,7 +64,7 @@ export function CssClassItem( {
|
|
|
64
64
|
|
|
65
65
|
const color = error ? 'error' : colorProp;
|
|
66
66
|
|
|
67
|
-
const providerActions = stylesRepository.getProviderByKey( provider )?.actions;
|
|
67
|
+
const providerActions = provider ? stylesRepository.getProviderByKey( provider )?.actions : null;
|
|
68
68
|
const allowRename = Boolean( providerActions?.update );
|
|
69
69
|
|
|
70
70
|
const isShowingState = isActive && meta.state;
|
|
@@ -153,13 +153,11 @@ export function CssClassItem( {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
const validateLabel = ( newLabel: string ) => {
|
|
156
|
-
|
|
157
|
-
return __( 'Format is not valid', 'elementor' );
|
|
158
|
-
}
|
|
156
|
+
const result = validateStyleLabel( newLabel );
|
|
159
157
|
|
|
160
|
-
if (
|
|
161
|
-
return
|
|
158
|
+
if ( result.isValid ) {
|
|
159
|
+
return null;
|
|
162
160
|
}
|
|
163
161
|
|
|
164
|
-
return
|
|
162
|
+
return result.error;
|
|
165
163
|
};
|
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { type StyleDefinitionState } from '@elementor/editor-styles';
|
|
3
|
-
import { stylesRepository } from '@elementor/editor-styles-repository';
|
|
3
|
+
import { isElementsStylesProvider, stylesRepository } from '@elementor/editor-styles-repository';
|
|
4
4
|
import { MenuListItem } from '@elementor/editor-ui';
|
|
5
|
-
import { bindMenu, Divider, Menu, MenuSubheader, type PopupState } from '@elementor/ui';
|
|
5
|
+
import { bindMenu, Divider, Menu, MenuSubheader, type PopupState, Stack } from '@elementor/ui';
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
7
|
|
|
8
8
|
import { useStyle } from '../../contexts/style-context';
|
|
9
9
|
import { useUnapplyClass } from '../../hooks/use-unapply-class';
|
|
10
|
+
import { type StyleDefinitionStateWithNormal } from '../../styles-inheritance/types';
|
|
11
|
+
import { StyleIndicator, type StyleIndicatorVariant } from '../style-indicator';
|
|
10
12
|
|
|
11
13
|
const STATES: NonNullable< StyleDefinitionState >[] = [ 'hover', 'focus', 'active' ];
|
|
12
14
|
|
|
13
15
|
type CssClassMenuProps = {
|
|
14
16
|
styleId: string | null;
|
|
15
|
-
provider: string;
|
|
17
|
+
provider: string | null;
|
|
16
18
|
popupState: PopupState;
|
|
17
19
|
handleRename: () => void;
|
|
18
20
|
anchorEl: HTMLElement | null;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
export function CssClassMenu( { styleId, provider, popupState, handleRename, anchorEl }: CssClassMenuProps ) {
|
|
24
|
+
const styledStates = useStyledStates( styleId );
|
|
25
|
+
|
|
26
|
+
const indicatorVariant = ! provider || isElementsStylesProvider( provider ) ? 'local' : 'global';
|
|
27
|
+
|
|
22
28
|
const handleKeyDown = ( e: React.KeyboardEvent< HTMLElement > ) => {
|
|
23
29
|
e.stopPropagation();
|
|
24
30
|
};
|
|
25
31
|
|
|
26
32
|
return (
|
|
27
33
|
<Menu
|
|
28
|
-
MenuListProps={ { dense: true } }
|
|
34
|
+
MenuListProps={ { dense: true, sx: { minWidth: '160px' } } }
|
|
29
35
|
{ ...bindMenu( popupState ) }
|
|
30
36
|
anchorEl={ anchorEl }
|
|
31
37
|
anchorOrigin={ {
|
|
@@ -37,34 +43,62 @@ export function CssClassMenu( { styleId, provider, popupState, handleRename, anc
|
|
|
37
43
|
vertical: -4,
|
|
38
44
|
} }
|
|
39
45
|
onKeyDown={ handleKeyDown }
|
|
46
|
+
// Workaround for focus-visible issue.
|
|
47
|
+
disableAutoFocusItem
|
|
40
48
|
>
|
|
41
49
|
{ /* It has to be an array since MUI menu doesn't accept a Fragment as a child, and wrapping the items with an HTML element disrupts keyboard navigation */ }
|
|
42
50
|
{ getMenuItemsByProvider( { provider, styleId, handleRename, closeMenu: popupState.close } ) }
|
|
43
51
|
<MenuSubheader sx={ { typography: 'caption', color: 'text.secondary', pb: 0.5, pt: 1 } }>
|
|
44
|
-
{ __( '
|
|
52
|
+
{ __( 'States', 'elementor' ) }
|
|
45
53
|
</MenuSubheader>
|
|
46
|
-
<StateMenuItem
|
|
54
|
+
<StateMenuItem
|
|
55
|
+
key="normal"
|
|
56
|
+
state={ null }
|
|
57
|
+
styleId={ styleId }
|
|
58
|
+
closeMenu={ popupState.close }
|
|
59
|
+
isStyled={ styledStates.normal }
|
|
60
|
+
indicatorVariant={ indicatorVariant }
|
|
61
|
+
/>
|
|
47
62
|
{ STATES.map( ( state ) => {
|
|
48
63
|
return (
|
|
49
|
-
<StateMenuItem
|
|
64
|
+
<StateMenuItem
|
|
65
|
+
key={ state }
|
|
66
|
+
state={ state }
|
|
67
|
+
styleId={ styleId }
|
|
68
|
+
closeMenu={ popupState.close }
|
|
69
|
+
isStyled={ styledStates[ state ] }
|
|
70
|
+
indicatorVariant={ indicatorVariant }
|
|
71
|
+
/>
|
|
50
72
|
);
|
|
51
73
|
} ) }
|
|
52
74
|
</Menu>
|
|
53
75
|
);
|
|
54
76
|
}
|
|
55
77
|
|
|
78
|
+
function useStyledStates( styleId: string | null ): Partial< Record< StyleDefinitionStateWithNormal, true > > {
|
|
79
|
+
const { meta } = useStyle();
|
|
80
|
+
|
|
81
|
+
const styleDef = stylesRepository.all().find( ( style ) => style.id === styleId );
|
|
82
|
+
|
|
83
|
+
return Object.fromEntries(
|
|
84
|
+
styleDef?.variants
|
|
85
|
+
.filter( ( variant ) => meta.breakpoint === variant.meta.breakpoint )
|
|
86
|
+
.map( ( variant ) => [ variant.meta.state ?? 'normal', true ] ) ?? []
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
56
90
|
function getMenuItemsByProvider( {
|
|
57
91
|
provider,
|
|
58
92
|
styleId,
|
|
59
93
|
handleRename,
|
|
60
94
|
closeMenu,
|
|
61
95
|
}: {
|
|
62
|
-
provider: string;
|
|
96
|
+
provider: string | null;
|
|
63
97
|
styleId: string | null;
|
|
64
98
|
handleRename: () => void;
|
|
65
99
|
closeMenu: () => void;
|
|
66
100
|
} ) {
|
|
67
|
-
if ( ! styleId ) {
|
|
101
|
+
if ( ! styleId || ! provider ) {
|
|
68
102
|
return [];
|
|
69
103
|
}
|
|
70
104
|
|
|
@@ -82,7 +116,7 @@ function getMenuItemsByProvider( {
|
|
|
82
116
|
actions.unshift(
|
|
83
117
|
<MenuSubheader
|
|
84
118
|
key="provider-label"
|
|
85
|
-
sx={ { typography: 'caption', color: 'text.secondary', pb: 0.5, pt: 1 } }
|
|
119
|
+
sx={ { typography: 'caption', color: 'text.secondary', pb: 0.5, pt: 1, textTransform: 'capitalize' } }
|
|
86
120
|
>
|
|
87
121
|
{ providerInstance?.labels?.singular }
|
|
88
122
|
</MenuSubheader>
|
|
@@ -97,9 +131,18 @@ type StateMenuItemProps = {
|
|
|
97
131
|
state: StyleDefinitionState;
|
|
98
132
|
styleId: string | null;
|
|
99
133
|
closeMenu: () => void;
|
|
134
|
+
isStyled?: boolean;
|
|
135
|
+
indicatorVariant: StyleIndicatorVariant;
|
|
100
136
|
};
|
|
101
137
|
|
|
102
|
-
function StateMenuItem( {
|
|
138
|
+
function StateMenuItem( {
|
|
139
|
+
state,
|
|
140
|
+
styleId,
|
|
141
|
+
closeMenu,
|
|
142
|
+
isStyled = false,
|
|
143
|
+
indicatorVariant,
|
|
144
|
+
...props
|
|
145
|
+
}: StateMenuItemProps ) {
|
|
103
146
|
const { id: activeId, setId: setActiveId, setMetaState: setActiveMetaState, meta } = useStyle();
|
|
104
147
|
const { state: activeState } = meta;
|
|
105
148
|
|
|
@@ -121,7 +164,12 @@ function StateMenuItem( { state, styleId, closeMenu, ...props }: StateMenuItemPr
|
|
|
121
164
|
closeMenu();
|
|
122
165
|
} }
|
|
123
166
|
>
|
|
124
|
-
{
|
|
167
|
+
<Stack gap={ 0.75 } direction="row" alignItems="center">
|
|
168
|
+
{ isStyled && (
|
|
169
|
+
<StyleIndicator aria-label={ __( 'Has style', 'elementor' ) } variant={ indicatorVariant } />
|
|
170
|
+
) }
|
|
171
|
+
{ state ?? 'normal' }
|
|
172
|
+
</Stack>
|
|
125
173
|
</MenuListItem>
|
|
126
174
|
);
|
|
127
175
|
}
|
|
@@ -4,16 +4,17 @@ import { getElementSetting, updateElementSettings, useElementSetting } from '@el
|
|
|
4
4
|
import { classesPropTypeUtil, type ClassesPropValue } from '@elementor/editor-props';
|
|
5
5
|
import { type StyleDefinitionID } from '@elementor/editor-styles';
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
isElementsStylesProvider,
|
|
8
8
|
type StylesProvider,
|
|
9
9
|
stylesRepository,
|
|
10
10
|
type UpdateActionPayload,
|
|
11
11
|
useCreateActionsByProvider,
|
|
12
12
|
useProviders,
|
|
13
|
+
validateStyleLabel,
|
|
13
14
|
} from '@elementor/editor-styles-repository';
|
|
14
15
|
import { MapPinIcon } from '@elementor/icons';
|
|
15
16
|
import { createLocation } from '@elementor/locations';
|
|
16
|
-
import { Chip,
|
|
17
|
+
import { Chip, FormLabel, Stack } from '@elementor/ui';
|
|
17
18
|
import { __ } from '@wordpress/i18n';
|
|
18
19
|
|
|
19
20
|
import { useClassesProp } from '../../contexts/classes-prop-context';
|
|
@@ -28,7 +29,7 @@ const TAGS_LIMIT = 50;
|
|
|
28
29
|
type StyleDefOption = Option & {
|
|
29
30
|
color: 'accent' | 'global';
|
|
30
31
|
icon: ReactElement | null;
|
|
31
|
-
provider: string;
|
|
32
|
+
provider: string | null;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
const EMPTY_OPTION = {
|
|
@@ -37,7 +38,7 @@ const EMPTY_OPTION = {
|
|
|
37
38
|
fixed: true,
|
|
38
39
|
color: 'accent',
|
|
39
40
|
icon: <MapPinIcon />,
|
|
40
|
-
provider:
|
|
41
|
+
provider: null,
|
|
41
42
|
} satisfies StyleDefOption;
|
|
42
43
|
|
|
43
44
|
export const { Slot: ClassSelectorActionsSlot, inject: injectIntoClassSelectorActions } = createLocation();
|
|
@@ -60,12 +61,14 @@ export function CssClassSelector() {
|
|
|
60
61
|
const applied = useAppliedOptions( options, appliedIds );
|
|
61
62
|
const active = applied.find( ( option ) => option.value === activeId ) ?? EMPTY_OPTION;
|
|
62
63
|
|
|
64
|
+
const showPlaceholder = applied.every( ( { fixed } ) => fixed );
|
|
65
|
+
|
|
63
66
|
return (
|
|
64
|
-
<Stack
|
|
67
|
+
<Stack p={ 2 }>
|
|
65
68
|
<Stack direction="row" gap={ 1 } alignItems="center" justifyContent="space-between">
|
|
66
|
-
<
|
|
67
|
-
{ __( '
|
|
68
|
-
</
|
|
69
|
+
<FormLabel htmlFor={ ID } size="small">
|
|
70
|
+
{ __( 'Classes', 'elementor' ) }
|
|
71
|
+
</FormLabel>
|
|
69
72
|
<Stack direction="row" gap={ 1 }>
|
|
70
73
|
<ClassSelectorActionsSlot />
|
|
71
74
|
</Stack>
|
|
@@ -73,6 +76,7 @@ export function CssClassSelector() {
|
|
|
73
76
|
<MultiCombobox
|
|
74
77
|
id={ ID }
|
|
75
78
|
size="tiny"
|
|
79
|
+
placeholder={ showPlaceholder ? __( 'Type to search/add global classes', 'elementor' ) : undefined }
|
|
76
80
|
options={ options }
|
|
77
81
|
selected={ applied }
|
|
78
82
|
onSelect={ handleApply }
|
|
@@ -114,7 +118,11 @@ export function CssClassSelector() {
|
|
|
114
118
|
);
|
|
115
119
|
}
|
|
116
120
|
|
|
117
|
-
const updateClassByProvider = ( provider: string, data: UpdateActionPayload ) => {
|
|
121
|
+
const updateClassByProvider = ( provider: string | null, data: UpdateActionPayload ) => {
|
|
122
|
+
if ( ! provider ) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
118
126
|
const providerInstance = stylesRepository.getProviderByKey( provider );
|
|
119
127
|
|
|
120
128
|
if ( ! providerInstance ) {
|
|
@@ -132,8 +140,8 @@ function useOptions() {
|
|
|
132
140
|
return useProviders()
|
|
133
141
|
.filter( isProviderEditable )
|
|
134
142
|
.flatMap< StyleDefOption >( ( provider ) => {
|
|
135
|
-
const isElements = provider.
|
|
136
|
-
const styleDefs = provider.actions.
|
|
143
|
+
const isElements = isElementsStylesProvider( provider.getKey() );
|
|
144
|
+
const styleDefs = provider.actions.all( { elementId: element.id } );
|
|
137
145
|
|
|
138
146
|
// Add empty local option for elements, as fallback.
|
|
139
147
|
if ( isElements && styleDefs.length === 0 ) {
|
|
@@ -147,8 +155,9 @@ function useOptions() {
|
|
|
147
155
|
fixed: isElements,
|
|
148
156
|
color: isElements ? 'accent' : 'global',
|
|
149
157
|
icon: isElements ? <MapPinIcon /> : null,
|
|
150
|
-
provider: provider.
|
|
151
|
-
|
|
158
|
+
provider: provider.getKey(),
|
|
159
|
+
// translators: %s is the plural label of the provider (e.g "Existing classes").
|
|
160
|
+
group: __( 'Existing %s', 'elementor' ).replace( '%s', provider.labels?.plural ?? '' ),
|
|
152
161
|
};
|
|
153
162
|
} );
|
|
154
163
|
} );
|
|
@@ -164,10 +173,10 @@ function useCreateActions( {
|
|
|
164
173
|
return useCreateActionsByProvider().map( ( [ provider, create ] ): Action< StyleDefOption > => {
|
|
165
174
|
return {
|
|
166
175
|
// translators: %s is the label of the new class.
|
|
167
|
-
label: ( value ) => __( 'Create
|
|
168
|
-
// translators: %s is the singular label of css class provider (e.g "
|
|
169
|
-
group: __( 'Create
|
|
170
|
-
condition: ( _, inputValue ) =>
|
|
176
|
+
label: ( value ) => __( 'Create "%s"', 'elementor' ).replace( '%s', value ),
|
|
177
|
+
// translators: %s is the singular label of css class provider (e.g "CSS Class").
|
|
178
|
+
group: __( 'Create a new %s', 'elementor' ).replace( '%s', provider.labels?.singular ?? '' ),
|
|
179
|
+
condition: ( _, inputValue ) => validateStyleLabel( inputValue ).isValid && ! hasReachedLimit( provider ),
|
|
171
180
|
apply: ( label ) => {
|
|
172
181
|
const createdId = create( label );
|
|
173
182
|
|
|
@@ -183,22 +192,14 @@ function useCreateActions( {
|
|
|
183
192
|
}
|
|
184
193
|
|
|
185
194
|
function hasReachedLimit( provider: StylesProvider ) {
|
|
186
|
-
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return provider.actions.get().length >= provider.limit;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function isLabelValid( newLabel: string ) {
|
|
194
|
-
return stylesRepository.isLabelValid( newLabel ) && ! stylesRepository.isLabelExist( newLabel );
|
|
195
|
+
return provider.actions.all().length >= provider.limit;
|
|
195
196
|
}
|
|
196
197
|
|
|
197
198
|
function useAppliedOptions( options: StyleDefOption[], appliedIds: StyleDefinitionID[] ) {
|
|
198
199
|
const applied = options.filter( ( option ) => option.value && appliedIds.includes( option.value ) );
|
|
199
200
|
|
|
200
201
|
const hasElementsProviderStyleApplied = applied.some(
|
|
201
|
-
( option ) => option.provider
|
|
202
|
+
( option ) => option.provider && isElementsStylesProvider( option.provider )
|
|
202
203
|
);
|
|
203
204
|
|
|
204
205
|
if ( ! hasElementsProviderStyleApplied ) {
|
|
@@ -19,14 +19,7 @@ export const EditingPanelTabs = () => {
|
|
|
19
19
|
// Reference: https://react.dev/learn/preserving-and-resetting-state#resetting-a-form-with-a-key
|
|
20
20
|
<Fragment key={ element.id }>
|
|
21
21
|
<Stack direction="column" sx={ { width: '100%' } }>
|
|
22
|
-
<Tabs
|
|
23
|
-
variant="fullWidth"
|
|
24
|
-
indicatorColor="secondary"
|
|
25
|
-
textColor="inherit"
|
|
26
|
-
size="small"
|
|
27
|
-
sx={ { mt: 0.5 } }
|
|
28
|
-
{ ...getTabsProps() }
|
|
29
|
-
>
|
|
22
|
+
<Tabs variant="fullWidth" size="small" sx={ { mt: 0.5 } } { ...getTabsProps() }>
|
|
30
23
|
<Tab label={ __( 'General', 'elementor' ) } { ...getTabProps( 'settings' ) } />
|
|
31
24
|
<Tab label={ __( 'Style', 'elementor' ) } { ...getTabProps( 'style' ) } />
|
|
32
25
|
</Tabs>
|
|
@@ -39,6 +39,7 @@ type Props< TOption extends Option > = Omit<
|
|
|
39
39
|
selected: TOption[];
|
|
40
40
|
options: TOption[];
|
|
41
41
|
onSelect?: ( value: TOption[] ) => void;
|
|
42
|
+
placeholder?: string;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
export function MultiCombobox< TOption extends Option >( {
|
|
@@ -46,6 +47,7 @@ export function MultiCombobox< TOption extends Option >( {
|
|
|
46
47
|
selected,
|
|
47
48
|
options,
|
|
48
49
|
onSelect,
|
|
50
|
+
placeholder,
|
|
49
51
|
...props
|
|
50
52
|
}: Props< TOption > ) {
|
|
51
53
|
const filter = useFilterOptions< TOption >();
|
|
@@ -67,6 +69,7 @@ export function MultiCombobox< TOption extends Option >( {
|
|
|
67
69
|
renderInput={ ( params ) => (
|
|
68
70
|
<TextField
|
|
69
71
|
{ ...params }
|
|
72
|
+
placeholder={ placeholder }
|
|
70
73
|
sx={ ( theme: Theme ) => ( {
|
|
71
74
|
'.MuiAutocomplete-inputRoot.MuiInputBase-adornedStart': {
|
|
72
75
|
paddingLeft: theme.spacing( 0.25 ),
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { styled } from '@elementor/ui';
|
|
2
|
+
|
|
3
|
+
export type StyleIndicatorVariant = 'overridden' | 'local' | 'global';
|
|
4
|
+
|
|
5
|
+
export const StyleIndicator = styled( 'div', {
|
|
6
|
+
shouldForwardProp: ( prop ) => prop !== 'variant',
|
|
7
|
+
} )< { variant?: StyleIndicatorVariant } >`
|
|
8
|
+
width: 5px;
|
|
9
|
+
height: 5px;
|
|
10
|
+
border-radius: 50%;
|
|
11
|
+
background-color: ${ ( { theme, variant } ) => {
|
|
12
|
+
switch ( variant ) {
|
|
13
|
+
case 'overridden':
|
|
14
|
+
return theme.palette.warning.light;
|
|
15
|
+
case 'global':
|
|
16
|
+
return theme.palette.global.dark;
|
|
17
|
+
case 'local':
|
|
18
|
+
return theme.palette.accent.main;
|
|
19
|
+
default:
|
|
20
|
+
return theme.palette.text.disabled;
|
|
21
|
+
}
|
|
22
|
+
} };
|
|
23
|
+
`;
|
|
@@ -13,7 +13,6 @@ import { __ } from '@wordpress/i18n';
|
|
|
13
13
|
|
|
14
14
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
15
15
|
import { useDirection } from '../../../hooks/use-direction';
|
|
16
|
-
import { RotatedIcon } from '../layout-section/utils/rotated-icon';
|
|
17
16
|
|
|
18
17
|
const StartStartIcon = withDirection( RadiusTopLeftIcon );
|
|
19
18
|
const StartEndIcon = withDirection( RadiusTopRightIcon );
|
|
@@ -32,22 +31,22 @@ const getEndEndLabel = ( isSiteRtl: boolean ) =>
|
|
|
32
31
|
const getCorners = ( isSiteRtl: boolean ): EqualUnequalItems => [
|
|
33
32
|
{
|
|
34
33
|
label: getStartStartLabel( isSiteRtl ),
|
|
35
|
-
icon: <
|
|
34
|
+
icon: <StartStartIcon fontSize={ 'tiny' } />,
|
|
36
35
|
bind: 'start-start',
|
|
37
36
|
},
|
|
38
37
|
{
|
|
39
38
|
label: getStartEndLabel( isSiteRtl ),
|
|
40
|
-
icon: <
|
|
39
|
+
icon: <StartEndIcon fontSize={ 'tiny' } />,
|
|
41
40
|
bind: 'start-end',
|
|
42
41
|
},
|
|
43
42
|
{
|
|
44
43
|
label: getEndStartLabel( isSiteRtl ),
|
|
45
|
-
icon: <
|
|
44
|
+
icon: <EndStartIcon fontSize={ 'tiny' } />,
|
|
46
45
|
bind: 'end-start',
|
|
47
46
|
},
|
|
48
47
|
{
|
|
49
48
|
label: getEndEndLabel( isSiteRtl ),
|
|
50
|
-
icon: <
|
|
49
|
+
icon: <EndEndIcon fontSize={ 'tiny' } />,
|
|
51
50
|
bind: 'end-end',
|
|
52
51
|
},
|
|
53
52
|
];
|
|
@@ -7,7 +7,6 @@ import { __ } from '@wordpress/i18n';
|
|
|
7
7
|
|
|
8
8
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
9
9
|
import { useDirection } from '../../../hooks/use-direction';
|
|
10
|
-
import { RotatedIcon } from '../layout-section/utils/rotated-icon';
|
|
11
10
|
|
|
12
11
|
const InlineStartIcon = withDirection( SideRightIcon );
|
|
13
12
|
const InlineEndIcon = withDirection( SideLeftIcon );
|
|
@@ -20,7 +19,7 @@ const getEdges = ( isSiteRtl: boolean ): EqualUnequalItems => [
|
|
|
20
19
|
},
|
|
21
20
|
{
|
|
22
21
|
label: isSiteRtl ? __( 'Left', 'elementor' ) : __( 'Right', 'elementor' ),
|
|
23
|
-
icon: <
|
|
22
|
+
icon: <InlineStartIcon fontSize={ 'tiny' } />,
|
|
24
23
|
bind: 'inline-end',
|
|
25
24
|
},
|
|
26
25
|
{
|
|
@@ -30,7 +29,7 @@ const getEdges = ( isSiteRtl: boolean ): EqualUnequalItems => [
|
|
|
30
29
|
},
|
|
31
30
|
{
|
|
32
31
|
label: isSiteRtl ? __( 'Right', 'elementor' ) : __( 'Left', 'elementor' ),
|
|
33
|
-
icon: <
|
|
32
|
+
icon: <InlineEndIcon fontSize={ 'tiny' } />,
|
|
34
33
|
bind: 'inline-start',
|
|
35
34
|
},
|
|
36
35
|
];
|
|
@@ -3,45 +3,51 @@ import { type ToggleButtonGroupItem, ToggleControl } from '@elementor/editor-con
|
|
|
3
3
|
import { Stack } from '@elementor/ui';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
|
|
6
|
+
import { useStylesInheritanceField } from '../../../contexts/styles-inheritance-context';
|
|
6
7
|
import { StylesField } from '../../../controls-registry/styles-field';
|
|
7
8
|
import { ControlLabel } from '../../control-label';
|
|
8
9
|
|
|
9
10
|
type Displays = 'block' | 'flex' | 'inline-block' | 'inline-flex';
|
|
10
11
|
|
|
12
|
+
const displayFieldOptions: ToggleButtonGroupItem< Displays >[] = [
|
|
13
|
+
{
|
|
14
|
+
value: 'block',
|
|
15
|
+
renderContent: () => __( 'Block', 'elementor' ),
|
|
16
|
+
label: __( 'Block', 'elementor' ),
|
|
17
|
+
showTooltip: true,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
value: 'flex',
|
|
21
|
+
renderContent: () => __( 'Flex', 'elementor' ),
|
|
22
|
+
label: __( 'Flex', 'elementor' ),
|
|
23
|
+
showTooltip: true,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
value: 'inline-block',
|
|
27
|
+
renderContent: () => __( 'In-blk', 'elementor' ),
|
|
28
|
+
label: __( 'Inline-block', 'elementor' ),
|
|
29
|
+
showTooltip: true,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
value: 'inline-flex',
|
|
33
|
+
renderContent: () => __( 'In-flx', 'elementor' ),
|
|
34
|
+
label: __( 'Inline-flex', 'elementor' ),
|
|
35
|
+
showTooltip: true,
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
11
39
|
export const DisplayField = () => {
|
|
12
|
-
const
|
|
13
|
-
{
|
|
14
|
-
value: 'block',
|
|
15
|
-
renderContent: () => __( 'Block', 'elementor' ),
|
|
16
|
-
label: __( 'Block', 'elementor' ),
|
|
17
|
-
showTooltip: true,
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
value: 'flex',
|
|
21
|
-
renderContent: () => __( 'Flex', 'elementor' ),
|
|
22
|
-
label: __( 'Flex', 'elementor' ),
|
|
23
|
-
showTooltip: true,
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
value: 'inline-block',
|
|
27
|
-
renderContent: () => __( 'In-blk', 'elementor' ),
|
|
28
|
-
label: __( 'Inline-block', 'elementor' ),
|
|
29
|
-
showTooltip: true,
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
value: 'inline-flex',
|
|
33
|
-
renderContent: () => __( 'In-flx', 'elementor' ),
|
|
34
|
-
label: __( 'Inline-flex', 'elementor' ),
|
|
35
|
-
showTooltip: true,
|
|
36
|
-
},
|
|
37
|
-
];
|
|
40
|
+
const placeholder = useDisplayPlaceholderValue();
|
|
38
41
|
|
|
39
42
|
return (
|
|
40
|
-
<StylesField bind="display">
|
|
43
|
+
<StylesField bind="display" placeholder={ placeholder }>
|
|
41
44
|
<Stack gap={ 0.75 }>
|
|
42
45
|
<ControlLabel>{ __( 'Display', 'elementor' ) }</ControlLabel>
|
|
43
|
-
<ToggleControl options={
|
|
46
|
+
<ToggleControl options={ displayFieldOptions } fullWidth={ true } />
|
|
44
47
|
</Stack>
|
|
45
48
|
</StylesField>
|
|
46
49
|
);
|
|
47
50
|
};
|
|
51
|
+
|
|
52
|
+
// TODO - placing this logic deliberately here, and will be removed once applied automatically to all style fields as part of ED-18491
|
|
53
|
+
export const useDisplayPlaceholderValue = () => useStylesInheritanceField( 'display' )[ 0 ]?.value ?? undefined;
|