@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 +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +26 -71
- package/dist/index.mjs +24 -71
- package/package.json +18 -18
- package/src/composition-builder/__tests__/composition-builder.test.ts +1 -187
- package/src/composition-builder/composition-builder.ts +0 -6
- package/src/index.ts +1 -0
- package/src/init-style-transformers.ts +2 -0
- package/src/mcp/resources/widgets-schema-resource.ts +0 -6
- package/src/mcp/tools/build-composition/prompt.ts +0 -1
- package/src/transformers/styles/grid-track-renderer.ts +11 -0
- package/src/transformers/styles/grid-track-size-transformer.ts +19 -0
- package/src/composition-builder/utils/__tests__/required-children-enforcer.test.ts +0 -79
- package/src/composition-builder/utils/__tests__/required-default-child-tags.test.ts +0 -46
- package/src/composition-builder/utils/required-children-enforcer.ts +0 -60
- package/src/composition-builder/utils/required-default-child-tags.ts +0 -31
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-
|
|
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-
|
|
40
|
+
"@elementor/editor": "4.2.0-879",
|
|
41
41
|
"dompurify": "^3.2.6",
|
|
42
|
-
"@elementor/editor-controls": "4.2.0-
|
|
43
|
-
"@elementor/editor-documents": "4.2.0-
|
|
44
|
-
"@elementor/editor-elements": "4.2.0-
|
|
45
|
-
"@elementor/editor-interactions": "4.2.0-
|
|
46
|
-
"@elementor/editor-mcp": "4.2.0-
|
|
47
|
-
"@elementor/editor-notifications": "4.2.0-
|
|
48
|
-
"@elementor/editor-props": "4.2.0-
|
|
49
|
-
"@elementor/editor-responsive": "4.2.0-
|
|
50
|
-
"@elementor/editor-styles": "4.2.0-
|
|
51
|
-
"@elementor/editor-styles-repository": "4.2.0-
|
|
52
|
-
"@elementor/editor-ui": "4.2.0-
|
|
53
|
-
"@elementor/editor-v1-adapters": "4.2.0-
|
|
54
|
-
"@elementor/schema": "4.2.0-
|
|
55
|
-
"@elementor/twing": "4.2.0-
|
|
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-
|
|
58
|
-
"@elementor/wp-media": "4.2.0-
|
|
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
|
|
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
|
-
}
|