@elementor/editor-editing-panel 4.2.0-885 → 4.2.0-887

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": "4.2.0-885",
3
+ "version": "4.2.0-887",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,31 +39,31 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "4.2.0-885",
43
- "@elementor/editor-canvas": "4.2.0-885",
44
- "@elementor/editor-controls": "4.2.0-885",
45
- "@elementor/editor-documents": "4.2.0-885",
46
- "@elementor/editor-elements": "4.2.0-885",
47
- "@elementor/editor-interactions": "4.2.0-885",
48
- "@elementor/editor-notifications": "4.2.0-885",
49
- "@elementor/editor-panels": "4.2.0-885",
50
- "@elementor/editor-props": "4.2.0-885",
51
- "@elementor/editor-responsive": "4.2.0-885",
52
- "@elementor/editor-styles": "4.2.0-885",
53
- "@elementor/editor-styles-repository": "4.2.0-885",
54
- "@elementor/editor-ui": "4.2.0-885",
55
- "@elementor/editor-v1-adapters": "4.2.0-885",
56
- "@elementor/http-client": "4.2.0-885",
42
+ "@elementor/editor": "4.2.0-887",
43
+ "@elementor/editor-canvas": "4.2.0-887",
44
+ "@elementor/editor-controls": "4.2.0-887",
45
+ "@elementor/editor-documents": "4.2.0-887",
46
+ "@elementor/editor-elements": "4.2.0-887",
47
+ "@elementor/editor-interactions": "4.2.0-887",
48
+ "@elementor/editor-notifications": "4.2.0-887",
49
+ "@elementor/editor-panels": "4.2.0-887",
50
+ "@elementor/editor-props": "4.2.0-887",
51
+ "@elementor/editor-responsive": "4.2.0-887",
52
+ "@elementor/editor-styles": "4.2.0-887",
53
+ "@elementor/editor-styles-repository": "4.2.0-887",
54
+ "@elementor/editor-ui": "4.2.0-887",
55
+ "@elementor/editor-v1-adapters": "4.2.0-887",
56
+ "@elementor/http-client": "4.2.0-887",
57
57
  "@elementor/icons": "~1.75.1",
58
- "@elementor/editor-variables": "4.2.0-885",
59
- "@elementor/locations": "4.2.0-885",
60
- "@elementor/menus": "4.2.0-885",
61
- "@elementor/query": "4.2.0-885",
62
- "@elementor/schema": "4.2.0-885",
63
- "@elementor/session": "4.2.0-885",
58
+ "@elementor/editor-variables": "4.2.0-887",
59
+ "@elementor/locations": "4.2.0-887",
60
+ "@elementor/menus": "4.2.0-887",
61
+ "@elementor/query": "4.2.0-887",
62
+ "@elementor/schema": "4.2.0-887",
63
+ "@elementor/session": "4.2.0-887",
64
64
  "@elementor/ui": "1.37.5",
65
- "@elementor/utils": "4.2.0-885",
66
- "@elementor/wp-media": "4.2.0-885",
65
+ "@elementor/utils": "4.2.0-887",
66
+ "@elementor/wp-media": "4.2.0-887",
67
67
  "@wordpress/i18n": "^5.13.0"
68
68
  },
