@elementor/editor-editing-panel 1.42.0 → 1.43.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-editing-panel",
3
- "version": "1.42.0",
3
+ "version": "1.43.0",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -41,7 +41,7 @@
41
41
  "dependencies": {
42
42
  "@elementor/editor": "0.19.4",
43
43
  "@elementor/editor-canvas": "0.22.2",
44
- "@elementor/editor-controls": "0.34.1",
44
+ "@elementor/editor-controls": "0.34.2",
45
45
  "@elementor/editor-current-user": "0.5.0",
46
46
  "@elementor/editor-documents": "0.13.6",
47
47
  "@elementor/editor-elements": "0.8.4",
@@ -50,7 +50,7 @@
50
50
  "@elementor/editor-responsive": "0.13.5",
51
51
  "@elementor/editor-styles": "0.6.8",
52
52
  "@elementor/editor-styles-repository": "0.10.1",
53
- "@elementor/editor-ui": "0.10.0",
53
+ "@elementor/editor-ui": "0.10.1",
54
54
  "@elementor/editor-v1-adapters": "0.12.0",
55
55
  "@elementor/icons": "1.44.0",
56
56
  "@elementor/locations": "0.8.0",
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { type ReactElement, useState } from 'react';
3
- import { stylesRepository, validateStyleLabel } from '@elementor/editor-styles-repository';
3
+ import { stylesRepository, useUserStylesCapability, 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 {
@@ -46,6 +46,8 @@ export function CssClassItem( props: CssClassItemProps ) {
46
46
  const [ chipRef, setChipRef ] = useState< HTMLElement | null >( null );
47
47
  const { onDelete, ...chipGroupProps } = chipProps;
48
48
 
49
+ const { userCan } = useUserStylesCapability();
50
+
49
51
  const {
50
52
  ref,
51
53
  isEditing,
@@ -62,7 +64,7 @@ export function CssClassItem( props: CssClassItemProps ) {
62
64
  const color = error ? 'error' : colorProp;
63
65
 
64
66
  const providerActions = provider ? stylesRepository.getProviderByKey( provider )?.actions : null;
65
- const allowRename = Boolean( providerActions?.update );
67
+ const allowRename = Boolean( providerActions?.update ) && userCan( provider ?? '' )?.update;
66
68
 
67
69
  const isShowingState = isActive && meta.state;
68
70
 
@@ -133,12 +133,12 @@ function StateMenuItem( { state, closeMenu, ...props }: StateMenuItemProps ) {
133
133
 
134
134
  const modifiedStates = useModifiedStates( styleId );
135
135
 
136
- const isUpdateAllowed = userCan( provider ?? '' ).updateProps;
136
+ const isUpdateAllowed = ! state || userCan( provider ?? '' ).updateProps;
137
137
 
138
138
  const indicatorVariant = ! provider || isElementsStylesProvider( provider ) ? 'local' : 'global';
139
139
 
140
140
  const isStyled = modifiedStates[ state ?? 'normal' ] ?? false;
141
- const disabled = isUpdateAllowed ? false : ! isStyled;
141
+ const disabled = ! isUpdateAllowed && ! isStyled;
142
142
  const isActive = styleId === activeId;
143
143
  const isSelected = state === activeState && isActive;
144
144
 
@@ -160,7 +160,7 @@ function StateMenuItem( { state, closeMenu, ...props }: StateMenuItemProps ) {
160
160
  >
161
161
  <MenuItemInfotip
162
162
  showInfoTip={ disabled }
163
- content={ __( 'With your role as an editor, you can only use existing states.', 'elementor' ) }
163
+ content={ __( 'With your current role, you can only use existing states.', 'elementor' ) }
164
164
  >
165
165
  <Stack gap={ 0.75 } direction="row" alignItems="center">
166
166
  { isStyled && (
@@ -211,7 +211,7 @@ function RenameClassMenuItem( { closeMenu }: { closeMenu: () => void } ) {
211
211
  <MenuItemInfotip
212
212
  showInfoTip={ ! isAllowed }
213
213
  content={ __(
214
- 'With your role as an editor, you can use existing classes but can’t modify them.',
214
+ 'With your current role, you can use existing classes but can’t modify them.',
215
215
  'elementor'
216
216
  ) }
217
217
  >
@@ -1,18 +1,17 @@
1
1
  import * as React from 'react';
2
2
  import { type ReactElement, useRef, useState } from 'react';
3
- import { getElementSetting, updateElementSettings, useElementSetting } from '@elementor/editor-elements';
4
- import { classesPropTypeUtil, type ClassesPropValue } from '@elementor/editor-props';
5
- import { type StyleDefinitionID } from '@elementor/editor-styles';
3
+ import { useElementSetting } from '@elementor/editor-elements';
4
+ import { type ClassesPropValue } from '@elementor/editor-props';
6
5
  import {
7
6
  isElementsStylesProvider,
8
7
  type StylesProvider,
9
8
  stylesRepository,
10
9
  type UpdateActionPayload,
11
- useGetStylesRepositoryCreateAction,
12
10
  useProviders,
11
+ useUserStylesCapability,
13
12
  validateStyleLabel,
14
13
  } from '@elementor/editor-styles-repository';
15
- import { WarningInfotip } from '@elementor/editor-ui';
14
+ import { InfoAlert, WarningInfotip } from '@elementor/editor-ui';
16
15
  import { ColorSwatchIcon, MapPinIcon } from '@elementor/icons';
17
16
  import { createLocation } from '@elementor/locations';
18
17
  import { type AutocompleteChangeReason, Box, Chip, FormLabel, Link, Stack, Typography } from '@elementor/ui';
@@ -29,7 +28,7 @@ import {
29
28
  type ValidationResult,
30
29
  } from '../creatable-autocomplete';
31
30
  import { CssClassItem } from './css-class-item';
32
- import { useApplyClass, useUnapplyClass } from './use-apply-and-unapply-class';
31
+ import { useApplyClass, useCreateAndApplyClass, useUnapplyClass } from './use-apply-and-unapply-class';
33
32
 
34
33
  const ID = 'elementor-css-class-selector';
35
34
  const TAGS_LIMIT = 50;
@@ -59,19 +58,22 @@ export const { Slot: ClassSelectorActionsSlot, inject: injectIntoClassSelectorAc
59
58
  export function CssClassSelector() {
60
59
  const options = useOptions();
61
60
 
62
- const { value: appliedIds, pushValue: pushAppliedId } = useAppliedClassesIds();
63
61
  const { id: activeId, setId: setActiveId } = useStyle();
64
62
 
65
63
  const autocompleteRef = useRef< HTMLElement | null >( null );
66
64
  const [ renameError, setRenameError ] = useState< string | null >( null );
67
65
 
68
66
  const handleSelect = useHandleSelect();
69
- const { create, validate, entityName } = useCreateAction( { pushAppliedId, setActiveId } );
67
+ const { create, validate, entityName } = useCreateAction();
70
68
 
71
- const applied = useAppliedOptions( options, appliedIds );
72
- const active = applied.find( ( option ) => option.value === activeId ) ?? EMPTY_OPTION;
69
+ const appliedOptions = useAppliedOptions( options );
70
+ const active = appliedOptions.find( ( option ) => option.value === activeId ) ?? EMPTY_OPTION;
73
71
 
74
- const showPlaceholder = applied.every( ( { fixed } ) => fixed );
72
+ const showPlaceholder = appliedOptions.every( ( { fixed } ) => fixed );
73
+
74
+ const { userCan } = useUserStylesCapability();
75
+
76
+ const canEdit = active.provider ? userCan( active.provider ).updateProps : true;
75
77
 
76
78
  return (
77
79
  <Stack p={ 2 }>
@@ -96,7 +98,7 @@ export function CssClassSelector() {
96
98
  size="tiny"
97
99
  placeholder={ showPlaceholder ? __( 'Type class name', 'elementor' ) : undefined }
98
100
  options={ options }
99
- selected={ applied }
101
+ selected={ appliedOptions }
100
102
  entityName={ entityName }
101
103
  onSelect={ handleSelect }
102
104
  onCreate={ create ?? undefined }
@@ -138,6 +140,15 @@ export function CssClassSelector() {
138
140
  }
139
141
  />
140
142
  </WarningInfotip>
143
+ { ! canEdit && (
144
+ <InfoAlert
145
+ content={ __(
146
+ 'With your current role, you can use existing classes but can’t modify them.',
147
+ 'elementor'
148
+ ) }
149
+ sx={ { mt: 1 } }
150
+ />
151
+ ) }
141
152
  </Stack>
142
153
  );
143
154
  }
@@ -212,23 +223,14 @@ function useOptions() {
212
223
  } );
213
224
  }
214
225
 
215
- function useCreateAction( {
216
- pushAppliedId,
217
- setActiveId,
218
- }: {
219
- pushAppliedId: ( id: StyleDefinitionID ) => void;
220
- setActiveId: ( id: StyleDefinitionID ) => void;
221
- } ) {
222
- const [ provider, createAction ] = useGetStylesRepositoryCreateAction() ?? [ null, null ];
226
+ function useCreateAction() {
227
+ const [ provider, createAction ] = useCreateAndApplyClass();
223
228
  if ( ! provider || ! createAction ) {
224
229
  return {};
225
230
  }
226
231
 
227
- const create = ( newClassLabel: string ) => {
228
- const createdId = createAction( newClassLabel );
229
-
230
- pushAppliedId( createdId );
231
- setActiveId( createdId );
232
+ const create = ( classLabel: string ) => {
233
+ createAction( { classLabel } );
232
234
  };
233
235
 
234
236
  const validate = ( newClassLabel: string, event: ValidationEvent ): ValidationResult => {
@@ -256,45 +258,22 @@ function hasReachedLimit( provider: StylesProvider ) {
256
258
  return provider.actions.all().length >= provider.limit;
257
259
  }
258
260
 
259
- function useAppliedOptions( options: StyleDefOption[], appliedIds: StyleDefinitionID[] ) {
260
- const applied = options.filter( ( option ) => option.value && appliedIds.includes( option.value ) );
261
+ function useAppliedOptions( options: StyleDefOption[] ) {
262
+ const { element } = useElement();
263
+ const currentClassesProp = useClassesProp();
264
+
265
+ const appliedIds = useElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
266
+ const appliedOptions = options.filter( ( option ) => option.value && appliedIds.includes( option.value ) );
261
267
 
262
- const hasElementsProviderStyleApplied = applied.some(
268
+ const hasElementsProviderStyleApplied = appliedOptions.some(
263
269
  ( option ) => option.provider && isElementsStylesProvider( option.provider )
264
270
  );
265
271
 
266
272
  if ( ! hasElementsProviderStyleApplied ) {
267
- applied.unshift( EMPTY_OPTION );
273
+ appliedOptions.unshift( EMPTY_OPTION );
268
274
  }
269
275
 
270
- return applied;
271
- }
272
-
273
- function useAppliedClassesIds() {
274
- const { element } = useElement();
275
- const currentClassesProp = useClassesProp();
276
-
277
- const value = useElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
278
-
279
- const setValue = ( ids: StyleDefinitionID[] ) => {
280
- updateElementSettings( {
281
- id: element.id,
282
- props: {
283
- [ currentClassesProp ]: classesPropTypeUtil.create( ids ),
284
- },
285
- } );
286
- };
287
-
288
- const pushValue = ( id: StyleDefinitionID ) => {
289
- const ids = getElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
290
-
291
- setValue( [ ...ids, id ] );
292
- };
293
-
294
- return {
295
- value,
296
- pushValue,
297
- };
276
+ return appliedOptions;
298
277
  }
299
278
 
300
279
  function useHandleSelect() {
@@ -3,23 +3,34 @@ import { setDocumentModifiedStatus } from '@elementor/editor-documents';
3
3
  import { getElementLabel, getElementSetting, updateElementSettings } from '@elementor/editor-elements';
4
4
  import { classesPropTypeUtil, type ClassesPropValue } from '@elementor/editor-props';
5
5
  import { type StyleDefinitionID } from '@elementor/editor-styles';
6
+ import { useGetStylesRepositoryCreateAction } from '@elementor/editor-styles-repository';
6
7
  import { isExperimentActive, undoable } from '@elementor/editor-v1-adapters';
7
8
  import { __ } from '@wordpress/i18n';
8
9
 
9
10
  import { useClassesProp } from '../../contexts/classes-prop-context';
10
11
  import { useElement } from '../../contexts/element-context';
11
12
  import { useStyle } from '../../contexts/style-context';
13
+ import { EXPERIMENTAL_FEATURES } from '../../sync/experiments-flags';
12
14
 
13
15
  type UndoableClassActionPayload = {
14
16
  classId: StyleDefinitionID;
15
17
  classLabel: string;
16
18
  };
17
19
 
20
+ type CreateAndApplyClassPayload = {
21
+ classLabel: string;
22
+ };
23
+
24
+ type CreateAndApplyClassUndoData = {
25
+ prevActiveId: string | null;
26
+ createdId: StyleDefinitionID;
27
+ };
28
+
18
29
  export function useApplyClass() {
19
30
  const { id: activeId, setId: setActiveId } = useStyle();
20
31
  const { element } = useElement();
21
32
 
22
- const isVersion330Active = isExperimentActive( 'e_v_3_30' );
33
+ const isVersion330Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
23
34
 
24
35
  const applyClass = useApply();
25
36
  const unapplyClass = useUnapply();
@@ -63,7 +74,7 @@ export function useUnapplyClass() {
63
74
  const { id: activeId, setId: setActiveId } = useStyle();
64
75
  const { element } = useElement();
65
76
 
66
- const isVersion330Active = isExperimentActive( 'e_v_3_30' );
77
+ const isVersion330Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
67
78
 
68
79
  const applyClass = useApply();
69
80
  const unapplyClass = useUnapply();
@@ -103,10 +114,74 @@ export function useUnapplyClass() {
103
114
  return isVersion330Active ? undoableUnapply : unapplyWithoutHistory;
104
115
  }
105
116
 
117
+ export function useCreateAndApplyClass() {
118
+ const { id: activeId, setId: setActiveId } = useStyle();
119
+
120
+ const isVersion330Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
121
+
122
+ const [ provider, createAction ] = useGetStylesRepositoryCreateAction() ?? [ null, null ];
123
+ const deleteAction = provider?.actions.delete;
124
+
125
+ const applyClass = useApply();
126
+ const unapplyClass = useUnapply();
127
+
128
+ const undoableCreateAndApply = useMemo( () => {
129
+ if ( ! provider || ! createAction ) {
130
+ return;
131
+ }
132
+
133
+ return undoable(
134
+ {
135
+ do: ( { classLabel }: CreateAndApplyClassPayload ): CreateAndApplyClassUndoData => {
136
+ const prevActiveId = activeId;
137
+
138
+ const createdId = createAction( classLabel );
139
+ applyClass( createdId );
140
+
141
+ return { prevActiveId, createdId };
142
+ },
143
+ undo: ( _: CreateAndApplyClassPayload, { prevActiveId, createdId }: CreateAndApplyClassUndoData ) => {
144
+ unapplyClass( createdId );
145
+ deleteAction?.( createdId );
146
+
147
+ setActiveId( prevActiveId );
148
+ },
149
+ },
150
+ {
151
+ title: __( 'Class', 'elementor' ),
152
+ subtitle: ( { classLabel } ) => {
153
+ /* translators: %s is the class name. */
154
+ return __( `%s created`, 'elementor' ).replace( '%s', classLabel );
155
+ },
156
+ }
157
+ );
158
+ }, [ activeId, applyClass, createAction, deleteAction, provider, setActiveId, unapplyClass ] );
159
+
160
+ const createAndApplyWithoutHistory = useCallback(
161
+ ( { classLabel }: CreateAndApplyClassPayload ) => {
162
+ if ( ! createAction ) {
163
+ return;
164
+ }
165
+
166
+ const createdId = createAction( classLabel );
167
+ applyClass( createdId );
168
+ },
169
+ [ applyClass, createAction ]
170
+ );
171
+
172
+ if ( ! provider || ! undoableCreateAndApply ) {
173
+ return [ null, null ];
174
+ }
175
+
176
+ return isVersion330Active
177
+ ? ( [ provider, undoableCreateAndApply ] as const )
178
+ : ( [ provider, createAndApplyWithoutHistory ] as const );
179
+ }
180
+
106
181
  function useApply() {
107
182
  const { element } = useElement();
108
183
  const { setId: setActiveId } = useStyle();
109
- const { setClasses, getAppliedClasses } = useSetClasses();
184
+ const { setClasses, getAppliedClasses } = useClasses();
110
185
 
111
186
  return useCallback(
112
187
  ( classIDToApply: StyleDefinitionID ) => {
@@ -129,7 +204,7 @@ function useApply() {
129
204
  function useUnapply() {
130
205
  const { element } = useElement();
131
206
  const { id: activeId, setId: setActiveId } = useStyle();
132
- const { setClasses, getAppliedClasses } = useSetClasses();
207
+ const { setClasses, getAppliedClasses } = useClasses();
133
208
 
134
209
  return useCallback(
135
210
  ( classIDToUnapply: StyleDefinitionID ) => {
@@ -152,11 +227,11 @@ function useUnapply() {
152
227
  );
153
228
  }
154
229
 
155
- function useSetClasses() {
230
+ function useClasses() {
156
231
  const { element } = useElement();
157
232
  const currentClassesProp = useClassesProp();
158
233
 
159
- const isVersion330Active = isExperimentActive( 'e_v_3_30' );
234
+ const isVersion330Active = isExperimentActive( EXPERIMENTAL_FEATURES.V_3_30 );
160
235
 
161
236
  return useMemo( () => {
162
237
  const setClasses = ( ids: StyleDefinitionID[] ) => {
@@ -174,9 +249,6 @@ function useSetClasses() {
174
249
  const getAppliedClasses = () =>
175
250
  getElementSetting< ClassesPropValue >( element.id, currentClassesProp )?.value || [];
176
251
 
177
- return {
178
- setClasses,
179
- getAppliedClasses,
180
- };
252
+ return { setClasses, getAppliedClasses };
181
253
  }, [ currentClassesProp, element.id, isVersion330Active ] );
182
254
  }