@elementor/editor-canvas 4.0.0-551 → 4.0.0-564
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 +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +123 -130
- package/dist/index.mjs +130 -133
- package/package.json +18 -18
- package/src/init-settings-transformers.ts +2 -0
- package/src/legacy/__tests__/twig-rendering-utils.test.ts +115 -0
- package/src/legacy/create-nested-templated-element-type.ts +18 -26
- package/src/legacy/create-templated-element-type.ts +26 -96
- package/src/legacy/replacements/inline-editing/__tests__/inline-editing-eligibility.test.ts +7 -7
- package/src/legacy/replacements/inline-editing/canvas-inline-editor.tsx +0 -3
- package/src/legacy/replacements/inline-editing/inline-editing-elements.tsx +20 -8
- package/src/legacy/replacements/inline-editing/inline-editing-eligibility.ts +6 -6
- package/src/legacy/tabs-model-extensions.ts +2 -2
- package/src/legacy/twig-rendering-utils.ts +110 -51
- package/src/legacy/types.ts +2 -0
- package/src/mcp/tools/build-composition/schema.ts +4 -1
- package/src/renderers/__tests__/create-dom-renderer.test.ts +0 -1
- package/src/renderers/__tests__/create-styles-renderer.test.ts +0 -1
- package/src/transformers/settings/html-v2-transformer.ts +10 -0
package/dist/index.mjs
CHANGED
|
@@ -1204,6 +1204,11 @@ var dateTimeTransformer = createTransformer((values) => {
|
|
|
1204
1204
|
}).join(" ");
|
|
1205
1205
|
});
|
|
1206
1206
|
|
|
1207
|
+
// src/transformers/settings/html-v2-transformer.ts
|
|
1208
|
+
var htmlV2Transformer = createTransformer((value) => {
|
|
1209
|
+
return value?.content ?? "";
|
|
1210
|
+
});
|
|
1211
|
+
|
|
1207
1212
|
// src/transformers/settings/link-transformer.ts
|
|
1208
1213
|
var linkTransformer = createTransformer(({ destination, isTargetBlank, tag }) => {
|
|
1209
1214
|
return {
|
|
@@ -1258,7 +1263,7 @@ var plainTransformer = createTransformer((value) => {
|
|
|
1258
1263
|
|
|
1259
1264
|
// src/init-settings-transformers.ts
|
|
1260
1265
|
function initSettingsTransformers() {
|
|
1261
|
-
settingsTransformersRegistry.register("classes", createClassesTransformer()).register("link", linkTransformer).register("query", queryTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).register("attributes", attributesTransformer).register("date-time", dateTimeTransformer).registerFallback(plainTransformer);
|
|
1266
|
+
settingsTransformersRegistry.register("classes", createClassesTransformer()).register("link", linkTransformer).register("query", queryTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).register("attributes", attributesTransformer).register("date-time", dateTimeTransformer).register("html-v2", htmlV2Transformer).registerFallback(plainTransformer);
|
|
1262
1267
|
}
|
|
1263
1268
|
|
|
1264
1269
|
// src/transformers/styles/background-color-overlay-transformer.ts
|
|
@@ -1723,9 +1728,9 @@ function createElementViewClassDeclaration() {
|
|
|
1723
1728
|
import { ELEMENT_STYLE_CHANGE_EVENT } from "@elementor/editor-elements";
|
|
1724
1729
|
|
|
1725
1730
|
// src/legacy/twig-rendering-utils.ts
|
|
1726
|
-
function
|
|
1731
|
+
function createTwigRenderState({ renderer, element }) {
|
|
1727
1732
|
const templateKey = element.twig_main_template;
|
|
1728
|
-
const
|
|
1733
|
+
const cacheState = createRenderCacheState();
|
|
1729
1734
|
Object.entries(element.twig_templates).forEach(([key, template]) => {
|
|
1730
1735
|
renderer.register(key, template);
|
|
1731
1736
|
});
|
|
@@ -1733,7 +1738,7 @@ function setupTwigRenderer({ renderer, element }) {
|
|
|
1733
1738
|
transformers: settingsTransformersRegistry,
|
|
1734
1739
|
schema: element.atomic_props_schema
|
|
1735
1740
|
});
|
|
1736
|
-
return { templateKey,
|
|
1741
|
+
return { templateKey, resolveProps, renderer, cacheState };
|
|
1737
1742
|
}
|
|
1738
1743
|
function createBeforeRender(view) {
|
|
1739
1744
|
view._ensureViewIsIntact();
|
|
@@ -1746,47 +1751,91 @@ function createAfterRender(view) {
|
|
|
1746
1751
|
view.isRendered = true;
|
|
1747
1752
|
view.triggerMethod("render", view);
|
|
1748
1753
|
}
|
|
1754
|
+
function createRenderCacheState() {
|
|
1755
|
+
return {
|
|
1756
|
+
lastResolvedSettingsHash: null,
|
|
1757
|
+
domUpdateWasSkipped: false,
|
|
1758
|
+
invalidate() {
|
|
1759
|
+
this.lastResolvedSettingsHash = null;
|
|
1760
|
+
this.domUpdateWasSkipped = false;
|
|
1761
|
+
}
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1749
1764
|
async function renderTwigTemplate({
|
|
1750
1765
|
view,
|
|
1751
1766
|
signal,
|
|
1752
|
-
|
|
1753
|
-
templateKey,
|
|
1754
|
-
baseStylesDictionary,
|
|
1755
|
-
type,
|
|
1756
|
-
renderer,
|
|
1767
|
+
renderState,
|
|
1757
1768
|
buildContext,
|
|
1758
|
-
attachContent
|
|
1769
|
+
attachContent,
|
|
1770
|
+
afterSettingsResolve
|
|
1759
1771
|
}) {
|
|
1760
1772
|
view.triggerMethod("before:render:template");
|
|
1761
|
-
|
|
1773
|
+
const { resolveProps, cacheState, renderer, templateKey } = renderState;
|
|
1774
|
+
if (signal?.aborted) {
|
|
1762
1775
|
return;
|
|
1763
1776
|
}
|
|
1764
1777
|
const settings = view.model.get("settings").toJSON();
|
|
1765
|
-
|
|
1778
|
+
let resolvedSettings = await resolveProps({
|
|
1766
1779
|
props: settings,
|
|
1767
1780
|
signal,
|
|
1768
1781
|
renderContext: view.getResolverRenderContext?.()
|
|
1769
1782
|
});
|
|
1770
|
-
if (signal
|
|
1783
|
+
if (signal?.aborted) {
|
|
1771
1784
|
return;
|
|
1772
1785
|
}
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1786
|
+
if (afterSettingsResolve) {
|
|
1787
|
+
resolvedSettings = afterSettingsResolve(resolvedSettings);
|
|
1788
|
+
}
|
|
1789
|
+
const settingsHash = JSON.stringify(resolvedSettings);
|
|
1790
|
+
const settingsChanged = settingsHash !== cacheState.lastResolvedSettingsHash;
|
|
1791
|
+
if (!settingsChanged && view.isRendered) {
|
|
1792
|
+
cacheState.domUpdateWasSkipped = true;
|
|
1793
|
+
view.bindUIElements();
|
|
1794
|
+
view.triggerMethod("render:template");
|
|
1795
|
+
return;
|
|
1781
1796
|
}
|
|
1797
|
+
cacheState.domUpdateWasSkipped = false;
|
|
1798
|
+
cacheState.lastResolvedSettingsHash = settingsHash;
|
|
1799
|
+
const context = buildContext(resolvedSettings);
|
|
1782
1800
|
const html = await renderer.render(templateKey, context);
|
|
1783
|
-
if (signal
|
|
1801
|
+
if (signal?.aborted) {
|
|
1784
1802
|
return;
|
|
1785
1803
|
}
|
|
1786
1804
|
attachContent(html);
|
|
1787
1805
|
view.bindUIElements();
|
|
1788
1806
|
view.triggerMethod("render:template");
|
|
1789
1807
|
}
|
|
1808
|
+
function collectChildrenRenderPromises(children) {
|
|
1809
|
+
const promises = [];
|
|
1810
|
+
children?.each((childView) => {
|
|
1811
|
+
if (childView._currentRenderPromise) {
|
|
1812
|
+
promises.push(childView._currentRenderPromise);
|
|
1813
|
+
}
|
|
1814
|
+
});
|
|
1815
|
+
return promises;
|
|
1816
|
+
}
|
|
1817
|
+
async function renderChildrenWithOptimization({
|
|
1818
|
+
children,
|
|
1819
|
+
domUpdateWasSkipped,
|
|
1820
|
+
renderChildren
|
|
1821
|
+
}) {
|
|
1822
|
+
const shouldReuseChildren = domUpdateWasSkipped && !!children?.length;
|
|
1823
|
+
if (shouldReuseChildren) {
|
|
1824
|
+
rerenderExistingChildViews(children);
|
|
1825
|
+
} else {
|
|
1826
|
+
renderChildren();
|
|
1827
|
+
}
|
|
1828
|
+
const promises = collectChildrenRenderPromises(children);
|
|
1829
|
+
await waitForChildrenToComplete(promises);
|
|
1830
|
+
}
|
|
1831
|
+
function rerenderExistingChildViews(children) {
|
|
1832
|
+
children?.each((childView) => childView.render());
|
|
1833
|
+
}
|
|
1834
|
+
async function waitForChildrenToComplete(promises) {
|
|
1835
|
+
if (promises.length > 0) {
|
|
1836
|
+
await Promise.all(promises);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1790
1839
|
|
|
1791
1840
|
// src/legacy/create-templated-element-type.ts
|
|
1792
1841
|
function canBeTemplated(element) {
|
|
@@ -1798,16 +1847,9 @@ function createTemplatedElementView({
|
|
|
1798
1847
|
element
|
|
1799
1848
|
}) {
|
|
1800
1849
|
const BaseView = createElementViewClassDeclaration();
|
|
1801
|
-
const {
|
|
1802
|
-
type,
|
|
1803
|
-
renderer,
|
|
1804
|
-
element
|
|
1805
|
-
});
|
|
1850
|
+
const renderState = createTwigRenderState({ renderer, element });
|
|
1806
1851
|
return class extends BaseView {
|
|
1807
|
-
|
|
1808
|
-
#childrenRenderPromises = [];
|
|
1809
|
-
#lastResolvedSettingsHash = null;
|
|
1810
|
-
#domUpdateWasSkipped = false;
|
|
1852
|
+
_abortController = null;
|
|
1811
1853
|
getTemplateType() {
|
|
1812
1854
|
return "twig";
|
|
1813
1855
|
}
|
|
@@ -1824,81 +1866,36 @@ function createTemplatedElementView({
|
|
|
1824
1866
|
return this._parent?.getResolverRenderContext?.();
|
|
1825
1867
|
}
|
|
1826
1868
|
invalidateRenderCache() {
|
|
1827
|
-
|
|
1869
|
+
renderState.cacheState.invalidate();
|
|
1828
1870
|
}
|
|
1829
1871
|
render() {
|
|
1830
|
-
this
|
|
1831
|
-
this
|
|
1832
|
-
const process = signalizedProcess(this
|
|
1872
|
+
this._abortController?.abort();
|
|
1873
|
+
this._abortController = new AbortController();
|
|
1874
|
+
const process = signalizedProcess(this._abortController.signal).then(() => this._beforeRender()).then(() => this._renderTemplate()).then(() => this._renderChildren()).then(() => this._afterRender());
|
|
1833
1875
|
this._currentRenderPromise = process.execute();
|
|
1834
1876
|
return this._currentRenderPromise;
|
|
1835
1877
|
}
|
|
1836
1878
|
async _renderChildren() {
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
super._renderChildren();
|
|
1842
|
-
}
|
|
1843
|
-
this.#collectChildrenRenderPromises();
|
|
1844
|
-
await this._waitForChildrenToComplete();
|
|
1845
|
-
}
|
|
1846
|
-
#shouldReuseChildren() {
|
|
1847
|
-
return this.#domUpdateWasSkipped && this.children?.length > 0;
|
|
1848
|
-
}
|
|
1849
|
-
#rerenderExistingChildren() {
|
|
1850
|
-
this.children?.each((childView) => {
|
|
1851
|
-
childView.render();
|
|
1879
|
+
await renderChildrenWithOptimization({
|
|
1880
|
+
children: this.children,
|
|
1881
|
+
domUpdateWasSkipped: renderState.cacheState.domUpdateWasSkipped,
|
|
1882
|
+
renderChildren: () => super._renderChildren()
|
|
1852
1883
|
});
|
|
1853
1884
|
}
|
|
1854
|
-
#collectChildrenRenderPromises() {
|
|
1855
|
-
this.children?.each((childView) => {
|
|
1856
|
-
if (childView._currentRenderPromise) {
|
|
1857
|
-
this.#childrenRenderPromises.push(childView._currentRenderPromise);
|
|
1858
|
-
}
|
|
1859
|
-
});
|
|
1860
|
-
}
|
|
1861
|
-
async _waitForChildrenToComplete() {
|
|
1862
|
-
if (this.#childrenRenderPromises.length > 0) {
|
|
1863
|
-
await Promise.all(this.#childrenRenderPromises);
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
1885
|
async _renderTemplate() {
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
signal,
|
|
1873
|
-
renderContext: this.getResolverRenderContext()
|
|
1874
|
-
});
|
|
1875
|
-
}).then((settings) => {
|
|
1876
|
-
return this.afterSettingsResolve(settings);
|
|
1877
|
-
}).then(async (settings) => {
|
|
1878
|
-
const settingsHash = JSON.stringify(settings);
|
|
1879
|
-
const settingsChanged = settingsHash !== this.#lastResolvedSettingsHash;
|
|
1880
|
-
if (!settingsChanged && this.isRendered) {
|
|
1881
|
-
this.#domUpdateWasSkipped = true;
|
|
1882
|
-
return null;
|
|
1883
|
-
}
|
|
1884
|
-
this.#domUpdateWasSkipped = false;
|
|
1885
|
-
this.#lastResolvedSettingsHash = settingsHash;
|
|
1886
|
-
const context = {
|
|
1886
|
+
await renderTwigTemplate({
|
|
1887
|
+
view: this,
|
|
1888
|
+
signal: this._abortController?.signal,
|
|
1889
|
+
renderState,
|
|
1890
|
+
buildContext: (resolvedSettings) => ({
|
|
1887
1891
|
id: this.model.get("id"),
|
|
1888
1892
|
type,
|
|
1889
|
-
settings,
|
|
1890
|
-
base_styles:
|
|
1891
|
-
}
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
if (html === null) {
|
|
1895
|
-
return;
|
|
1896
|
-
}
|
|
1897
|
-
this.$el.html(html);
|
|
1893
|
+
settings: resolvedSettings,
|
|
1894
|
+
base_styles: element.base_styles_dictionary
|
|
1895
|
+
}),
|
|
1896
|
+
attachContent: (html) => this.$el.html(html),
|
|
1897
|
+
afterSettingsResolve: (settings) => this.afterSettingsResolve(settings)
|
|
1898
1898
|
});
|
|
1899
|
-
await process.execute();
|
|
1900
|
-
this.bindUIElements();
|
|
1901
|
-
this.triggerMethod("render:template");
|
|
1902
1899
|
}
|
|
1903
1900
|
afterSettingsResolve(settings) {
|
|
1904
1901
|
return settings;
|
|
@@ -1969,11 +1966,7 @@ function createNestedTemplatedElementView({
|
|
|
1969
1966
|
element
|
|
1970
1967
|
}) {
|
|
1971
1968
|
const legacyWindow = window;
|
|
1972
|
-
const {
|
|
1973
|
-
type,
|
|
1974
|
-
renderer,
|
|
1975
|
-
element
|
|
1976
|
-
});
|
|
1969
|
+
const renderState = createTwigRenderState({ renderer, element });
|
|
1977
1970
|
const AtomicElementBaseView = legacyWindow.elementor.modules.elements.views.createAtomicElementBase(type);
|
|
1978
1971
|
const parentRenderChildren = AtomicElementBaseView.prototype._renderChildren;
|
|
1979
1972
|
const parentOpenEditingPanel = AtomicElementBaseView.prototype._openEditingPanel;
|
|
@@ -1983,6 +1976,9 @@ function createNestedTemplatedElementView({
|
|
|
1983
1976
|
getTemplateType() {
|
|
1984
1977
|
return "twig";
|
|
1985
1978
|
},
|
|
1979
|
+
invalidateRenderCache() {
|
|
1980
|
+
renderState.cacheState.invalidate();
|
|
1981
|
+
},
|
|
1986
1982
|
render() {
|
|
1987
1983
|
this._abortController?.abort();
|
|
1988
1984
|
this._abortController = new AbortController();
|
|
@@ -2010,13 +2006,12 @@ function createNestedTemplatedElementView({
|
|
|
2010
2006
|
await renderTwigTemplate({
|
|
2011
2007
|
view: this,
|
|
2012
2008
|
signal: this._abortController?.signal,
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
...context,
|
|
2009
|
+
renderState,
|
|
2010
|
+
buildContext: (resolvedSettings) => ({
|
|
2011
|
+
id: model.get("id"),
|
|
2012
|
+
type,
|
|
2013
|
+
settings: resolvedSettings,
|
|
2014
|
+
base_styles: element.base_styles_dictionary,
|
|
2020
2015
|
editor_attributes: buildEditorAttributes(model),
|
|
2021
2016
|
editor_classes: buildEditorClasses(model)
|
|
2022
2017
|
}),
|
|
@@ -2046,14 +2041,11 @@ function createNestedTemplatedElementView({
|
|
|
2046
2041
|
oldEl.innerHTML = overlayHTML + newEl.innerHTML;
|
|
2047
2042
|
},
|
|
2048
2043
|
async _renderChildren() {
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
renderPromises.push(childView._currentRenderPromise);
|
|
2054
|
-
}
|
|
2044
|
+
await renderChildrenWithOptimization({
|
|
2045
|
+
children: this.children,
|
|
2046
|
+
domUpdateWasSkipped: renderState.cacheState.domUpdateWasSkipped,
|
|
2047
|
+
renderChildren: () => parentRenderChildren.call(this)
|
|
2055
2048
|
});
|
|
2056
|
-
await Promise.all(renderPromises);
|
|
2057
2049
|
this._removeChildrenPlaceholder();
|
|
2058
2050
|
},
|
|
2059
2051
|
_removeChildrenPlaceholder() {
|
|
@@ -2136,7 +2128,11 @@ function createNestedTemplatedElementView({
|
|
|
2136
2128
|
import * as React6 from "react";
|
|
2137
2129
|
import { createRoot } from "react-dom/client";
|
|
2138
2130
|
import { getContainer, getElementLabel, getElementType as getElementType2 } from "@elementor/editor-elements";
|
|
2139
|
-
import {
|
|
2131
|
+
import {
|
|
2132
|
+
htmlV2PropTypeUtil as htmlV2PropTypeUtil2,
|
|
2133
|
+
parseHtmlChildren,
|
|
2134
|
+
stringPropTypeUtil as stringPropTypeUtil2
|
|
2135
|
+
} from "@elementor/editor-props";
|
|
2140
2136
|
import { __privateRunCommandSync as runCommandSync, getCurrentEditMode, undoable } from "@elementor/editor-v1-adapters";
|
|
2141
2137
|
import { __ as __3 } from "@wordpress/i18n";
|
|
2142
2138
|
|
|
@@ -2259,9 +2255,6 @@ var CanvasInlineEditor = ({
|
|
|
2259
2255
|
};
|
|
2260
2256
|
useOnClickOutsideIframe(onBlur);
|
|
2261
2257
|
return /* @__PURE__ */ React5.createElement(ThemeProvider, null, /* @__PURE__ */ React5.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React5.createElement("style", null, `
|
|
2262
|
-
.${EDITOR_WRAPPER_SELECTOR}, .${EDITOR_WRAPPER_SELECTOR} > * {
|
|
2263
|
-
height: 100%;
|
|
2264
|
-
}
|
|
2265
2258
|
.ProseMirror > * {
|
|
2266
2259
|
height: 100%;
|
|
2267
2260
|
}
|
|
@@ -2385,12 +2378,13 @@ var useOnClickOutsideIframe = (handleUnmount) => {
|
|
|
2385
2378
|
};
|
|
2386
2379
|
|
|
2387
2380
|
// src/legacy/replacements/inline-editing/inline-editing-eligibility.ts
|
|
2388
|
-
import {
|
|
2381
|
+
import { htmlV2PropTypeUtil, stringPropTypeUtil } from "@elementor/editor-props";
|
|
2389
2382
|
var hasKey = (propType) => {
|
|
2390
2383
|
return "key" in propType;
|
|
2391
2384
|
};
|
|
2385
|
+
var TEXT_PROP_TYPE_KEYS = /* @__PURE__ */ new Set([htmlV2PropTypeUtil.key, stringPropTypeUtil.key]);
|
|
2392
2386
|
var isCoreTextPropTypeKey = (key) => {
|
|
2393
|
-
return
|
|
2387
|
+
return TEXT_PROP_TYPE_KEYS.has(key);
|
|
2394
2388
|
};
|
|
2395
2389
|
var isAllowedBySchema = (propTypeFromSchema) => {
|
|
2396
2390
|
if (!propTypeFromSchema) {
|
|
@@ -2402,15 +2396,13 @@ var isAllowedBySchema = (propTypeFromSchema) => {
|
|
|
2402
2396
|
if (propTypeFromSchema.kind !== "union") {
|
|
2403
2397
|
return false;
|
|
2404
2398
|
}
|
|
2405
|
-
return
|
|
2406
|
-
propTypeFromSchema.prop_types[htmlPropTypeUtil.key] || propTypeFromSchema.prop_types[stringPropTypeUtil.key]
|
|
2407
|
-
);
|
|
2399
|
+
return [...TEXT_PROP_TYPE_KEYS].some((key) => propTypeFromSchema.prop_types[key]);
|
|
2408
2400
|
};
|
|
2409
2401
|
var isInlineEditingAllowed = ({ rawValue, propTypeFromSchema }) => {
|
|
2410
2402
|
if (rawValue === null || rawValue === void 0) {
|
|
2411
2403
|
return isAllowedBySchema(propTypeFromSchema);
|
|
2412
2404
|
}
|
|
2413
|
-
return
|
|
2405
|
+
return htmlV2PropTypeUtil.isValid(rawValue) || stringPropTypeUtil.isValid(rawValue);
|
|
2414
2406
|
};
|
|
2415
2407
|
|
|
2416
2408
|
// src/legacy/replacements/inline-editing/inline-editing-elements.tsx
|
|
@@ -2495,11 +2487,16 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
2495
2487
|
}
|
|
2496
2488
|
getExtractedContentValue() {
|
|
2497
2489
|
const propValue = this.getInlineEditablePropValue();
|
|
2498
|
-
return
|
|
2490
|
+
return htmlV2PropTypeUtil2.extract(propValue)?.content ?? "";
|
|
2499
2491
|
}
|
|
2500
2492
|
setContentValue(value) {
|
|
2501
2493
|
const settingKey = this.getInlineEditablePropertyName();
|
|
2502
|
-
const
|
|
2494
|
+
const html = value || "";
|
|
2495
|
+
const parsed = parseHtmlChildren(html);
|
|
2496
|
+
const valueToSave = htmlV2PropTypeUtil2.create({
|
|
2497
|
+
content: parsed.content || null,
|
|
2498
|
+
children: parsed.children
|
|
2499
|
+
});
|
|
2503
2500
|
undoable(
|
|
2504
2501
|
{
|
|
2505
2502
|
do: () => {
|
|
@@ -2528,11 +2525,11 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
2528
2525
|
return null;
|
|
2529
2526
|
}
|
|
2530
2527
|
if (propType.kind === "union") {
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2528
|
+
const textKeys = [htmlV2PropTypeUtil2.key, stringPropTypeUtil2.key];
|
|
2529
|
+
for (const key of textKeys) {
|
|
2530
|
+
if (propType.prop_types[key]) {
|
|
2531
|
+
return key;
|
|
2532
|
+
}
|
|
2536
2533
|
}
|
|
2537
2534
|
return null;
|
|
2538
2535
|
}
|
|
@@ -2753,7 +2750,7 @@ function createNestedTemplatedType(type, renderer, element) {
|
|
|
2753
2750
|
}
|
|
2754
2751
|
|
|
2755
2752
|
// src/legacy/tabs-model-extensions.ts
|
|
2756
|
-
import {
|
|
2753
|
+
import { htmlV2PropTypeUtil as htmlV2PropTypeUtil3 } from "@elementor/editor-props";
|
|
2757
2754
|
var tabModelExtensions = {
|
|
2758
2755
|
modifyDefaultChildren(elements) {
|
|
2759
2756
|
if (!Array.isArray(elements) || elements.length === 0) {
|
|
@@ -2769,7 +2766,7 @@ var tabModelExtensions = {
|
|
|
2769
2766
|
...paragraphElement,
|
|
2770
2767
|
settings: {
|
|
2771
2768
|
...paragraphElement.settings,
|
|
2772
|
-
paragraph:
|
|
2769
|
+
paragraph: htmlV2PropTypeUtil3.create({ content: `Tab ${position}`, children: [] })
|
|
2773
2770
|
}
|
|
2774
2771
|
};
|
|
2775
2772
|
return [updatedParagraph, ...elements.slice(1)];
|
|
@@ -3443,7 +3440,7 @@ var outputSchema = {
|
|
|
3443
3440
|
xmlStructure: z.string().describe(
|
|
3444
3441
|
"The built XML structure as a string. Must use this XML after completion of building the composition, it contains real IDs."
|
|
3445
3442
|
).optional(),
|
|
3446
|
-
llm_instructions: z.string().describe("Instructions what to do next, Important to follow these instructions!")
|
|
3443
|
+
llm_instructions: z.string().describe("Instructions what to do next, Important to follow these instructions!").optional()
|
|
3447
3444
|
};
|
|
3448
3445
|
|
|
3449
3446
|
// src/mcp/tools/build-composition/tool.ts
|
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.0.0-
|
|
4
|
+
"version": "4.0.0-564",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -37,24 +37,24 @@
|
|
|
37
37
|
"react-dom": "^18.3.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@elementor/editor": "4.0.0-
|
|
41
|
-
"@elementor/editor-controls": "4.0.0-
|
|
42
|
-
"@elementor/editor-documents": "4.0.0-
|
|
43
|
-
"@elementor/editor-elements": "4.0.0-
|
|
44
|
-
"@elementor/editor-interactions": "4.0.0-
|
|
45
|
-
"@elementor/editor-mcp": "4.0.0-
|
|
46
|
-
"@elementor/editor-notifications": "4.0.0-
|
|
47
|
-
"@elementor/editor-props": "4.0.0-
|
|
48
|
-
"@elementor/editor-responsive": "4.0.0-
|
|
49
|
-
"@elementor/editor-styles": "4.0.0-
|
|
50
|
-
"@elementor/editor-styles-repository": "4.0.0-
|
|
51
|
-
"@elementor/editor-ui": "4.0.0-
|
|
52
|
-
"@elementor/editor-v1-adapters": "4.0.0-
|
|
53
|
-
"@elementor/schema": "4.0.0-
|
|
54
|
-
"@elementor/twing": "4.0.0-
|
|
40
|
+
"@elementor/editor": "4.0.0-564",
|
|
41
|
+
"@elementor/editor-controls": "4.0.0-564",
|
|
42
|
+
"@elementor/editor-documents": "4.0.0-564",
|
|
43
|
+
"@elementor/editor-elements": "4.0.0-564",
|
|
44
|
+
"@elementor/editor-interactions": "4.0.0-564",
|
|
45
|
+
"@elementor/editor-mcp": "4.0.0-564",
|
|
46
|
+
"@elementor/editor-notifications": "4.0.0-564",
|
|
47
|
+
"@elementor/editor-props": "4.0.0-564",
|
|
48
|
+
"@elementor/editor-responsive": "4.0.0-564",
|
|
49
|
+
"@elementor/editor-styles": "4.0.0-564",
|
|
50
|
+
"@elementor/editor-styles-repository": "4.0.0-564",
|
|
51
|
+
"@elementor/editor-ui": "4.0.0-564",
|
|
52
|
+
"@elementor/editor-v1-adapters": "4.0.0-564",
|
|
53
|
+
"@elementor/schema": "4.0.0-564",
|
|
54
|
+
"@elementor/twing": "4.0.0-564",
|
|
55
55
|
"@elementor/ui": "1.36.17",
|
|
56
|
-
"@elementor/utils": "4.0.0-
|
|
57
|
-
"@elementor/wp-media": "4.0.0-
|
|
56
|
+
"@elementor/utils": "4.0.0-564",
|
|
57
|
+
"@elementor/wp-media": "4.0.0-564",
|
|
58
58
|
"@floating-ui/react": "^0.27.5",
|
|
59
59
|
"@wordpress/i18n": "^5.13.0"
|
|
60
60
|
},
|
|
@@ -2,6 +2,7 @@ import { settingsTransformersRegistry } from './settings-transformers-registry';
|
|
|
2
2
|
import { attributesTransformer } from './transformers/settings/attributes-transformer';
|
|
3
3
|
import { createClassesTransformer } from './transformers/settings/classes-transformer';
|
|
4
4
|
import { dateTimeTransformer } from './transformers/settings/date-time-transformer';
|
|
5
|
+
import { htmlV2Transformer } from './transformers/settings/html-v2-transformer';
|
|
5
6
|
import { linkTransformer } from './transformers/settings/link-transformer';
|
|
6
7
|
import { queryTransformer } from './transformers/settings/query-transformer';
|
|
7
8
|
import { imageSrcTransformer } from './transformers/shared/image-src-transformer';
|
|
@@ -17,5 +18,6 @@ export function initSettingsTransformers() {
|
|
|
17
18
|
.register( 'image-src', imageSrcTransformer )
|
|
18
19
|
.register( 'attributes', attributesTransformer )
|
|
19
20
|
.register( 'date-time', dateTimeTransformer )
|
|
21
|
+
.register( 'html-v2', htmlV2Transformer )
|
|
20
22
|
.registerFallback( plainTransformer );
|
|
21
23
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ChildrenCollection,
|
|
3
|
+
collectChildrenRenderPromises,
|
|
4
|
+
createRenderCacheState,
|
|
5
|
+
renderChildrenWithOptimization,
|
|
6
|
+
} from '../twig-rendering-utils';
|
|
7
|
+
|
|
8
|
+
describe( 'twig-rendering-utils', () => {
|
|
9
|
+
describe( 'createRenderCacheState', () => {
|
|
10
|
+
it( 'should initialize with empty state and reset on invalidate', () => {
|
|
11
|
+
// Act
|
|
12
|
+
const state = createRenderCacheState();
|
|
13
|
+
|
|
14
|
+
// Assert
|
|
15
|
+
expect( state.lastResolvedSettingsHash ).toBeNull();
|
|
16
|
+
expect( state.domUpdateWasSkipped ).toBe( false );
|
|
17
|
+
|
|
18
|
+
// Arrange
|
|
19
|
+
state.lastResolvedSettingsHash = 'test-hash';
|
|
20
|
+
state.domUpdateWasSkipped = true;
|
|
21
|
+
|
|
22
|
+
// Act
|
|
23
|
+
state.invalidate();
|
|
24
|
+
|
|
25
|
+
// Assert
|
|
26
|
+
expect( state.lastResolvedSettingsHash ).toBeNull();
|
|
27
|
+
expect( state.domUpdateWasSkipped ).toBe( false );
|
|
28
|
+
} );
|
|
29
|
+
} );
|
|
30
|
+
|
|
31
|
+
describe( 'collectChildrenRenderPromises', () => {
|
|
32
|
+
it( 'should return empty array when children is undefined', () => {
|
|
33
|
+
expect( collectChildrenRenderPromises( undefined ) ).toEqual( [] );
|
|
34
|
+
} );
|
|
35
|
+
|
|
36
|
+
it( 'should collect only existing render promises from children', () => {
|
|
37
|
+
// Arrange
|
|
38
|
+
const promise1 = Promise.resolve();
|
|
39
|
+
const promise2 = Promise.resolve();
|
|
40
|
+
|
|
41
|
+
const children = createMockChildren( [
|
|
42
|
+
{ _currentRenderPromise: promise1 },
|
|
43
|
+
{ _currentRenderPromise: undefined },
|
|
44
|
+
{ _currentRenderPromise: promise2 },
|
|
45
|
+
] );
|
|
46
|
+
|
|
47
|
+
// Act
|
|
48
|
+
const result = collectChildrenRenderPromises( children );
|
|
49
|
+
|
|
50
|
+
// Assert
|
|
51
|
+
expect( result ).toEqual( [ promise1, promise2 ] );
|
|
52
|
+
} );
|
|
53
|
+
} );
|
|
54
|
+
|
|
55
|
+
describe( 'renderChildrenWithOptimization', () => {
|
|
56
|
+
it( 'should render new children when DOM was not skipped', () => {
|
|
57
|
+
// Arrange
|
|
58
|
+
const renderChildren = jest.fn();
|
|
59
|
+
|
|
60
|
+
// Act
|
|
61
|
+
renderChildrenWithOptimization( {
|
|
62
|
+
children: createMockChildren( [] ),
|
|
63
|
+
domUpdateWasSkipped: false,
|
|
64
|
+
renderChildren,
|
|
65
|
+
} );
|
|
66
|
+
|
|
67
|
+
// Assert
|
|
68
|
+
expect( renderChildren ).toHaveBeenCalled();
|
|
69
|
+
} );
|
|
70
|
+
|
|
71
|
+
it( 'should rerender existing children when DOM update was skipped', () => {
|
|
72
|
+
// Arrange
|
|
73
|
+
const renderChildren = jest.fn();
|
|
74
|
+
const childView1 = { render: jest.fn() };
|
|
75
|
+
const childView2 = { render: jest.fn() };
|
|
76
|
+
|
|
77
|
+
// Act
|
|
78
|
+
renderChildrenWithOptimization( {
|
|
79
|
+
children: createMockChildren( [ childView1, childView2 ] ),
|
|
80
|
+
domUpdateWasSkipped: true,
|
|
81
|
+
renderChildren,
|
|
82
|
+
} );
|
|
83
|
+
|
|
84
|
+
// Assert
|
|
85
|
+
expect( renderChildren ).not.toHaveBeenCalled();
|
|
86
|
+
expect( childView1.render ).toHaveBeenCalled();
|
|
87
|
+
expect( childView2.render ).toHaveBeenCalled();
|
|
88
|
+
} );
|
|
89
|
+
|
|
90
|
+
it( 'should safely fall back to renderChildren when skipped but children are empty to handle emptyView', () => {
|
|
91
|
+
// Arrange
|
|
92
|
+
const renderChildren = jest.fn();
|
|
93
|
+
|
|
94
|
+
// Act
|
|
95
|
+
renderChildrenWithOptimization( {
|
|
96
|
+
children: undefined,
|
|
97
|
+
domUpdateWasSkipped: true,
|
|
98
|
+
renderChildren,
|
|
99
|
+
} );
|
|
100
|
+
|
|
101
|
+
// Assert
|
|
102
|
+
expect( renderChildren ).toHaveBeenCalled();
|
|
103
|
+
} );
|
|
104
|
+
} );
|
|
105
|
+
} );
|
|
106
|
+
|
|
107
|
+
function createMockChildren( items: Record< string, unknown >[] ): ChildrenCollection {
|
|
108
|
+
return {
|
|
109
|
+
length: items.length,
|
|
110
|
+
findByIndex: jest.fn(),
|
|
111
|
+
each: jest.fn( ( callback ) => {
|
|
112
|
+
items.forEach( ( item ) => callback( item ) );
|
|
113
|
+
} ),
|
|
114
|
+
} as unknown as ChildrenCollection;
|
|
115
|
+
}
|