69
69
  "peerDependencies": {
@@ -18,7 +18,7 @@ import { StyleIndicator } from '../style-indicator';
18
18
  import { useCssClass } from './css-class-context';
19
19
  import { DuplicateClassMenuItem } from './duplicate-class-menu-item';
20
20
  import { LocalClassSubMenu } from './local-class-sub-menu';
21
- import { useUnapplyClass } from './use-apply-and-unapply-class';
21
+ import { useUndoableUnapplyClass } from './use-apply-and-unapply-class';
22
22
 
23
23
  type State = {
24
24
  key: StyleDefinitionStateWithNormal;
@@ -264,7 +264,7 @@ function StateMenuItem( { state, label, closeMenu, ...props }: StateMenuItemProp
264
264
 
265
265
  function UnapplyClassMenuItem( { closeMenu, ...props }: { closeMenu: () => void } ) {
266
266
  const { id: classId, label: classLabel, provider } = useCssClass();
267
- const unapplyClass = useUnapplyClass();
267
+ const unapplyClass = useUndoableUnapplyClass();
268
268
 
269
269
  return classId ? (
270
270
  <MenuListItem
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { type ReactElement, useRef, useState } from 'react';
2
+ import { type ReactElement, useCallback, useRef, useState } from 'react';
3
3
  import { type ClassesPropValue } from '@elementor/editor-props';
4
4
  import {
5
5
  isElementsStylesProvider,
@@ -39,7 +39,14 @@ import {
39
39
  type ValidationResult,
40
40
  } from '../creatable-autocomplete';
41
41
  import { CssClassItem } from './css-class-item';
42
- import { useApplyClass, useCreateAndApplyClass, useUnapplyClass } from './use-apply-and-unapply-class';
42
+ import { MissingClassesAlert } from './missing-classes-alert';
43
+ import {
44
+ useCreateAndApplyClass,
45
+ useUnapplyClasses,
46
+ useUndoableApplyClass,
47
+ useUndoableUnapplyClass,
48
+ } from './use-apply-and-unapply-class';
49
+ import { useMissingClassesIds } from './use-missing-classes';
43
50
 
44
51
  const ID = 'elementor-css-class-selector';
45
52
  const TAGS_LIMIT = 50;
@@ -94,6 +101,15 @@ export function CssClassSelector() {
94
101
 
95
102
  const canEdit = active.provider ? userCan( active.provider ).updateProps : true;
96
103
 
104
+ const missingClassesIds = useMissingClassesIds();
105
+ const hasMissingClasses = missingClassesIds.length > 0;
106
+
107
+ const unapplyClasses = useUnapplyClasses();
108
+
109
+ const clearMissingClasses = useCallback( () => {
110
+ unapplyClasses( missingClassesIds );
111
+ }, [ missingClassesIds, unapplyClasses ] );
112
+
97
113
  return (
98
114
  <Stack p={ 2 }>
99
115
  <Stack direction="row" gap={ 1 } alignItems="center" justifyContent="space-between">
@@ -172,6 +188,7 @@ export function CssClassSelector() {
172
188
  }
173
189
  />
174
190
  </WarningInfotip>
191
+ { hasMissingClasses && <MissingClassesAlert onDismiss={ clearMissingClasses } /> }
175
192
  { ! canEdit && (
176
193
  <InfoAlert sx={ { mt: 1 } }>
177
194
  { __( 'With your current role, you can use existing classes but can’t modify them.', 'elementor' ) }
@@ -365,8 +382,8 @@ function useAppliedOptions( options: StyleDefOption[] ) {
365
382
  }
366
383
 
367
384
  function useHandleSelect() {
368
- const apply = useApplyClass();
369
- const unapply = useUnapplyClass();
385
+ const apply = useUndoableApplyClass();
386
+ const unapply = useUndoableUnapplyClass();
370
387
 
371
388
  return ( _selectedOptions: StyleDefOption[], reason: AutocompleteChangeReason, option: StyleDefOption ) => {
372
389
  if ( ! option.value ) {
@@ -7,7 +7,7 @@ import { __ } from '@wordpress/i18n';
7
7
  import { trackStyles } from '../../utils/tracking/subscribe';
8
8
  import { PENDING_CLASS_RENAME_SESSION_KEY } from './consts';
9
9
  import { useCssClass } from './css-class-context';
10
- import { useApplyClass } from './use-apply-and-unapply-class';
10
+ import { useUndoableApplyClass } from './use-apply-and-unapply-class';
11
11
 
12
12
  const DUPLICATE_LABEL_PREFIX = 'copy-of';
13
13
 
@@ -24,7 +24,7 @@ export function getUniqueDuplicateLabel( originalLabel: string, existingLabels:
24
24
  export function DuplicateClassMenuItem( { closeMenu }: { closeMenu: () => void } ) {
25
25
  const { id: classId, provider } = useCssClass();
26
26
  const { userCan } = useUserStylesCapability();
27
- const applyClass = useApplyClass();
27
+ const applyClass = useUndoableApplyClass();
28
28
  const [ , setPendingEditId ] = useSessionStorage( PENDING_CLASS_RENAME_SESSION_KEY, 'app' );
29
29
 
30
30
  if ( ! provider || ! classId ) {
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import { AlertTriangleFilledIcon } from '@elementor/icons';
3
+ import { Alert, AlertTitle, Typography } from '@elementor/ui';
4
+ import { __ } from '@wordpress/i18n';
5
+
6
+ type MissingClassesAlertProps = {
7
+ onDismiss: () => void;
8
+ };
9
+
10
+ export function MissingClassesAlert( { onDismiss }: MissingClassesAlertProps ) {
11
+ return (
12
+ <Alert
13
+ severity="warning"
14
+ onClose={ onDismiss }
15
+ size="small"
16
+ icon={ <AlertTriangleFilledIcon fontSize="tiny" /> }
17
+ sx={ { mt: 1 } }
18
+ >
19
+ <AlertTitle>{ __( 'Some classes are missing', 'elementor' ) }</AlertTitle>
20
+ <Typography variant="caption" textColor="primary">
21
+ { __( 'A class was removed from your site and is no longer active on this element', 'elementor' ) }
22
+ </Typography>
23
+ </Alert>
24
+ );
25
+ }
@@ -24,12 +24,12 @@ type CreateAndApplyClassUndoData = {
24
24
  createdId: StyleDefinitionID;
25
25
  };
26
26
 
27
- export function useApplyClass() {
27
+ export function useUndoableApplyClass() {
28
28
  const { id: activeId, setId: setActiveId } = useStyle();
29
29
  const { element } = useElement();
30
30
 
31
- const applyClass = useApply();
32
- const unapplyClass = useUnapply();
31
+ const applyClass = useApplyClass();
32
+ const unapplyClasses = useUnapplyClasses();
33
33
 
34
34
  return useMemo( () => {
35
35
  return undoable(
@@ -42,7 +42,7 @@ export function useApplyClass() {
42
42
  return prevActiveId;
43
43
  },
44
44
  undo: ( { classId }: UndoableClassActionPayload, prevActiveId: string | null ) => {
45
- unapplyClass( classId );
45
+ unapplyClasses( [ classId ] );
46
46
  setActiveId( prevActiveId );
47
47
  },
48
48
  },
@@ -54,15 +54,15 @@ export function useApplyClass() {
54
54
  },
55
55
  }
56
56
  );
57
- }, [ activeId, applyClass, element.id, unapplyClass, setActiveId ] );
57
+ }, [ activeId, applyClass, element.id, unapplyClasses, setActiveId ] );
58
58
  }
59
59
 
60
- export function useUnapplyClass() {
60
+ export function useUndoableUnapplyClass() {
61
61
  const { id: activeId, setId: setActiveId } = useStyle();
62
62
  const { element } = useElement();
63
63
 
64
- const applyClass = useApply();
65
- const unapplyClass = useUnapply();
64
+ const applyClass = useApplyClass();
65
+ const unapplyClasses = useUnapplyClasses();
66
66
 
67
67
  return useMemo( () => {
68
68
  return undoable(
@@ -70,7 +70,7 @@ export function useUnapplyClass() {
70
70
  do: ( { classId }: UndoableClassActionPayload ) => {
71
71
  const prevActiveId = activeId;
72
72
 
73
- unapplyClass( classId );
73
+ unapplyClasses( [ classId ] );
74
74
 
75
75
  return prevActiveId;
76
76
  },
@@ -87,7 +87,7 @@ export function useUnapplyClass() {
87
87
  },
88
88
  }
89
89
  );
90
- }, [ activeId, applyClass, element.id, unapplyClass, setActiveId ] );
90
+ }, [ activeId, applyClass, element.id, unapplyClasses, setActiveId ] );
91
91
  }
92
92
 
93
93
  export function useCreateAndApplyClass() {
@@ -96,8 +96,8 @@ export function useCreateAndApplyClass() {
96
96
  const [ provider, createAction ] = useGetStylesRepositoryCreateAction() ?? [ null, null ];
97
97
  const deleteAction = provider?.actions.delete;
98
98
 
99
- const applyClass = useApply();
100
- const unapplyClass = useUnapply();
99
+ const applyClass = useApplyClass();
100
+ const unapplyClasses = useUnapplyClasses();
101
101
 
102
102
  const undoableCreateAndApply = useMemo( () => {
103
103
  if ( ! provider || ! createAction ) {
@@ -114,7 +114,7 @@ export function useCreateAndApplyClass() {
114
114
  return { prevActiveId, createdId };
115
115
  },
116
116
  undo: ( _: CreateAndApplyClassPayload, { prevActiveId, createdId }: CreateAndApplyClassUndoData ) => {
117
- unapplyClass( createdId );
117
+ unapplyClasses( [ createdId ] );
118
118
  deleteAction?.( createdId );
119
119
 
120
120
  setActiveId( prevActiveId );
@@ -138,7 +138,7 @@ export function useCreateAndApplyClass() {
138
138
  },
139
139
  }
140
140
  );
141
- }, [ activeId, applyClass, createAction, deleteAction, provider, setActiveId, unapplyClass ] );
141
+ }, [ activeId, applyClass, createAction, deleteAction, provider, setActiveId, unapplyClasses ] );
142
142
 
143
143
  if ( ! provider || ! undoableCreateAndApply ) {
144
144
  return [ null, null ];
@@ -147,7 +147,7 @@ export function useCreateAndApplyClass() {
147
147
  return [ provider, undoableCreateAndApply ] as const;
148
148
  }
149
149
 
150
- function useApply() {
150
+ function useApplyClass() {
151
151
  const { element } = useElement();
152
152
  const { setId: setActiveId } = useStyle();
153
153
  const { setClasses, getAppliedClasses } = useClasses();
@@ -170,25 +170,28 @@ function useApply() {
170
170
  );
171
171
  }
172
172
 
173
- function useUnapply() {
173
+ export function useUnapplyClasses() {
174
174
  const { element } = useElement();
175
175
  const { id: activeId, setId: setActiveId } = useStyle();
176
176
  const { setClasses, getAppliedClasses } = useClasses();
177
177
 
178
178
  return useCallback(
179
- ( classIDToUnapply: StyleDefinitionID ) => {
179
+ ( classIDsToUnapply: StyleDefinitionID[] ) => {
180
180
  const appliedClasses = getAppliedClasses();
181
181
 
182
- if ( ! appliedClasses.includes( classIDToUnapply ) ) {
182
+ if ( ! classIDsToUnapply.every( ( classID ) => appliedClasses.includes( classID ) ) ) {
183
+ const missingClasses = classIDsToUnapply.filter( ( classID ) => ! appliedClasses.includes( classID ) );
183
184
  throw new Error(
184
- `Class ${ classIDToUnapply } is not applied to element ${ element.id }, cannot unapply it.`
185
+ `Classes ${ missingClasses.join( ', ' ) } are not applied to element ${
186
+ element.id
187
+ }, cannot unapply them.`
185
188
  );
186
189
  }
187
190
 
188
- const updatedClassesIds = appliedClasses.filter( ( id ) => id !== classIDToUnapply );
191
+ const updatedClassesIds = appliedClasses.filter( ( id ) => ! classIDsToUnapply.includes( id ) );
189
192
  setClasses( updatedClassesIds );
190
193
 
191
- if ( activeId === classIDToUnapply ) {
194
+ if ( activeId && classIDsToUnapply.includes( activeId ) ) {
192
195
  setActiveId( updatedClassesIds[ 0 ] ?? null );
193
196
  }
194
197
  },
@@ -0,0 +1,17 @@
1
+ import { type ClassesPropValue } from '@elementor/editor-props';
2
+ import { useProviders } from '@elementor/editor-styles-repository';
3
+
4
+ import { useClassesProp } from '../../contexts/classes-prop-context';
5
+ import { usePanelElementSetting } from '../../contexts/element-context';
6
+
7
+ export function useMissingClassesIds(): string[] {
8
+ const providers = useProviders();
9
+ const currentClassesProp = useClassesProp();
10
+ const appliedIds = usePanelElementSetting< ClassesPropValue >( currentClassesProp )?.value ?? [];
11
+
12
+ const allKnownIds = new Set(
13
+ providers.flatMap( ( provider ) => provider.actions.all().map( ( style ) => style.id ) )
14
+ );
15
+
16
+ return appliedIds.filter( ( id ) => ! allKnownIds.has( id ) );
17
+ }
@@ -1,6 +1,7 @@
1
1
  import { getElementStyles } from '@elementor/editor-elements';
2
2
  import { type ClassesPropValue, type PropKey } from '@elementor/editor-props';
3
3
  import { type StyleDefinitionID } from '@elementor/editor-styles';
4
+ import { useProviders } from '@elementor/editor-styles-repository';
4
5
 
5
6
  import { useElement, usePanelElementSetting } from '../contexts/element-context';
6
7
  import { useStateByElement } from './use-state-by-element';
@@ -12,13 +13,22 @@ export function useActiveStyleDefId( classProp: PropKey ) {
12
13
  );
13
14
 
14
15
  const appliedClassesIds = usePanelElementSetting< ClassesPropValue >( classProp )?.value || [];
16
+ const validAppliedClassesIds = useValidClassIds( appliedClassesIds );
15
17
 
16
18
  const fallback = useFirstAppliedClass( appliedClassesIds );
17
19
 
18
- const activeAndAppliedClassId = useActiveAndAppliedClassId( activeStyledDefId, appliedClassesIds );
20
+ const activeAndAppliedClassId = useActiveAndAppliedClassId( activeStyledDefId, validAppliedClassesIds );
19
21
  return [ activeAndAppliedClassId || fallback?.id || null, setActiveStyledDefId ] as const;
20
22
  }
21
23
 
24
+ function useValidClassIds( appliedClassesIds: string[] ) {
25
+ const providers = useProviders();
26
+ const allKnownIds = new Set(
27
+ providers.flatMap( ( provider ) => provider.actions.all().map( ( style ) => style.id ) )
28
+ );
29
+ return appliedClassesIds.filter( ( id ) => allKnownIds.has( id ) );
30
+ }
31
+
22
32
  function useFirstAppliedClass( appliedClassesIds: string[] ) {
23
33
  const { element } = useElement();
24
34
  const stylesDefs = getElementStyles( element.id ) ?? {};