@elementor/editor-controls 0.20.0 → 0.24.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 +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +373 -290
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +307 -224
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/components/control-form-label.tsx +6 -0
- package/src/components/control-label.tsx +12 -3
- package/src/components/repeater.tsx +18 -8
- package/src/components/sortable.tsx +6 -6
- package/src/components/text-field-inner-selection.tsx +3 -3
- package/src/controls/background-control/background-control.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-attachment.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-position.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-repeat.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-image-overlay/background-image-overlay-size.tsx +2 -2
- package/src/controls/background-control/background-overlay/background-overlay-repeater-control.tsx +30 -5
- package/src/controls/color-control.tsx +1 -1
- package/src/controls/equal-unequal-sizes-control.tsx +2 -1
- package/src/controls/font-family-control/font-family-control.tsx +2 -0
- package/src/controls/gap-control.tsx +3 -2
- package/src/controls/image-control.tsx +3 -3
- package/src/controls/link-control.tsx +99 -27
- package/src/controls/linked-dimensions-control.tsx +7 -6
- package/src/controls/stroke-control.tsx +2 -2
- package/src/controls/svg-media-control.tsx +2 -2
- package/src/index.ts +2 -1
- package/src/control-adornments/control-label-with-adornments.tsx +0 -15
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useMemo, useState } from 'react';
|
|
3
|
-
import {
|
|
2
|
+
import { type PropsWithChildren, useMemo, useState } from 'react';
|
|
3
|
+
import { getLinkInLinkRestriction, type LinkInLinkRestriction, selectElement } from '@elementor/editor-elements';
|
|
4
4
|
import {
|
|
5
5
|
booleanPropTypeUtil,
|
|
6
6
|
linkPropTypeUtil,
|
|
@@ -9,10 +9,11 @@ import {
|
|
|
9
9
|
stringPropTypeUtil,
|
|
10
10
|
urlPropTypeUtil,
|
|
11
11
|
} from '@elementor/editor-props';
|
|
12
|
+
import { InfoTipCard } from '@elementor/editor-ui';
|
|
12
13
|
import { type HttpResponse, httpService } from '@elementor/http';
|
|
13
|
-
import { MinusIcon, PlusIcon } from '@elementor/icons';
|
|
14
|
+
import { AlertTriangleIcon, MinusIcon, PlusIcon } from '@elementor/icons';
|
|
14
15
|
import { useSessionStorage } from '@elementor/session';
|
|
15
|
-
import { Collapse, Divider, Grid, IconButton, Stack, Switch } from '@elementor/ui';
|
|
16
|
+
import { Box, Collapse, Divider, Grid, IconButton, Infotip, Stack, Switch } from '@elementor/ui';
|
|
16
17
|
import { debounce } from '@elementor/utils';
|
|
17
18
|
import { __ } from '@wordpress/i18n';
|
|
18
19
|
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
type FlatOption,
|
|
25
26
|
isCategorizedOptionPool,
|
|
26
27
|
} from '../components/autocomplete';
|
|
27
|
-
import {
|
|
28
|
+
import { ControlFormLabel } from '../components/control-form-label';
|
|
28
29
|
import ControlActions from '../control-actions/control-actions';
|
|
29
30
|
import { createControl } from '../create-control';
|
|
30
31
|
import { type ControlProps } from '../utils/types';
|
|
@@ -49,11 +50,15 @@ type LinkSessionValue = {
|
|
|
49
50
|
type Response = HttpResponse< { value: FlatOption[] | CategorizedOption[] } >;
|
|
50
51
|
|
|
51
52
|
const SIZE = 'tiny';
|
|
53
|
+
const learnMoreButton = {
|
|
54
|
+
label: __( 'Learn More', 'elementor' ),
|
|
55
|
+
href: 'https://go.elementor.com/element-link-inside-link-infotip',
|
|
56
|
+
};
|
|
52
57
|
|
|
53
58
|
export const LinkControl = createControl( ( props: Props ) => {
|
|
54
59
|
const { value, path, setValue, ...propContext } = useBoundProp( linkPropTypeUtil );
|
|
55
60
|
const [ linkSessionValue, setLinkSessionValue ] = useSessionStorage< LinkSessionValue >( path.join( '/' ) );
|
|
56
|
-
const [
|
|
61
|
+
const [ isActive, setIsActive ] = useState( !! value );
|
|
57
62
|
|
|
58
63
|
const {
|
|
59
64
|
allowCustomValues,
|
|
@@ -63,20 +68,22 @@ export const LinkControl = createControl( ( props: Props ) => {
|
|
|
63
68
|
context: { elementId },
|
|
64
69
|
} = props || {};
|
|
65
70
|
|
|
71
|
+
const [ linkInLinkRestriction, setLinkInLinkRestriction ] = useState( getLinkInLinkRestriction( elementId ) );
|
|
66
72
|
const [ options, setOptions ] = useState< FlatOption[] | CategorizedOption[] >(
|
|
67
73
|
generateFirstLoadedOption( value )
|
|
68
74
|
);
|
|
75
|
+
const shouldDisableAddingLink = ! isActive && linkInLinkRestriction.shouldRestrict;
|
|
69
76
|
|
|
70
77
|
const onEnabledChange = () => {
|
|
71
|
-
|
|
78
|
+
setLinkInLinkRestriction( getLinkInLinkRestriction( elementId ) );
|
|
72
79
|
|
|
73
|
-
if ( shouldRestrict && !
|
|
80
|
+
if ( linkInLinkRestriction.shouldRestrict && ! isActive ) {
|
|
74
81
|
return;
|
|
75
82
|
}
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
setValue(
|
|
79
|
-
setLinkSessionValue( { value, meta: { isEnabled: !
|
|
84
|
+
setIsActive( ( prevState ) => ! prevState );
|
|
85
|
+
setValue( isActive ? null : linkSessionValue?.value ?? null );
|
|
86
|
+
setLinkSessionValue( { value, meta: { isEnabled: ! isActive } } );
|
|
80
87
|
};
|
|
81
88
|
|
|
82
89
|
const onOptionChange = ( newValue: number | null ) => {
|
|
@@ -144,14 +151,17 @@ export const LinkControl = createControl( ( props: Props ) => {
|
|
|
144
151
|
alignItems: 'center',
|
|
145
152
|
} }
|
|
146
153
|
>
|
|
147
|
-
<
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
<ControlFormLabel>{ __( 'Link', 'elementor' ) }</ControlFormLabel>
|
|
155
|
+
<ConditionalInfoTip isVisible={ ! isActive } linkInLinkRestriction={ linkInLinkRestriction }>
|
|
156
|
+
<ToggleIconControl
|
|
157
|
+
disabled={ shouldDisableAddingLink }
|
|
158
|
+
active={ isActive }
|
|
159
|
+
onIconClick={ onEnabledChange }
|
|
160
|
+
label={ __( 'Toggle link', 'elementor' ) }
|
|
161
|
+
/>
|
|
162
|
+
</ConditionalInfoTip>
|
|
153
163
|
</Stack>
|
|
154
|
-
<Collapse in={
|
|
164
|
+
<Collapse in={ isActive } timeout="auto" unmountOnExit>
|
|
155
165
|
<Stack gap={ 1.5 }>
|
|
156
166
|
<PropKeyProvider bind={ 'destination' }>
|
|
157
167
|
<ControlActions>
|
|
@@ -159,7 +169,7 @@ export const LinkControl = createControl( ( props: Props ) => {
|
|
|
159
169
|
options={ options }
|
|
160
170
|
allowCustomValues={ allowCustomValues }
|
|
161
171
|
placeholder={ placeholder }
|
|
162
|
-
value={ value?.destination?.value }
|
|
172
|
+
value={ value?.destination?.value?.settings?.label || value?.destination?.value }
|
|
163
173
|
onOptionChange={ onOptionChange }
|
|
164
174
|
onTextChange={ onTextChange }
|
|
165
175
|
minInputLength={ minInputLength }
|
|
@@ -167,7 +177,7 @@ export const LinkControl = createControl( ( props: Props ) => {
|
|
|
167
177
|
</ControlActions>
|
|
168
178
|
</PropKeyProvider>
|
|
169
179
|
<PropKeyProvider bind={ 'isTargetBlank' }>
|
|
170
|
-
<SwitchControl />
|
|
180
|
+
<SwitchControl disabled={ ! value } />
|
|
171
181
|
</PropKeyProvider>
|
|
172
182
|
</Stack>
|
|
173
183
|
</Collapse>
|
|
@@ -177,34 +187,43 @@ export const LinkControl = createControl( ( props: Props ) => {
|
|
|
177
187
|
} );
|
|
178
188
|
|
|
179
189
|
type ToggleIconControlProps = {
|
|
180
|
-
|
|
190
|
+
disabled: boolean;
|
|
191
|
+
active: boolean;
|
|
181
192
|
onIconClick: () => void;
|
|
182
193
|
label?: string;
|
|
183
194
|
};
|
|
184
195
|
|
|
185
|
-
const ToggleIconControl = ( {
|
|
196
|
+
const ToggleIconControl = ( { disabled, active, onIconClick, label }: ToggleIconControlProps ) => {
|
|
186
197
|
return (
|
|
187
|
-
<IconButton size={ SIZE } onClick={ onIconClick } aria-label={ label }>
|
|
188
|
-
{
|
|
198
|
+
<IconButton size={ SIZE } onClick={ onIconClick } aria-label={ label } disabled={ disabled }>
|
|
199
|
+
{ active ? <MinusIcon fontSize={ SIZE } /> : <PlusIcon fontSize={ SIZE } /> }
|
|
189
200
|
</IconButton>
|
|
190
201
|
);
|
|
191
202
|
};
|
|
192
203
|
|
|
193
204
|
// @TODO Should be refactored in ED-16323
|
|
194
|
-
const SwitchControl = () => {
|
|
205
|
+
const SwitchControl = ( { disabled }: { disabled: boolean } ) => {
|
|
195
206
|
const { value = false, setValue } = useBoundProp( booleanPropTypeUtil );
|
|
196
207
|
|
|
197
208
|
const onClick = () => {
|
|
198
209
|
setValue( ! value );
|
|
199
210
|
};
|
|
200
211
|
|
|
212
|
+
const inputProps = disabled
|
|
213
|
+
? {
|
|
214
|
+
style: {
|
|
215
|
+
opacity: 0,
|
|
216
|
+
},
|
|
217
|
+
}
|
|
218
|
+
: {};
|
|
219
|
+
|
|
201
220
|
return (
|
|
202
221
|
<Grid container alignItems="center" flexWrap="nowrap" justifyContent="space-between">
|
|
203
222
|
<Grid item>
|
|
204
|
-
<
|
|
223
|
+
<ControlFormLabel>{ __( 'Open in a new tab', 'elementor' ) }</ControlFormLabel>
|
|
205
224
|
</Grid>
|
|
206
225
|
<Grid item>
|
|
207
|
-
<Switch checked={ value } onClick={ onClick } />
|
|
226
|
+
<Switch checked={ value } onClick={ onClick } disabled={ disabled } inputProps={ inputProps } />
|
|
208
227
|
</Grid>
|
|
209
228
|
</Grid>
|
|
210
229
|
);
|
|
@@ -248,3 +267,56 @@ function generateFirstLoadedOption( unionValue: LinkPropValue[ 'value' ] | null
|
|
|
248
267
|
]
|
|
249
268
|
: [];
|
|
250
269
|
}
|
|
270
|
+
|
|
271
|
+
interface ConditionalInfoTipType extends PropsWithChildren {
|
|
272
|
+
linkInLinkRestriction: LinkInLinkRestriction;
|
|
273
|
+
isVisible: boolean;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const ConditionalInfoTip: React.FC< ConditionalInfoTipType > = ( { linkInLinkRestriction, isVisible, children } ) => {
|
|
277
|
+
const { shouldRestrict, reason, elementId } = linkInLinkRestriction;
|
|
278
|
+
|
|
279
|
+
const handleTakeMeClick = () => {
|
|
280
|
+
if ( elementId ) {
|
|
281
|
+
selectElement( elementId );
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
return shouldRestrict && isVisible ? (
|
|
286
|
+
<Infotip
|
|
287
|
+
placement="right"
|
|
288
|
+
content={
|
|
289
|
+
<InfoTipCard
|
|
290
|
+
content={ INFOTIP_CONTENT[ reason ] }
|
|
291
|
+
svgIcon={ <AlertTriangleIcon /> }
|
|
292
|
+
learnMoreButton={ learnMoreButton }
|
|
293
|
+
ctaButton={ {
|
|
294
|
+
label: __( 'Take me there', 'elementor' ),
|
|
295
|
+
onClick: handleTakeMeClick,
|
|
296
|
+
} }
|
|
297
|
+
/>
|
|
298
|
+
}
|
|
299
|
+
>
|
|
300
|
+
<Box>{ children }</Box>
|
|
301
|
+
</Infotip>
|
|
302
|
+
) : (
|
|
303
|
+
<>{ children }</>
|
|
304
|
+
);
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const INFOTIP_CONTENT = {
|
|
308
|
+
descendant: (
|
|
309
|
+
<>
|
|
310
|
+
{ __( 'To add a link to this container,', 'elementor' ) }
|
|
311
|
+
<br />
|
|
312
|
+
{ __( 'first remove the link from the elements inside of it.', 'elementor' ) }
|
|
313
|
+
</>
|
|
314
|
+
),
|
|
315
|
+
ancestor: (
|
|
316
|
+
<>
|
|
317
|
+
{ __( 'To add a link to this element,', 'elementor' ) }
|
|
318
|
+
<br />
|
|
319
|
+
{ __( 'first remove the link from its parent container.', 'elementor' ) }
|
|
320
|
+
</>
|
|
321
|
+
),
|
|
322
|
+
};
|
|
@@ -5,6 +5,7 @@ import { Grid, Stack, ToggleButton, Tooltip } from '@elementor/ui';
|
|
|
5
5
|
import { __ } from '@wordpress/i18n';
|
|
6
6
|
|
|
7
7
|
import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
|
|
8
|
+
import { ControlFormLabel } from '../components/control-form-label';
|
|
8
9
|
import { ControlLabel } from '../components/control-label';
|
|
9
10
|
import { createControl } from '../create-control';
|
|
10
11
|
import { type ExtendedValue, SizeControl } from './size-control';
|
|
@@ -72,7 +73,7 @@ export const LinkedDimensionsControl = createControl(
|
|
|
72
73
|
<Stack direction="row" gap={ 2 } flexWrap="nowrap">
|
|
73
74
|
<Grid container gap={ 0.75 } alignItems="center">
|
|
74
75
|
<Grid item xs={ 12 }>
|
|
75
|
-
<
|
|
76
|
+
<ControlFormLabel>{ __( 'Top', 'elementor' ) }</ControlFormLabel>
|
|
76
77
|
</Grid>
|
|
77
78
|
<Grid item xs={ 12 }>
|
|
78
79
|
<Control
|
|
@@ -85,9 +86,9 @@ export const LinkedDimensionsControl = createControl(
|
|
|
85
86
|
</Grid>
|
|
86
87
|
<Grid container gap={ 0.75 } alignItems="center">
|
|
87
88
|
<Grid item xs={ 12 }>
|
|
88
|
-
<
|
|
89
|
+
<ControlFormLabel>
|
|
89
90
|
{ isSiteRtl ? __( 'Left', 'elementor' ) : __( 'Right', 'elementor' ) }
|
|
90
|
-
</
|
|
91
|
+
</ControlFormLabel>
|
|
91
92
|
</Grid>
|
|
92
93
|
<Grid item xs={ 12 }>
|
|
93
94
|
<Control
|
|
@@ -108,7 +109,7 @@ export const LinkedDimensionsControl = createControl(
|
|
|
108
109
|
<Stack direction="row" gap={ 2 } flexWrap="nowrap">
|
|
109
110
|
<Grid container gap={ 0.75 } alignItems="center">
|
|
110
111
|
<Grid item xs={ 12 }>
|
|
111
|
-
<
|
|
112
|
+
<ControlFormLabel>{ __( 'Bottom', 'elementor' ) }</ControlFormLabel>
|
|
112
113
|
</Grid>
|
|
113
114
|
<Grid item xs={ 12 }>
|
|
114
115
|
<Control
|
|
@@ -121,9 +122,9 @@ export const LinkedDimensionsControl = createControl(
|
|
|
121
122
|
</Grid>
|
|
122
123
|
<Grid container gap={ 0.75 } alignItems="center">
|
|
123
124
|
<Grid item xs={ 12 }>
|
|
124
|
-
<
|
|
125
|
+
<ControlFormLabel>
|
|
125
126
|
{ isSiteRtl ? __( 'Right', 'elementor' ) : __( 'Left', 'elementor' ) }
|
|
126
|
-
</
|
|
127
|
+
</ControlFormLabel>
|
|
127
128
|
</Grid>
|
|
128
129
|
<Grid item xs={ 12 }>
|
|
129
130
|
<Control
|
|
@@ -4,7 +4,7 @@ import { Grid } from '@elementor/ui';
|
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
|
|
6
6
|
import { PropKeyProvider, PropProvider, useBoundProp } from '../bound-prop-context';
|
|
7
|
-
import {
|
|
7
|
+
import { ControlFormLabel } from '../components/control-form-label';
|
|
8
8
|
import { SectionContent } from '../components/section-content';
|
|
9
9
|
import { createControl } from '../create-control';
|
|
10
10
|
import { ColorControl } from './color-control';
|
|
@@ -39,7 +39,7 @@ const Control = ( { bind, label, children }: StrokeProps ) => (
|
|
|
39
39
|
<PropKeyProvider bind={ bind }>
|
|
40
40
|
<Grid container gap={ 2 } alignItems="center" flexWrap="nowrap">
|
|
41
41
|
<Grid item xs={ 6 }>
|
|
42
|
-
<
|
|
42
|
+
<ControlFormLabel>{ label }</ControlFormLabel>
|
|
43
43
|
</Grid>
|
|
44
44
|
<Grid item xs={ 6 }>
|
|
45
45
|
{ children }
|
|
@@ -7,7 +7,7 @@ import { type OpenOptions, useWpMediaAttachment, useWpMediaFrame } from '@elemen
|
|
|
7
7
|
import { __ } from '@wordpress/i18n';
|
|
8
8
|
|
|
9
9
|
import { useBoundProp } from '../bound-prop-context';
|
|
10
|
-
import {
|
|
10
|
+
import { ControlFormLabel } from '../components/control-form-label';
|
|
11
11
|
import { EnableUnfilteredModal } from '../components/enable-unfiltered-modal';
|
|
12
12
|
import ControlActions from '../control-actions/control-actions';
|
|
13
13
|
import { createControl } from '../create-control';
|
|
@@ -83,7 +83,7 @@ export const SvgMediaControl = createControl( () => {
|
|
|
83
83
|
return (
|
|
84
84
|
<Stack gap={ 1 }>
|
|
85
85
|
<EnableUnfilteredModal open={ unfilteredModalOpenState } onClose={ onCloseUnfilteredModal } />
|
|
86
|
-
<
|
|
86
|
+
<ControlFormLabel> { __( 'SVG', 'elementor' ) } </ControlFormLabel>
|
|
87
87
|
<ControlActions>
|
|
88
88
|
<StyledCard variant="outlined">
|
|
89
89
|
<StyledCardMediaContainer>
|
package/src/index.ts
CHANGED
|
@@ -19,7 +19,7 @@ export { SvgMediaControl } from './controls/svg-media-control';
|
|
|
19
19
|
export { BackgroundControl } from './controls/background-control/background-control';
|
|
20
20
|
|
|
21
21
|
// components
|
|
22
|
-
export {
|
|
22
|
+
export { ControlFormLabel } from './components/control-form-label';
|
|
23
23
|
export { ControlToggleButtonGroup } from './components/control-toggle-button-group';
|
|
24
24
|
|
|
25
25
|
// types
|
|
@@ -39,5 +39,6 @@ export { ControlActionsProvider, useControlActions } from './control-actions/con
|
|
|
39
39
|
export { useBoundProp, PropProvider, PropKeyProvider } from './bound-prop-context';
|
|
40
40
|
export { ControlAdornmentsProvider } from './control-adornments/control-adornments-context';
|
|
41
41
|
export { ControlAdornments } from './control-adornments/control-adornments';
|
|
42
|
+
|
|
42
43
|
// hooks
|
|
43
44
|
export { useSyncExternalState } from './hooks/use-sync-external-state';
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { type PropsWithChildren } from 'react';
|
|
3
|
-
import { Stack } from '@elementor/ui';
|
|
4
|
-
|
|
5
|
-
import { ControlLabel } from '../components/control-label';
|
|
6
|
-
import { ControlAdornments } from './control-adornments';
|
|
7
|
-
|
|
8
|
-
export const ControlLabelWithAdornments = ( { children }: PropsWithChildren< object > ) => {
|
|
9
|
-
return (
|
|
10
|
-
<Stack direction="row" alignItems="center" justifyItems="start" gap={ 1 }>
|
|
11
|
-
<ControlLabel>{ children }</ControlLabel>
|
|
12
|
-
<ControlAdornments />
|
|
13
|
-
</Stack>
|
|
14
|
-
);
|
|
15
|
-
};
|