@elementor/editor-canvas 4.1.0-738 → 4.1.0-740

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/dist/index.js CHANGED
@@ -1187,6 +1187,9 @@ function getArgsElementType(args) {
1187
1187
  function getElementType(element) {
1188
1188
  return element?.model.get("widgetType") || element?.model.get("elType");
1189
1189
  }
1190
+ function getClipboardElementType(element) {
1191
+ return element?.widgetType || element?.elType;
1192
+ }
1190
1193
  function isElementWithinFormSelector(element) {
1191
1194
  return !!element?.view?.el?.closest('form,[data-element_type="e-form"]');
1192
1195
  }
@@ -1204,7 +1207,7 @@ function hasElementTypes(element, types) {
1204
1207
  }
1205
1208
  function hasClipboardElementType(elements, type) {
1206
1209
  return elements.some((element) => {
1207
- const elementType = element.widgetType || element.elType;
1210
+ const elementType = getClipboardElementType(element);
1208
1211
  if (elementType === type) {
1209
1212
  return true;
1210
1213
  }
@@ -1213,13 +1216,22 @@ function hasClipboardElementType(elements, type) {
1213
1216
  }
1214
1217
  function hasClipboardElementTypes(elements, types) {
1215
1218
  return elements.some((element) => {
1216
- const elementType = element.widgetType || element.elType;
1219
+ const elementType = getClipboardElementType(element);
1217
1220
  if (elementType && types.has(elementType)) {
1218
1221
  return true;
1219
1222
  }
1220
1223
  return element.elements ? hasClipboardElementTypes(element.elements, types) : false;
1221
1224
  });
1222
1225
  }
1226
+ function movedContainersIncludeAtomicFormRoot(containers) {
1227
+ return containers.some((container) => getElementType(container) === FORM_ELEMENT_TYPE);
1228
+ }
1229
+ function clipboardRootsAreAtomicForms(elements) {
1230
+ if (!elements.length) {
1231
+ return false;
1232
+ }
1233
+ return elements.every((el) => getClipboardElementType(el) === FORM_ELEMENT_TYPE);
1234
+ }
1223
1235
 
1224
1236
  // src/form-structure/enforce-form-ancestor-commands.ts
1225
1237
  var FORM_FIELDS_OUTSIDE_ALERT = {
@@ -1257,7 +1269,7 @@ function blockFormFieldMove(args) {
1257
1269
  const hasFormFieldElement = containers.some(
1258
1270
  (container) => container ? hasElementTypes(container, FORM_FIELD_ELEMENT_TYPES) : false
1259
1271
  );
1260
- if (hasFormFieldElement && !isWithinForm(target)) {
1272
+ if (hasFormFieldElement && !isWithinForm(target) && !movedContainersIncludeAtomicFormRoot(containers)) {
1261
1273
  handleBlockedFormField();
1262
1274
  return true;
1263
1275
  }
@@ -1273,7 +1285,7 @@ function blockFormFieldPaste(args) {
1273
1285
  return false;
1274
1286
  }
1275
1287
  const hasFormFieldElement = hasClipboardElementTypes(data.clipboard.elements, FORM_FIELD_ELEMENT_TYPES);
1276
- if (hasFormFieldElement && !isWithinForm(args.container)) {
1288
+ if (hasFormFieldElement && !isWithinForm(args.container) && !clipboardRootsAreAtomicForms(data.clipboard.elements)) {
1277
1289
  handleBlockedFormField();
1278
1290
  return true;
1279
1291
  }
@@ -2487,7 +2499,8 @@ var INLINE_EDITING_PROPERTY_PER_TYPE = {
2487
2499
  "e-button": "text",
2488
2500
  "e-form-label": "text",
2489
2501
  "e-heading": "title",
2490
- "e-paragraph": "paragraph"
2502
+ "e-paragraph": "paragraph",
2503
+ "e-form-submit-button": "text"
2491
2504
  };
2492
2505
  var getInlineEditorElement = (elementWrapper, expectedTag) => {
2493
2506
  return !expectedTag ? null : elementWrapper.querySelector(expectedTag);
package/dist/index.mjs CHANGED
@@ -1153,6 +1153,9 @@ function getArgsElementType(args) {
1153
1153
  function getElementType(element) {
1154
1154
  return element?.model.get("widgetType") || element?.model.get("elType");
1155
1155
  }
1156
+ function getClipboardElementType(element) {
1157
+ return element?.widgetType || element?.elType;
1158
+ }
1156
1159
  function isElementWithinFormSelector(element) {
1157
1160
  return !!element?.view?.el?.closest('form,[data-element_type="e-form"]');
1158
1161
  }
@@ -1170,7 +1173,7 @@ function hasElementTypes(element, types) {
1170
1173
  }
1171
1174
  function hasClipboardElementType(elements, type) {
1172
1175
  return elements.some((element) => {
1173
- const elementType = element.widgetType || element.elType;
1176
+ const elementType = getClipboardElementType(element);
1174
1177
  if (elementType === type) {
1175
1178
  return true;
1176
1179
  }
@@ -1179,13 +1182,22 @@ function hasClipboardElementType(elements, type) {
1179
1182
  }
1180
1183
  function hasClipboardElementTypes(elements, types) {
1181
1184
  return elements.some((element) => {
1182
- const elementType = element.widgetType || element.elType;
1185
+ const elementType = getClipboardElementType(element);
1183
1186
  if (elementType && types.has(elementType)) {
1184
1187
  return true;
1185
1188
  }
1186
1189
  return element.elements ? hasClipboardElementTypes(element.elements, types) : false;
1187
1190
  });
1188
1191
  }
1192
+ function movedContainersIncludeAtomicFormRoot(containers) {
1193
+ return containers.some((container) => getElementType(container) === FORM_ELEMENT_TYPE);
1194
+ }
1195
+ function clipboardRootsAreAtomicForms(elements) {
1196
+ if (!elements.length) {
1197
+ return false;
1198
+ }
1199
+ return elements.every((el) => getClipboardElementType(el) === FORM_ELEMENT_TYPE);
1200
+ }
1189
1201
 
1190
1202
  // src/form-structure/enforce-form-ancestor-commands.ts
1191
1203
  var FORM_FIELDS_OUTSIDE_ALERT = {
@@ -1223,7 +1235,7 @@ function blockFormFieldMove(args) {
1223
1235
  const hasFormFieldElement = containers.some(
1224
1236
  (container) => container ? hasElementTypes(container, FORM_FIELD_ELEMENT_TYPES) : false
1225
1237
  );
1226
- if (hasFormFieldElement && !isWithinForm(target)) {
1238
+ if (hasFormFieldElement && !isWithinForm(target) && !movedContainersIncludeAtomicFormRoot(containers)) {
1227
1239
  handleBlockedFormField();
1228
1240
  return true;
1229
1241
  }
@@ -1239,7 +1251,7 @@ function blockFormFieldPaste(args) {
1239
1251
  return false;
1240
1252
  }
1241
1253
  const hasFormFieldElement = hasClipboardElementTypes(data.clipboard.elements, FORM_FIELD_ELEMENT_TYPES);
1242
- if (hasFormFieldElement && !isWithinForm(args.container)) {
1254
+ if (hasFormFieldElement && !isWithinForm(args.container) && !clipboardRootsAreAtomicForms(data.clipboard.elements)) {
1243
1255
  handleBlockedFormField();
1244
1256
  return true;
1245
1257
  }
@@ -2457,7 +2469,8 @@ var INLINE_EDITING_PROPERTY_PER_TYPE = {
2457
2469
  "e-button": "text",
2458
2470
  "e-form-label": "text",
2459
2471
  "e-heading": "title",
2460
- "e-paragraph": "paragraph"
2472
+ "e-paragraph": "paragraph",
2473
+ "e-form-submit-button": "text"
2461
2474
  };
2462
2475
  var getInlineEditorElement = (elementWrapper, expectedTag) => {
2463
2476
  return !expectedTag ? null : elementWrapper.querySelector(expectedTag);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "4.1.0-738",
4
+ "version": "4.1.0-740",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,25 +37,25 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.1.0-738",
40
+ "@elementor/editor": "4.1.0-740",
41
41
  "dompurify": "^3.2.6",
42
- "@elementor/editor-controls": "4.1.0-738",
43
- "@elementor/editor-documents": "4.1.0-738",
44
- "@elementor/editor-elements": "4.1.0-738",
45
- "@elementor/editor-interactions": "4.1.0-738",
46
- "@elementor/editor-mcp": "4.1.0-738",
47
- "@elementor/editor-notifications": "4.1.0-738",
48
- "@elementor/editor-props": "4.1.0-738",
49
- "@elementor/editor-responsive": "4.1.0-738",
50
- "@elementor/editor-styles": "4.1.0-738",
51
- "@elementor/editor-styles-repository": "4.1.0-738",
52
- "@elementor/editor-ui": "4.1.0-738",
53
- "@elementor/editor-v1-adapters": "4.1.0-738",
54
- "@elementor/schema": "4.1.0-738",
55
- "@elementor/twing": "4.1.0-738",
42
+ "@elementor/editor-controls": "4.1.0-740",
43
+ "@elementor/editor-documents": "4.1.0-740",
44
+ "@elementor/editor-elements": "4.1.0-740",
45
+ "@elementor/editor-interactions": "4.1.0-740",
46
+ "@elementor/editor-mcp": "4.1.0-740",
47
+ "@elementor/editor-notifications": "4.1.0-740",
48
+ "@elementor/editor-props": "4.1.0-740",
49
+ "@elementor/editor-responsive": "4.1.0-740",
50
+ "@elementor/editor-styles": "4.1.0-740",
51
+ "@elementor/editor-styles-repository": "4.1.0-740",
52
+ "@elementor/editor-ui": "4.1.0-740",
53
+ "@elementor/editor-v1-adapters": "4.1.0-740",
54
+ "@elementor/schema": "4.1.0-740",
55
+ "@elementor/twing": "4.1.0-740",
56
56
  "@elementor/ui": "1.36.17",
57
- "@elementor/utils": "4.1.0-738",
58
- "@elementor/wp-media": "4.1.0-738",
57
+ "@elementor/utils": "4.1.0-740",
58
+ "@elementor/wp-media": "4.1.0-740",
59
59
  "@floating-ui/react": "^0.27.5",
60
60
  "@wordpress/i18n": "^5.13.0"
61
61
  },
@@ -0,0 +1,70 @@
1
+ import type { V1Element } from '@elementor/editor-elements';
2
+
3
+ import {
4
+ clipboardRootsAreAtomicForms,
5
+ FORM_ELEMENT_TYPE,
6
+ getClipboardElementType,
7
+ movedContainersIncludeAtomicFormRoot,
8
+ } from '../utils';
9
+
10
+ function mockElement( widgetType?: string, elType?: string ): V1Element {
11
+ return {
12
+ model: {
13
+ get: ( key: string ) => {
14
+ if ( key === 'widgetType' ) {
15
+ return widgetType;
16
+ }
17
+ if ( key === 'elType' ) {
18
+ return elType;
19
+ }
20
+ return undefined;
21
+ },
22
+ },
23
+ } as V1Element;
24
+ }
25
+
26
+ describe( 'form-structure utils', () => {
27
+ describe( 'getClipboardElementType', () => {
28
+ it( 'prefers widgetType over elType', () => {
29
+ expect( getClipboardElementType( { widgetType: 'e-form-input', elType: 'widget' } ) ).toBe(
30
+ 'e-form-input'
31
+ );
32
+ } );
33
+
34
+ it( 'falls back to elType', () => {
35
+ expect( getClipboardElementType( { elType: FORM_ELEMENT_TYPE } ) ).toBe( FORM_ELEMENT_TYPE );
36
+ } );
37
+
38
+ it( 'returns undefined when absent', () => {
39
+ expect( getClipboardElementType( {} ) ).toBeUndefined();
40
+ } );
41
+ } );
42
+
43
+ describe( 'movedContainersIncludeAtomicFormRoot', () => {
44
+ it( 'returns true when a top-level moved container is e-form', () => {
45
+ const form = mockElement( undefined, FORM_ELEMENT_TYPE );
46
+
47
+ expect( movedContainersIncludeAtomicFormRoot( [ form ] ) ).toBe( true );
48
+ } );
49
+
50
+ it( 'returns false when moved containers are only form fields', () => {
51
+ const input = mockElement( 'e-form-input', 'widget' );
52
+
53
+ expect( movedContainersIncludeAtomicFormRoot( [ input ] ) ).toBe( false );
54
+ } );
55
+ } );
56
+
57
+ describe( 'clipboardRootsAreAtomicForms', () => {
58
+ it( 'returns true when every root is e-form', () => {
59
+ expect( clipboardRootsAreAtomicForms( [ { elType: FORM_ELEMENT_TYPE, elements: [] } ] ) ).toBe( true );
60
+ } );
61
+
62
+ it( 'returns false when a root is a bare form field', () => {
63
+ expect( clipboardRootsAreAtomicForms( [ { widgetType: 'e-form-input', elements: [] } ] ) ).toBe( false );
64
+ } );
65
+
66
+ it( 'returns false for empty roots', () => {
67
+ expect( clipboardRootsAreAtomicForms( [] ) ).toBe( false );
68
+ } );
69
+ } );
70
+ } );
@@ -3,6 +3,7 @@ import { blockCommand } from '@elementor/editor-v1-adapters';
3
3
  import { __ } from '@wordpress/i18n';
4
4
 
5
5
  import {
6
+ clipboardRootsAreAtomicForms,
6
7
  type CreateArgs,
7
8
  FORM_FIELD_ELEMENT_TYPES,
8
9
  getArgsElementType,
@@ -10,6 +11,7 @@ import {
10
11
  hasElementTypes,
11
12
  isWithinForm,
12
13
  type MoveArgs,
14
+ movedContainersIncludeAtomicFormRoot,
13
15
  type PasteArgs,
14
16
  type StorageContent,
15
17
  } from './utils';
@@ -60,7 +62,7 @@ function blockFormFieldMove( args: MoveArgs ): boolean {
60
62
  container ? hasElementTypes( container, FORM_FIELD_ELEMENT_TYPES ) : false
61
63
  );
62
64
 
63
- if ( hasFormFieldElement && ! isWithinForm( target ) ) {
65
+ if ( hasFormFieldElement && ! isWithinForm( target ) && ! movedContainersIncludeAtomicFormRoot( containers ) ) {
64
66
  handleBlockedFormField();
65
67
 
66
68
  return true;
@@ -86,7 +88,11 @@ function blockFormFieldPaste( args: PasteArgs ): boolean {
86
88
 
87
89
  const hasFormFieldElement = hasClipboardElementTypes( data.clipboard.elements, FORM_FIELD_ELEMENT_TYPES );
88
90
 
89
- if ( hasFormFieldElement && ! isWithinForm( args.container ) ) {
91
+ if (
92
+ hasFormFieldElement &&
93
+ ! isWithinForm( args.container ) &&
94
+ ! clipboardRootsAreAtomicForms( data.clipboard.elements )
95
+ ) {
90
96
  handleBlockedFormField();
91
97
 
92
98
  return true;
@@ -50,6 +50,10 @@ export function getElementType( element?: V1Element ): string | undefined {
50
50
  return element?.model.get( 'widgetType' ) || element?.model.get( 'elType' );
51
51
  }
52
52
 
53
+ export function getClipboardElementType( element?: ClipboardElement ): string | undefined {
54
+ return element?.widgetType || element?.elType;
55
+ }
56
+
53
57
  export function isElementWithinFormSelector( element?: V1Element ): boolean {
54
58
  return !! element?.view?.el?.closest( 'form,[data-element_type="e-form"]' );
55
59
  }
@@ -72,7 +76,7 @@ export function hasElementTypes( element: V1Element, types: Set< string > ): boo
72
76
 
73
77
  export function hasClipboardElementType( elements: ClipboardElement[], type: string ): boolean {
74
78
  return elements.some( ( element ) => {
75
- const elementType = element.widgetType || element.elType;
79
+ const elementType = getClipboardElementType( element );
76
80
 
77
81
  if ( elementType === type ) {
78
82
  return true;
@@ -84,7 +88,7 @@ export function hasClipboardElementType( elements: ClipboardElement[], type: str
84
88
 
85
89
  export function hasClipboardElementTypes( elements: ClipboardElement[], types: Set< string > ): boolean {
86
90
  return elements.some( ( element ) => {
87
- const elementType = element.widgetType || element.elType;
91
+ const elementType = getClipboardElementType( element );
88
92
 
89
93
  if ( elementType && types.has( elementType ) ) {
90
94
  return true;
@@ -93,3 +97,15 @@ export function hasClipboardElementTypes( elements: ClipboardElement[], types: S
93
97
  return element.elements ? hasClipboardElementTypes( element.elements, types ) : false;
94
98
  } );
95
99
  }
100
+
101
+ export function movedContainersIncludeAtomicFormRoot( containers: ( V1Element | undefined )[] ): boolean {
102
+ return containers.some( ( container ) => getElementType( container ) === FORM_ELEMENT_TYPE );
103
+ }
104
+
105
+ export function clipboardRootsAreAtomicForms( elements: ClipboardElement[] ): boolean {
106
+ if ( ! elements.length ) {
107
+ return false;
108
+ }
109
+
110
+ return elements.every( ( el ) => getClipboardElementType( el ) === FORM_ELEMENT_TYPE );
111
+ }
@@ -43,6 +43,7 @@ export const INLINE_EDITING_PROPERTY_PER_TYPE: Record< string, string > = {
43
43
  'e-form-label': 'text',
44
44
  'e-heading': 'title',
45
45
  'e-paragraph': 'paragraph',
46
+ 'e-form-submit-button': 'text',
46
47
  };
47
48
 
48
49
  export const legacyWindow = window as unknown as LegacyWindow;