@elementor/editor-canvas 4.2.0-877 → 4.2.0-879

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.d.mts CHANGED
@@ -328,6 +328,9 @@ declare const DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
328
328
 
329
329
  declare function createTransformer<TValue = never>(cb: TValue extends AnyTransformable ? 'Transformable values are invalid, use the actual value instead.' : UnbrandedTransformer<TValue>): Transformer<NoInfer<TValue>>;
330
330
 
331
+ declare const isGridTrackProperty: (cssProperty: string) => boolean;
332
+ declare const formatGridTrackRepeat: (count: number) => string | null;
333
+
331
334
  declare const UnknownStyleTypeError: {
332
335
  new ({ cause, context }?: {
333
336
  cause?: _elementor_utils.ElementorErrorOptions["cause"];
@@ -363,4 +366,4 @@ declare const UnknownStyleStateError: {
363
366
 
364
367
  declare function doAfterRender(elementIds: string[], callback: (elementIds: string[]) => void): void;
365
368
 
366
- export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type ContextMenuAction, type ContextMenuEventData, type CreateNestedTemplatedElementTypeOptions, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload, type LegacyWindow, type NamespacedRenderContext, type NestedTemplatedElementConfig, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, TemplatedElementView, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, canBeNestedTemplated, createNestedTemplatedElementType, createNestedTemplatedElementView, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, doAfterRender, endDragElementFromPanel, init, isAtomicWidget, registerElementType, registerModelExtensions, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry, stylesInheritanceTransformersRegistry };
369
+ export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type ContextMenuAction, type ContextMenuEventData, type CreateNestedTemplatedElementTypeOptions, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload, type LegacyWindow, type NamespacedRenderContext, type NestedTemplatedElementConfig, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, TemplatedElementView, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, canBeNestedTemplated, createNestedTemplatedElementType, createNestedTemplatedElementView, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, doAfterRender, endDragElementFromPanel, formatGridTrackRepeat, init, isAtomicWidget, isGridTrackProperty, registerElementType, registerModelExtensions, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry, stylesInheritanceTransformersRegistry };
package/dist/index.d.ts CHANGED
@@ -328,6 +328,9 @@ declare const DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
328
328
 
329
329
  declare function createTransformer<TValue = never>(cb: TValue extends AnyTransformable ? 'Transformable values are invalid, use the actual value instead.' : UnbrandedTransformer<TValue>): Transformer<NoInfer<TValue>>;
330
330
 
331
+ declare const isGridTrackProperty: (cssProperty: string) => boolean;
332
+ declare const formatGridTrackRepeat: (count: number) => string | null;
333
+
331
334
  declare const UnknownStyleTypeError: {
332
335
  new ({ cause, context }?: {
333
336
  cause?: _elementor_utils.ElementorErrorOptions["cause"];
@@ -363,4 +366,4 @@ declare const UnknownStyleStateError: {
363
366
 
364
367
  declare function doAfterRender(elementIds: string[], callback: (elementIds: string[]) => void): void;
365
368
 
366
- export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type ContextMenuAction, type ContextMenuEventData, type CreateNestedTemplatedElementTypeOptions, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload, type LegacyWindow, type NamespacedRenderContext, type NestedTemplatedElementConfig, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, TemplatedElementView, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, canBeNestedTemplated, createNestedTemplatedElementType, createNestedTemplatedElementView, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, doAfterRender, endDragElementFromPanel, init, isAtomicWidget, registerElementType, registerModelExtensions, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry, stylesInheritanceTransformersRegistry };
369
+ export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type ContextMenuAction, type ContextMenuEventData, type CreateNestedTemplatedElementTypeOptions, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload, type LegacyWindow, type NamespacedRenderContext, type NestedTemplatedElementConfig, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, TemplatedElementView, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, canBeNestedTemplated, createNestedTemplatedElementType, createNestedTemplatedElementView, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, doAfterRender, endDragElementFromPanel, formatGridTrackRepeat, init, isAtomicWidget, isGridTrackProperty, registerElementType, registerModelExtensions, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry, stylesInheritanceTransformersRegistry };
package/dist/index.js CHANGED
@@ -46,8 +46,10 @@ __export(index_exports, {
46
46
  createTransformersRegistry: () => createTransformersRegistry,
47
47
  doAfterRender: () => doAfterRender,
48
48
  endDragElementFromPanel: () => endDragElementFromPanel,
49
+ formatGridTrackRepeat: () => formatGridTrackRepeat,
49
50
  init: () => init,
50
51
  isAtomicWidget: () => isAtomicWidget,
52
+ isGridTrackProperty: () => isGridTrackProperty,
51
53
  registerElementType: () => registerElementType,
52
54
  registerModelExtensions: () => registerModelExtensions,
53
55
  settingsTransformersRegistry: () => settingsTransformersRegistry,
@@ -109,27 +111,6 @@ var import_editor_mcp = require("@elementor/editor-mcp");
109
111
  var import_editor_props = require("@elementor/editor-props");
110
112
  var import_editor_styles = require("@elementor/editor-styles");
111
113
 
112
- // src/composition-builder/utils/required-default-child-tags.ts
113
- function resolveDefaultChildTemplateTagName(template) {
114
- const elementType = template.elType;
115
- if (elementType === "widget") {
116
- return typeof template.widgetType === "string" ? template.widgetType : "";
117
- }
118
- return typeof elementType === "string" ? elementType : "";
119
- }
120
- function getRequiredDefaultChildTemplates(elementConfig) {
121
- const defaultChildren = elementConfig?.default_children;
122
- if (!Array.isArray(defaultChildren)) {
123
- return [];
124
- }
125
- return defaultChildren.filter(
126
- (child) => !!child?.meta?.required
127
- );
128
- }
129
- function getRequiredDefaultChildTagNames(elementConfig) {
130
- return getRequiredDefaultChildTemplates(elementConfig).map(resolveDefaultChildTemplateTagName).filter((tag) => Boolean(tag));
131
- }
132
-
133
114
  // src/mcp/utils/element-data-util.ts
134
115
  var import_editor_elements = require("@elementor/editor-elements");
135
116
  function hasV3Controls(controls) {
@@ -346,10 +327,6 @@ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
346
327
  ...allowedParents.length ? { allowed_parents: allowedParents } : {}
347
328
  };
348
329
  }
349
- const requiredDirectChildTags = getRequiredDefaultChildTagNames(widgetData);
350
- if (requiredDirectChildTags.length) {
351
- llmGuidance.required_direct_children = requiredDirectChildTags;
352
- }
353
330
  return {
354
331
  contents: [
355
332
  {
@@ -1892,6 +1869,27 @@ var flexTransformer = createTransformer((value) => {
1892
1869
  return null;
1893
1870
  });
1894
1871
 
1872
+ // src/transformers/styles/grid-track-renderer.ts
1873
+ var GRID_TRACK_PROPERTIES = /* @__PURE__ */ new Set(["grid-template-columns", "grid-template-rows"]);
1874
+ var isGridTrackProperty = (cssProperty) => GRID_TRACK_PROPERTIES.has(cssProperty);
1875
+ var formatGridTrackRepeat = (count) => {
1876
+ if (!Number.isFinite(count) || count < 1) {
1877
+ return null;
1878
+ }
1879
+ return `repeat(${count}, 1fr)`;
1880
+ };
1881
+
1882
+ // src/transformers/styles/grid-track-size-transformer.ts
1883
+ var gridTrackSizeTransformer = createTransformer((value) => {
1884
+ if (value.unit === "custom") {
1885
+ return value.size;
1886
+ }
1887
+ if (value.unit === "fr") {
1888
+ return formatGridTrackRepeat(Math.trunc(Number(value.size)));
1889
+ }
1890
+ return `${value.size}${value.unit}`;
1891
+ });
1892
+
1895
1893
  // src/transformers/styles/perspective-origin-transformer.ts
1896
1894
  var FALLBACK = "0px";
1897
1895
  function getVal(val) {
@@ -2022,7 +2020,7 @@ var mapToTransitionString = (value, allowedProperties) => {
2022
2020
 
2023
2021
  // src/init-style-transformers.ts
2024
2022
  function initStyleTransformers() {
2025
- styleTransformersRegistry.register("size", sizeTransformer).register("shadow", shadowTransformer).register("stroke", strokeTransformer).register(
2023
+ styleTransformersRegistry.register("size", sizeTransformer).register("grid-track-size", gridTrackSizeTransformer).register("shadow", shadowTransformer).register("stroke", strokeTransformer).register(
2026
2024
  "dimensions",
2027
2025
  createMultiPropsTransformer(
2028
2026
  ["block-start", "block-end", "inline-start", "inline-end"],
@@ -4116,46 +4114,6 @@ var validateInput = {
4116
4114
  }
4117
4115
  };
4118
4116
 
4119
- // src/composition-builder/utils/required-children-enforcer.ts
4120
- var REQUIRED_CHILD_SCHEMA_HINT = "Use the widget schema resource; under llm_guidance.required_direct_children for V4 widgets.";
4121
- var RequiredChildrenEnforcer = class {
4122
- elementType;
4123
- requiredTemplates;
4124
- constructor(elementType, widgetsCache) {
4125
- this.elementType = elementType;
4126
- this.requiredTemplates = getRequiredDefaultChildTemplates(widgetsCache[elementType]);
4127
- }
4128
- enforce(xml) {
4129
- if (this.requiredTemplates.length === 0) {
4130
- return;
4131
- }
4132
- const errors = [];
4133
- for (const rootNode of Array.from(xml.children)) {
4134
- this.collectMissingRequiredErrors(rootNode, errors);
4135
- }
4136
- if (errors.length) {
4137
- throw new Error(`${errors.join("\n")}
4138
- ${REQUIRED_CHILD_SCHEMA_HINT}`);
4139
- }
4140
- }
4141
- collectMissingRequiredErrors(node, errors) {
4142
- if (node.tagName === this.elementType) {
4143
- const existingChildTags = new Set(Array.from(node.children).map((child) => child.tagName));
4144
- const missingTags = this.requiredTemplates.map(resolveDefaultChildTemplateTagName).filter((tag) => tag && !existingChildTags.has(tag));
4145
- if (missingTags.length) {
4146
- const configurationId = node.getAttribute("configuration-id");
4147
- const location2 = configurationId ? `<${node.tagName} configuration-id="${configurationId}">` : `<${node.tagName}>`;
4148
- errors.push(
4149
- `${location2} Missing required direct child element tag(s): ${missingTags.join(", ")}.`
4150
- );
4151
- }
4152
- }
4153
- for (const childNode of Array.from(node.children)) {
4154
- this.collectMissingRequiredErrors(childNode, errors);
4155
- }
4156
- }
4157
- };
4158
-
4159
4117
  // src/composition-builder/composition-builder.ts
4160
4118
  var CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE = "createElement did not return an element container with a model.";
4161
4119
  var CompositionBuilder = class _CompositionBuilder {
@@ -4359,10 +4317,6 @@ var CompositionBuilder = class _CompositionBuilder {
4359
4317
  throw new Error(`Unknown widget type: ${node.tagName}`);
4360
4318
  }
4361
4319
  });
4362
- Object.keys(widgetsCache).forEach((elementType) => {
4363
- const requiredChildrenEnforcer = new RequiredChildrenEnforcer(elementType, widgetsCache);
4364
- requiredChildrenEnforcer.enforce(this.xml);
4365
- });
4366
4320
  const childTypeErrors = [];
4367
4321
  for (const rootChild of Array.from(this.xml.children)) {
4368
4322
  childTypeErrors.push(...this.validateChildTypes(rootChild, widgetsCache));
@@ -4441,7 +4395,6 @@ This tool support v4 elements only
4441
4395
  ## NESTED ELEMENTS
4442
4396
  Some elements have internal tree structures (nesting). When using these elements, you MUST build the FULL tree in XML.
4443
4397
  - Check \`llm_guidance.nesting\` in widget schemas for structure requirements
4444
- - \`llm_guidance.required_direct_children\` lists element types that must appear as direct child tags in XML (from widget defaults)
4445
4398
  - \`allowed_child_types\` lists which element types can be nested inside
4446
4399
  - \`allowed_parents\` lists which element types this element can be placed inside
4447
4400
 
@@ -5693,8 +5646,10 @@ function hasDoAfterRender(view) {
5693
5646
  createTransformersRegistry,
5694
5647
  doAfterRender,
5695
5648
  endDragElementFromPanel,
5649
+ formatGridTrackRepeat,
5696
5650
  init,
5697
5651
  isAtomicWidget,
5652
+ isGridTrackProperty,
5698
5653
  registerElementType,
5699
5654
  registerModelExtensions,
5700
5655
  settingsTransformersRegistry,
package/dist/index.mjs CHANGED
@@ -52,27 +52,6 @@ import {
52
52
  } from "@elementor/editor-props";
53
53
  import { getStylesSchema } from "@elementor/editor-styles";
54
54
 
55
- // src/composition-builder/utils/required-default-child-tags.ts
56
- function resolveDefaultChildTemplateTagName(template) {
57
- const elementType = template.elType;
58
- if (elementType === "widget") {
59
- return typeof template.widgetType === "string" ? template.widgetType : "";
60
- }
61
- return typeof elementType === "string" ? elementType : "";
62
- }
63
- function getRequiredDefaultChildTemplates(elementConfig) {
64
- const defaultChildren = elementConfig?.default_children;
65
- if (!Array.isArray(defaultChildren)) {
66
- return [];
67
- }
68
- return defaultChildren.filter(
69
- (child) => !!child?.meta?.required
70
- );
71
- }
72
- function getRequiredDefaultChildTagNames(elementConfig) {
73
- return getRequiredDefaultChildTemplates(elementConfig).map(resolveDefaultChildTemplateTagName).filter((tag) => Boolean(tag));
74
- }
75
-
76
55
  // src/mcp/utils/element-data-util.ts
77
56
  import { getWidgetsCache } from "@elementor/editor-elements";
78
57
  function hasV3Controls(controls) {
@@ -289,10 +268,6 @@ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
289
268
  ...allowedParents.length ? { allowed_parents: allowedParents } : {}
290
269
  };
291
270
  }
292
- const requiredDirectChildTags = getRequiredDefaultChildTagNames(widgetData);
293
- if (requiredDirectChildTags.length) {
294
- llmGuidance.required_direct_children = requiredDirectChildTags;
295
- }
296
271
  return {
297
272
  contents: [
298
273
  {
@@ -1856,6 +1831,27 @@ var flexTransformer = createTransformer((value) => {
1856
1831
  return null;
1857
1832
  });
1858
1833
 
1834
+ // src/transformers/styles/grid-track-renderer.ts
1835
+ var GRID_TRACK_PROPERTIES = /* @__PURE__ */ new Set(["grid-template-columns", "grid-template-rows"]);
1836
+ var isGridTrackProperty = (cssProperty) => GRID_TRACK_PROPERTIES.has(cssProperty);
1837
+ var formatGridTrackRepeat = (count) => {
1838
+ if (!Number.isFinite(count) || count < 1) {
1839
+ return null;
1840
+ }
1841
+ return `repeat(${count}, 1fr)`;
1842
+ };
1843
+
1844
+ // src/transformers/styles/grid-track-size-transformer.ts
1845
+ var gridTrackSizeTransformer = createTransformer((value) => {
1846
+ if (value.unit === "custom") {
1847
+ return value.size;
1848
+ }
1849
+ if (value.unit === "fr") {
1850
+ return formatGridTrackRepeat(Math.trunc(Number(value.size)));
1851
+ }
1852
+ return `${value.size}${value.unit}`;
1853
+ });
1854
+
1859
1855
  // src/transformers/styles/perspective-origin-transformer.ts
1860
1856
  var FALLBACK = "0px";
1861
1857
  function getVal(val) {
@@ -1986,7 +1982,7 @@ var mapToTransitionString = (value, allowedProperties) => {
1986
1982
 
1987
1983
  // src/init-style-transformers.ts
1988
1984
  function initStyleTransformers() {
1989
- styleTransformersRegistry.register("size", sizeTransformer).register("shadow", shadowTransformer).register("stroke", strokeTransformer).register(
1985
+ styleTransformersRegistry.register("size", sizeTransformer).register("grid-track-size", gridTrackSizeTransformer).register("shadow", shadowTransformer).register("stroke", strokeTransformer).register(
1990
1986
  "dimensions",
1991
1987
  createMultiPropsTransformer(
1992
1988
  ["block-start", "block-end", "inline-start", "inline-end"],
@@ -4111,46 +4107,6 @@ var validateInput = {
4111
4107
  }
4112
4108
  };
4113
4109
 
4114
- // src/composition-builder/utils/required-children-enforcer.ts
4115
- var REQUIRED_CHILD_SCHEMA_HINT = "Use the widget schema resource; under llm_guidance.required_direct_children for V4 widgets.";
4116
- var RequiredChildrenEnforcer = class {
4117
- elementType;
4118
- requiredTemplates;
4119
- constructor(elementType, widgetsCache) {
4120
- this.elementType = elementType;
4121
- this.requiredTemplates = getRequiredDefaultChildTemplates(widgetsCache[elementType]);
4122
- }
4123
- enforce(xml) {
4124
- if (this.requiredTemplates.length === 0) {
4125
- return;
4126
- }
4127
- const errors = [];
4128
- for (const rootNode of Array.from(xml.children)) {
4129
- this.collectMissingRequiredErrors(rootNode, errors);
4130
- }
4131
- if (errors.length) {
4132
- throw new Error(`${errors.join("\n")}
4133
- ${REQUIRED_CHILD_SCHEMA_HINT}`);
4134
- }
4135
- }
4136
- collectMissingRequiredErrors(node, errors) {
4137
- if (node.tagName === this.elementType) {
4138
- const existingChildTags = new Set(Array.from(node.children).map((child) => child.tagName));
4139
- const missingTags = this.requiredTemplates.map(resolveDefaultChildTemplateTagName).filter((tag) => tag && !existingChildTags.has(tag));
4140
- if (missingTags.length) {
4141
- const configurationId = node.getAttribute("configuration-id");
4142
- const location2 = configurationId ? `<${node.tagName} configuration-id="${configurationId}">` : `<${node.tagName}>`;
4143
- errors.push(
4144
- `${location2} Missing required direct child element tag(s): ${missingTags.join(", ")}.`
4145
- );
4146
- }
4147
- }
4148
- for (const childNode of Array.from(node.children)) {
4149
- this.collectMissingRequiredErrors(childNode, errors);
4150
- }
4151
- }
4152
- };
4153
-
4154
4110
  // src/composition-builder/composition-builder.ts
4155
4111
  var CREATE_ELEMENT_INVALID_CONTAINER_MESSAGE = "createElement did not return an element container with a model.";
4156
4112
  var CompositionBuilder = class _CompositionBuilder {
@@ -4354,10 +4310,6 @@ var CompositionBuilder = class _CompositionBuilder {
4354
4310
  throw new Error(`Unknown widget type: ${node.tagName}`);
4355
4311
  }
4356
4312
  });
4357
- Object.keys(widgetsCache).forEach((elementType) => {
4358
- const requiredChildrenEnforcer = new RequiredChildrenEnforcer(elementType, widgetsCache);
4359
- requiredChildrenEnforcer.enforce(this.xml);
4360
- });
4361
4313
  const childTypeErrors = [];
4362
4314
  for (const rootChild of Array.from(this.xml.children)) {
4363
4315
  childTypeErrors.push(...this.validateChildTypes(rootChild, widgetsCache));
@@ -4436,7 +4388,6 @@ This tool support v4 elements only
4436
4388
  ## NESTED ELEMENTS
4437
4389
  Some elements have internal tree structures (nesting). When using these elements, you MUST build the FULL tree in XML.
4438
4390
  - Check \`llm_guidance.nesting\` in widget schemas for structure requirements
4439
- - \`llm_guidance.required_direct_children\` lists element types that must appear as direct child tags in XML (from widget defaults)
4440
4391
  - \`allowed_child_types\` lists which element types can be nested inside
4441
4392
  - \`allowed_parents\` lists which element types this element can be placed inside
4442
4393
 
@@ -5704,8 +5655,10 @@ export {
5704
5655
  createTransformersRegistry,
5705
5656
  doAfterRender,
5706
5657
  endDragElementFromPanel,
5658
+ formatGridTrackRepeat,
5707
5659
  init,
5708
5660
  isAtomicWidget,
5661
+ isGridTrackProperty,
5709
5662
  registerElementType,
5710
5663
  registerModelExtensions,
5711
5664
  settingsTransformersRegistry,
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.2.0-877",
4
+ "version": "4.2.0-879",
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.2.0-877",
40
+ "@elementor/editor": "4.2.0-879",
41
41
  "dompurify": "^3.2.6",
42
- "@elementor/editor-controls": "4.2.0-877",
43
- "@elementor/editor-documents": "4.2.0-877",
44
- "@elementor/editor-elements": "4.2.0-877",
45
- "@elementor/editor-interactions": "4.2.0-877",
46
- "@elementor/editor-mcp": "4.2.0-877",
47
- "@elementor/editor-notifications": "4.2.0-877",
48
- "@elementor/editor-props": "4.2.0-877",
49
- "@elementor/editor-responsive": "4.2.0-877",
50
- "@elementor/editor-styles": "4.2.0-877",
51
- "@elementor/editor-styles-repository": "4.2.0-877",
52
- "@elementor/editor-ui": "4.2.0-877",
53
- "@elementor/editor-v1-adapters": "4.2.0-877",
54
- "@elementor/schema": "4.2.0-877",
55
- "@elementor/twing": "4.2.0-877",
42
+ "@elementor/editor-controls": "4.2.0-879",
43
+ "@elementor/editor-documents": "4.2.0-879",
44
+ "@elementor/editor-elements": "4.2.0-879",
45
+ "@elementor/editor-interactions": "4.2.0-879",
46
+ "@elementor/editor-mcp": "4.2.0-879",
47
+ "@elementor/editor-notifications": "4.2.0-879",
48
+ "@elementor/editor-props": "4.2.0-879",
49
+ "@elementor/editor-responsive": "4.2.0-879",
50
+ "@elementor/editor-styles": "4.2.0-879",
51
+ "@elementor/editor-styles-repository": "4.2.0-879",
52
+ "@elementor/editor-ui": "4.2.0-879",
53
+ "@elementor/editor-v1-adapters": "4.2.0-879",
54
+ "@elementor/schema": "4.2.0-879",
55
+ "@elementor/twing": "4.2.0-879",
56
56
  "@elementor/ui": "1.37.5",
57
- "@elementor/utils": "4.2.0-877",
58
- "@elementor/wp-media": "4.2.0-877",
57
+ "@elementor/utils": "4.2.0-879",
58
+ "@elementor/wp-media": "4.2.0-879",
59
59
  "@floating-ui/react": "^0.27.5",
60
60
  "@wordpress/i18n": "^5.13.0"
61
61
  },
@@ -1,4 +1,4 @@
1
- import { type CreateElementParams, type V1Element, type V1ElementConfig } from '@elementor/editor-elements';
1
+ import { type V1Element } from '@elementor/editor-elements';
2
2
 
3
3
  import { CompositionBuilder } from '../composition-builder';
4
4
 
@@ -188,189 +188,3 @@ describe( 'CompositionBuilder.build applyProperties after create', () => {
188
188
  expect( doUpdateElementProperty ).not.toHaveBeenCalled();
189
189
  } );
190
190
  } );
191
-
192
- describe( 'CompositionBuilder.build required children', () => {
193
- it( 'rejects build when required direct children are absent from XML', async () => {
194
- // Arrange
195
- let elementIdSequence = 0;
196
- const createdElement = createMockPartialContainer( GENERATED_ELEMENT_ID );
197
- const createElementMock = jest.fn().mockReturnValue( createdElement );
198
- const formWidgetsCache = {
199
- 'e-form': {
200
- title: 'Form',
201
- controls: {},
202
- elType: 'widget',
203
- default_children: [
204
- {
205
- elType: 'e-form-success-message',
206
- meta: { required: true },
207
- elements: [],
208
- },
209
- {
210
- elType: 'e-form-error-message',
211
- meta: { required: true },
212
- elements: [],
213
- },
214
- {
215
- elType: 'widget',
216
- widgetType: 'e-form-input',
217
- elements: [],
218
- },
219
- ],
220
- },
221
- 'e-form-error-message': {
222
- title: 'Error',
223
- controls: {},
224
- elType: 'e-form-error-message',
225
- },
226
- 'e-form-input': { title: 'Input', controls: {}, elType: 'widget' },
227
- 'e-form-success-message': {
228
- title: 'Success',
229
- controls: {},
230
- elType: 'e-form-success-message',
231
- },
232
- } as Record< string, V1ElementConfig >;
233
- const builder = CompositionBuilder.fromXMLString(
234
- '<e-form configuration-id="form-1"><e-form-input /></e-form>',
235
- {
236
- createElement: createElementMock,
237
- deleteElement: jest.fn(),
238
- getContainer: jest.fn(),
239
- generateElementId: jest.fn().mockImplementation( () => `form-comp-${ ++elementIdSequence }` ),
240
- getWidgetsCache: jest.fn().mockReturnValue( formWidgetsCache ),
241
- doUpdateElementProperty: jest.fn(),
242
- }
243
- );
244
-
245
- // Act & Assert
246
- await expect( builder.build( createMockRootContainer() ) ).rejects.toThrow(
247
- /Missing required direct child element tag\(s\): e-form-success-message, e-form-error-message/
248
- );
249
- expect( createElementMock ).not.toHaveBeenCalled();
250
- } );
251
-
252
- it( 'rejects build when only some required direct children exist', async () => {
253
- // Arrange
254
- let elementIdSequence = 0;
255
- const createdElement = createMockPartialContainer( GENERATED_ELEMENT_ID );
256
- const createElementMock = jest.fn().mockReturnValue( createdElement );
257
- const formWidgetsCache = {
258
- 'e-form': {
259
- title: 'Form',
260
- controls: {},
261
- elType: 'widget',
262
- default_children: [
263
- {
264
- elType: 'e-form-success-message',
265
- meta: { required: true },
266
- elements: [],
267
- },
268
- {
269
- elType: 'e-form-error-message',
270
- meta: { required: true },
271
- elements: [],
272
- },
273
- {
274
- elType: 'widget',
275
- widgetType: 'e-form-input',
276
- elements: [],
277
- },
278
- ],
279
- },
280
- 'e-form-error-message': {
281
- title: 'Error',
282
- controls: {},
283
- elType: 'e-form-error-message',
284
- },
285
- 'e-form-input': { title: 'Input', controls: {}, elType: 'widget' },
286
- 'e-form-success-message': {
287
- title: 'Success',
288
- controls: {},
289
- elType: 'e-form-success-message',
290
- },
291
- } as Record< string, V1ElementConfig >;
292
- const builder = CompositionBuilder.fromXMLString(
293
- '<e-form configuration-id="form-1"><e-form-success-message /><e-form-input /></e-form>',
294
- {
295
- createElement: createElementMock,
296
- deleteElement: jest.fn(),
297
- getContainer: jest.fn(),
298
- generateElementId: jest.fn().mockImplementation( () => `form-comp-${ ++elementIdSequence }` ),
299
- getWidgetsCache: jest.fn().mockReturnValue( formWidgetsCache ),
300
- doUpdateElementProperty: jest.fn(),
301
- }
302
- );
303
-
304
- // Act & Assert
305
- await expect( builder.build( createMockRootContainer() ) ).rejects.toThrow(
306
- /Missing required direct child element tag\(s\): e-form-error-message/
307
- );
308
- expect( createElementMock ).not.toHaveBeenCalled();
309
- } );
310
-
311
- it( 'creates elements when XML includes all required direct children', async () => {
312
- // Arrange
313
- let elementIdSequence = 0;
314
- const createdElement = createMockPartialContainer( GENERATED_ELEMENT_ID );
315
- const createElementMock = jest.fn().mockReturnValue( createdElement );
316
- const formWidgetsCache = {
317
- 'e-form': {
318
- title: 'Form',
319
- controls: {},
320
- elType: 'widget',
321
- default_children: [
322
- {
323
- elType: 'e-form-success-message',
324
- meta: { required: true },
325
- elements: [],
326
- },
327
- {
328
- elType: 'e-form-error-message',
329
- meta: { required: true },
330
- elements: [],
331
- },
332
- {
333
- elType: 'widget',
334
- widgetType: 'e-form-input',
335
- elements: [],
336
- },
337
- ],
338
- },
339
- 'e-form-error-message': {
340
- title: 'Error',
341
- controls: {},
342
- elType: 'e-form-error-message',
343
- },
344
- 'e-form-input': { title: 'Input', controls: {}, elType: 'widget' },
345
- 'e-form-success-message': {
346
- title: 'Success',
347
- controls: {},
348
- elType: 'e-form-success-message',
349
- },
350
- } as Record< string, V1ElementConfig >;
351
- const builder = CompositionBuilder.fromXMLString(
352
- '<e-form configuration-id="form-1">' +
353
- '<e-form-success-message /><e-form-error-message /><e-form-input />' +
354
- '</e-form>',
355
- {
356
- createElement: createElementMock,
357
- deleteElement: jest.fn(),
358
- getContainer: jest.fn(),
359
- generateElementId: jest.fn().mockImplementation( () => `form-comp-${ ++elementIdSequence }` ),
360
- getWidgetsCache: jest.fn().mockReturnValue( formWidgetsCache ),
361
- doUpdateElementProperty: jest.fn(),
362
- }
363
- );
364
-
365
- // Act
366
- await builder.build( createMockRootContainer() );
367
-
368
- // Assert
369
- const createArgs = createElementMock.mock.calls[ 0 ]?.[ 0 ] as CreateElementParams;
370
- const childElements = ( createArgs.model?.elements || [] ) as Array< { elType?: string; widgetType?: string } >;
371
-
372
- expect( childElements.filter( ( child ) => child.elType === 'e-form-success-message' ).length ).toBe( 1 );
373
- expect( childElements.filter( ( child ) => child.elType === 'e-form-error-message' ).length ).toBe( 1 );
374
- expect( childElements.some( ( child ) => child.widgetType === 'e-form-input' ) ).toBe( true );
375
- } );
376
- } );
@@ -13,7 +13,6 @@ import { type z } from '@elementor/schema';
13
13
 
14
14
  import { doUpdateElementProperty } from '../mcp/utils/do-update-element-property';
15
15
  import { validateInput } from '../mcp/utils/validate-input';
16
- import { RequiredChildrenEnforcer } from './utils/required-children-enforcer';
17
16
 
18
17
  type AnyValue = z.infer< z.ZodTypeAny >;
19
18
  type AnyConfig = Record< string, Record< string, AnyValue > >;
@@ -281,11 +280,6 @@ export class CompositionBuilder {
281
280
  }
282
281
  } );
283
282
 
284
- Object.keys( widgetsCache ).forEach( ( elementType ) => {
285
- const requiredChildrenEnforcer = new RequiredChildrenEnforcer( elementType, widgetsCache );
286
- requiredChildrenEnforcer.enforce( this.xml );
287
- } );
288
-
289
283
  const childTypeErrors: string[] = [];
290
284
  for ( const rootChild of Array.from( this.xml.children ) ) {
291
285
  childTypeErrors.push( ...this.validateChildTypes( rootChild, widgetsCache ) );
package/src/index.ts CHANGED
@@ -26,6 +26,7 @@ export { DOCUMENT_STRUCTURE_URI } from './mcp/resources/document-structure-resou
26
26
  export { WIDGET_SCHEMA_URI } from './mcp/resources/widgets-schema-resource';
27
27
  export * from './legacy/types';
28
28
  export { createTransformer } from './transformers/create-transformer';
29
+ export { formatGridTrackRepeat, isGridTrackProperty } from './transformers/styles/grid-track-renderer';
29
30
  export {
30
31
  createTransformersRegistry,
31
32
  stylesInheritanceTransformersRegistry,
@@ -13,6 +13,7 @@ import { createCombineArrayTransformer } from './transformers/styles/create-comb
13
13
  import { createMultiPropsTransformer } from './transformers/styles/create-multi-props-transformer';
14
14
  import { filterTransformer } from './transformers/styles/filter-transformer';
15
15
  import { flexTransformer } from './transformers/styles/flex-transformer';
16
+ import { gridTrackSizeTransformer } from './transformers/styles/grid-track-size-transformer';
16
17
  import { perspectiveOriginTransformer } from './transformers/styles/perspective-origin-transformer';
17
18
  import { positionTransformer } from './transformers/styles/position-transformer';
18
19
  import { shadowTransformer } from './transformers/styles/shadow-transformer';
@@ -30,6 +31,7 @@ import { transitionTransformer } from './transformers/styles/transition-transfor
30
31
  export function initStyleTransformers() {
31
32
  styleTransformersRegistry
32
33
  .register( 'size', sizeTransformer )
34
+ .register( 'grid-track-size', gridTrackSizeTransformer )
33
35
  .register( 'shadow', shadowTransformer )
34
36
  .register( 'stroke', strokeTransformer )
35
37
  .register(
@@ -11,7 +11,6 @@ import {
11
11
  } from '@elementor/editor-props';
12
12
  import { getStylesSchema } from '@elementor/editor-styles';
13
13
 
14
- import { getRequiredDefaultChildTagNames } from '../../composition-builder/utils/required-default-child-tags';
15
14
  import { hasV3Controls, isWidgetAvailableForLLM } from '../utils/element-data-util';
16
15
 
17
16
  const V3_LAYOUT_CONTROL_TYPES = new Set( [ 'section', 'tab', 'tabs' ] );
@@ -223,11 +222,6 @@ Variables from the user context ARE NOT SUPPORTED AND WILL RESOLVE IN ERROR.
223
222
  };
224
223
  }
225
224
 
226
- const requiredDirectChildTags = getRequiredDefaultChildTagNames( widgetData );
227
- if ( requiredDirectChildTags.length ) {
228
- llmGuidance.required_direct_children = requiredDirectChildTags;
229
- }
230
-
231
225
  return {
232
226
  contents: [
233
227
  {
@@ -30,7 +30,6 @@ This tool support v4 elements only
30
30
  ## NESTED ELEMENTS
31
31
  Some elements have internal tree structures (nesting). When using these elements, you MUST build the FULL tree in XML.
32
32
  - Check \`llm_guidance.nesting\` in widget schemas for structure requirements
33
- - \`llm_guidance.required_direct_children\` lists element types that must appear as direct child tags in XML (from widget defaults)
34
33
  - \`allowed_child_types\` lists which element types can be nested inside
35
34
  - \`allowed_parents\` lists which element types this element can be placed inside
36
35
 
@@ -0,0 +1,11 @@
1
+ const GRID_TRACK_PROPERTIES = new Set( [ 'grid-template-columns', 'grid-template-rows' ] );
2
+
3
+ export const isGridTrackProperty = ( cssProperty: string ): boolean => GRID_TRACK_PROPERTIES.has( cssProperty );
4
+
5
+ export const formatGridTrackRepeat = ( count: number ): string | null => {
6
+ if ( ! Number.isFinite( count ) || count < 1 ) {
7
+ return null;
8
+ }
9
+
10
+ return `repeat(${ count }, 1fr)`;
11
+ };
@@ -0,0 +1,19 @@
1
+ import { createTransformer } from '../create-transformer';
2
+ import { formatGridTrackRepeat } from './grid-track-renderer';
3
+
4
+ type GridTrackSize = {
5
+ size?: number | string;
6
+ unit?: string;
7
+ };
8
+
9
+ export const gridTrackSizeTransformer = createTransformer( ( value: GridTrackSize ) => {
10
+ if ( value.unit === 'custom' ) {
11
+ return value.size;
12
+ }
13
+
14
+ if ( value.unit === 'fr' ) {
15
+ return formatGridTrackRepeat( Math.trunc( Number( value.size ) ) );
16
+ }
17
+
18
+ return `${ value.size }${ value.unit }`;
19
+ } );
@@ -1,79 +0,0 @@
1
- import { type V1ElementConfig } from '@elementor/editor-elements';
2
-
3
- import { RequiredChildrenEnforcer } from '../required-children-enforcer';
4
-
5
- describe( 'RequiredChildrenEnforcer', () => {
6
- const FULL_FORM_DIRECT_CHILD_COUNT = 3;
7
-
8
- const createWidgetsCache = (): Record< string, V1ElementConfig > => ( {
9
- 'e-form': {
10
- title: 'Form',
11
- controls: {},
12
- elType: 'widget',
13
- default_children: [
14
- {
15
- elType: 'e-form-success-message',
16
- meta: { required: true },
17
- elements: [],
18
- },
19
- {
20
- elType: 'e-form-error-message',
21
- meta: { required: true },
22
- elements: [],
23
- },
24
- {
25
- elType: 'widget',
26
- widgetType: 'e-form-input',
27
- elements: [],
28
- },
29
- ],
30
- } as V1ElementConfig,
31
- 'e-form-input': { title: 'Input', controls: {}, elType: 'widget' } as V1ElementConfig,
32
- 'e-form-success-message': {
33
- title: 'Success',
34
- controls: {},
35
- elType: 'e-form-success-message',
36
- } as V1ElementConfig,
37
- 'e-form-error-message': {
38
- title: 'Error',
39
- controls: {},
40
- elType: 'e-form-error-message',
41
- } as V1ElementConfig,
42
- } );
43
-
44
- it( 'throws when required direct children are missing', () => {
45
- // Arrange
46
- const xml = new DOMParser().parseFromString( '<e-form><e-form-input /></e-form>', 'application/xml' );
47
- const enforcer = new RequiredChildrenEnforcer( 'e-form', createWidgetsCache() );
48
-
49
- // Act & Assert
50
- expect( () => enforcer.enforce( xml ) ).toThrow(
51
- /Missing required direct child element tag\(s\): e-form-success-message, e-form-error-message/
52
- );
53
- } );
54
-
55
- it( 'throws when only some required direct children exist', () => {
56
- // Arrange
57
- const xml = new DOMParser().parseFromString( '<e-form><e-form-success-message /></e-form>', 'application/xml' );
58
- const enforcer = new RequiredChildrenEnforcer( 'e-form', createWidgetsCache() );
59
-
60
- // Act & Assert
61
- expect( () => enforcer.enforce( xml ) ).toThrow(
62
- /Missing required direct child element tag\(s\): e-form-error-message/
63
- );
64
- } );
65
-
66
- it( 'does not throw when all required direct children exist', () => {
67
- // Arrange
68
- const xmlStr = '<e-form><e-form-success-message /><e-form-error-message /><e-form-input /></e-form>';
69
- const xml = new DOMParser().parseFromString( xmlStr, 'application/xml' );
70
- const enforcer = new RequiredChildrenEnforcer( 'e-form', createWidgetsCache() );
71
-
72
- // Act
73
- expect( () => enforcer.enforce( xml ) ).not.toThrow();
74
-
75
- // Assert
76
- const form = xml.querySelector( 'e-form' );
77
- expect( form?.children.length ).toBe( FULL_FORM_DIRECT_CHILD_COUNT );
78
- } );
79
- } );
@@ -1,46 +0,0 @@
1
- import { type V1ElementConfig } from '@elementor/editor-elements';
2
-
3
- import { getRequiredDefaultChildTagNames, resolveDefaultChildTemplateTagName } from '../required-default-child-tags';
4
-
5
- describe( 'required-default-child-tags', () => {
6
- it( 'returns XML tag names for default children marked meta.required', () => {
7
- // Arrange
8
- const config = {
9
- title: 'Form',
10
- controls: {},
11
- default_children: [
12
- {
13
- elType: 'e-form-success-message',
14
- meta: { required: true },
15
- elements: [],
16
- },
17
- {
18
- elType: 'widget',
19
- widgetType: 'e-form-input',
20
- meta: { required: true },
21
- },
22
- {
23
- elType: 'e-form-label',
24
- elements: [],
25
- },
26
- ],
27
- } as unknown as V1ElementConfig;
28
-
29
- // Act
30
- const tags = getRequiredDefaultChildTagNames( config );
31
-
32
- // Assert
33
- expect( tags ).toEqual( [ 'e-form-success-message', 'e-form-input' ] );
34
- } );
35
-
36
- it( 'resolveDefaultChildTemplateTagName uses widgetType when elType is widget', () => {
37
- // Arrange
38
- const template = { elType: 'widget', widgetType: 'e-form-submit-button' };
39
-
40
- // Act
41
- const tag = resolveDefaultChildTemplateTagName( template );
42
-
43
- // Assert
44
- expect( tag ).toBe( 'e-form-submit-button' );
45
- } );
46
- } );
@@ -1,60 +0,0 @@
1
- import { type V1ElementConfig } from '@elementor/editor-elements';
2
-
3
- import {
4
- type DefaultChildTemplate,
5
- getRequiredDefaultChildTemplates,
6
- resolveDefaultChildTemplateTagName,
7
- } from './required-default-child-tags';
8
-
9
- const REQUIRED_CHILD_SCHEMA_HINT =
10
- 'Use the widget schema resource; under llm_guidance.required_direct_children for V4 widgets.';
11
-
12
- export class RequiredChildrenEnforcer {
13
- private readonly elementType: string;
14
- private readonly requiredTemplates: DefaultChildTemplate[];
15
-
16
- constructor( elementType: string, widgetsCache: Record< string, V1ElementConfig > ) {
17
- this.elementType = elementType;
18
- this.requiredTemplates = getRequiredDefaultChildTemplates( widgetsCache[ elementType ] );
19
- }
20
-
21
- enforce( xml: Document ) {
22
- if ( this.requiredTemplates.length === 0 ) {
23
- return;
24
- }
25
-
26
- const errors: string[] = [];
27
-
28
- for ( const rootNode of Array.from( xml.children ) ) {
29
- this.collectMissingRequiredErrors( rootNode, errors );
30
- }
31
-
32
- if ( errors.length ) {
33
- throw new Error( `${ errors.join( '\n' ) }\n${ REQUIRED_CHILD_SCHEMA_HINT }` );
34
- }
35
- }
36
-
37
- private collectMissingRequiredErrors( node: Element, errors: string[] ) {
38
- if ( node.tagName === this.elementType ) {
39
- const existingChildTags = new Set( Array.from( node.children ).map( ( child ) => child.tagName ) );
40
- const missingTags = this.requiredTemplates
41
- .map( resolveDefaultChildTemplateTagName )
42
- .filter( ( tag ) => tag && ! existingChildTags.has( tag ) ) as string[];
43
-
44
- if ( missingTags.length ) {
45
- const configurationId = node.getAttribute( 'configuration-id' );
46
- const location = configurationId
47
- ? `<${ node.tagName } configuration-id="${ configurationId }">`
48
- : `<${ node.tagName }>`;
49
-
50
- errors.push(
51
- `${ location } Missing required direct child element tag(s): ${ missingTags.join( ', ' ) }.`
52
- );
53
- }
54
- }
55
-
56
- for ( const childNode of Array.from( node.children ) ) {
57
- this.collectMissingRequiredErrors( childNode, errors );
58
- }
59
- }
60
- }
@@ -1,31 +0,0 @@
1
- import { type V1ElementConfig } from '@elementor/editor-elements';
2
-
3
- export type DefaultChildTemplate = Record< string, unknown >;
4
-
5
- export function resolveDefaultChildTemplateTagName( template: DefaultChildTemplate ): string {
6
- const elementType = template.elType;
7
-
8
- if ( elementType === 'widget' ) {
9
- return typeof template.widgetType === 'string' ? template.widgetType : '';
10
- }
11
-
12
- return typeof elementType === 'string' ? elementType : '';
13
- }
14
-
15
- export function getRequiredDefaultChildTemplates( elementConfig: V1ElementConfig | undefined ): DefaultChildTemplate[] {
16
- const defaultChildren = elementConfig?.default_children;
17
-
18
- if ( ! Array.isArray( defaultChildren ) ) {
19
- return [];
20
- }
21
-
22
- return defaultChildren.filter(
23
- ( child ): child is DefaultChildTemplate => !! ( child as { meta?: { required?: boolean } } )?.meta?.required
24
- );
25
- }
26
-
27
- export function getRequiredDefaultChildTagNames( elementConfig: V1ElementConfig | undefined ): string[] {
28
- return getRequiredDefaultChildTemplates( elementConfig )
29
- .map( resolveDefaultChildTemplateTagName )
30
- .filter( ( tag ) => Boolean( tag ) );
31
- }