@elementor/editor-canvas 4.0.0-683 → 4.0.0-beta5
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 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +260 -79
- package/dist/index.mjs +261 -80
- package/package.json +19 -18
- package/src/components/__tests__/style-renderer.test.tsx +4 -0
- package/src/hooks/__tests__/use-style-items.test.ts +119 -0
- package/src/hooks/use-style-items.ts +39 -15
- package/src/init-settings-transformers.ts +2 -0
- package/src/legacy/create-nested-templated-element-type.ts +15 -2
- package/src/legacy/create-templated-element-type.ts +8 -0
- package/src/legacy/replacements/base.ts +4 -0
- package/src/legacy/replacements/inline-editing/canvas-inline-editor.tsx +49 -27
- package/src/legacy/replacements/inline-editing/inline-editing-elements.tsx +16 -10
- package/src/legacy/replacements/inline-editing/inline-editing-utils.ts +12 -1
- package/src/legacy/replacements/manager.ts +13 -0
- package/src/legacy/types.ts +4 -0
- package/src/mcp/canvas-mcp.ts +5 -7
- package/src/mcp/resources/breakpoints-resource.ts +11 -4
- package/src/mcp/resources/document-structure-resource.ts +18 -13
- package/src/mcp/tools/build-composition/tool.ts +5 -1
- package/src/mcp/utils/__tests__/get-composition-target-container.test.ts +59 -0
- package/src/mcp/utils/get-composition-target-container.ts +15 -0
- package/src/renderers/__tests__/create-styles-renderer.test.ts +117 -0
- package/src/renderers/create-styles-renderer.ts +13 -3
- package/src/transformers/shared/__tests__/svg-src-transformer.test.ts +184 -0
- package/src/transformers/shared/svg-src-transformer.ts +87 -0
- package/src/transformers/styles/__tests__/size-transformer.test.ts +24 -0
- package/src/transformers/styles/size-transformer.ts +3 -0
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { v1ReadyEvent } from "@elementor/editor-v1-adapters";
|
|
3
3
|
var BREAKPOINTS_SCHEMA_URI = "elementor://breakpoints/list";
|
|
4
4
|
var initBreakpointsResource = (reg) => {
|
|
5
|
-
const {
|
|
5
|
+
const { resource, sendResourceUpdated } = reg;
|
|
6
6
|
const getBreakpointsList = () => {
|
|
7
7
|
const { breakpoints } = window.elementor?.config?.responsive || {};
|
|
8
8
|
if (!breakpoints) {
|
|
@@ -26,9 +26,16 @@ var initBreakpointsResource = (reg) => {
|
|
|
26
26
|
}
|
|
27
27
|
]
|
|
28
28
|
});
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
resource(
|
|
30
|
+
"breakpoints ",
|
|
31
|
+
BREAKPOINTS_SCHEMA_URI,
|
|
32
|
+
{
|
|
33
|
+
description: "Breakpoints list."
|
|
34
|
+
},
|
|
35
|
+
() => {
|
|
36
|
+
return buildResourceResponse();
|
|
37
|
+
}
|
|
38
|
+
);
|
|
32
39
|
window.addEventListener(v1ReadyEvent().name, () => {
|
|
33
40
|
sendResourceUpdated({
|
|
34
41
|
uri: BREAKPOINTS_SCHEMA_URI,
|
|
@@ -799,14 +806,22 @@ var UnknownStyleStateError = createError({
|
|
|
799
806
|
var SELECTORS_MAP = {
|
|
800
807
|
class: "."
|
|
801
808
|
};
|
|
809
|
+
var DEFAULT_BREAKPOINT = "desktop";
|
|
810
|
+
var DEFAULT_STATE = "normal";
|
|
811
|
+
function getStyleUniqueKey(style) {
|
|
812
|
+
const breakpoint = style.variants[0]?.meta?.breakpoint ?? DEFAULT_BREAKPOINT;
|
|
813
|
+
const state = style.variants[0]?.meta?.state ?? DEFAULT_STATE;
|
|
814
|
+
return `${style.id}-${breakpoint}-${state}`;
|
|
815
|
+
}
|
|
802
816
|
function createStylesRenderer({ resolve, breakpoints, selectorPrefix = "" }) {
|
|
803
817
|
return async ({ styles, signal }) => {
|
|
804
|
-
const
|
|
818
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
805
819
|
const uniqueStyles = styles.filter((style) => {
|
|
806
|
-
|
|
820
|
+
const key = getStyleUniqueKey(style);
|
|
821
|
+
if (seenKeys.has(key)) {
|
|
807
822
|
return false;
|
|
808
823
|
}
|
|
809
|
-
|
|
824
|
+
seenKeys.add(key);
|
|
810
825
|
return true;
|
|
811
826
|
});
|
|
812
827
|
const stylesCssPromises = uniqueStyles.map(async (style) => {
|
|
@@ -895,22 +910,30 @@ function useStyleItems() {
|
|
|
895
910
|
const [styleItems, setStyleItems] = useState3({});
|
|
896
911
|
const styleItemsCacheRef = useRef2(/* @__PURE__ */ new Map());
|
|
897
912
|
const providerAndSubscribers = useMemo4(() => {
|
|
898
|
-
|
|
899
|
-
|
|
913
|
+
const createEmptyCache = () => {
|
|
914
|
+
return { orderedIds: [], itemsById: /* @__PURE__ */ new Map() };
|
|
915
|
+
};
|
|
916
|
+
const getCache = (provider) => {
|
|
917
|
+
const providerKey = safeGetKey(provider);
|
|
918
|
+
if (!providerKey) {
|
|
919
|
+
return createEmptyCache();
|
|
920
|
+
}
|
|
900
921
|
if (!styleItemsCacheRef.current.has(providerKey)) {
|
|
901
|
-
styleItemsCacheRef.current.set(providerKey,
|
|
922
|
+
styleItemsCacheRef.current.set(providerKey, createEmptyCache());
|
|
902
923
|
}
|
|
903
|
-
|
|
904
|
-
|
|
924
|
+
return styleItemsCacheRef.current.get(providerKey);
|
|
925
|
+
};
|
|
926
|
+
return stylesRepository2.getProviders().map(
|
|
927
|
+
(provider) => ({
|
|
905
928
|
provider,
|
|
906
929
|
subscriber: createProviderSubscriber2({
|
|
907
930
|
provider,
|
|
908
931
|
renderStyles,
|
|
909
932
|
setStyleItems,
|
|
910
|
-
|
|
933
|
+
getCache: () => getCache(provider)
|
|
911
934
|
})
|
|
912
|
-
}
|
|
913
|
-
|
|
935
|
+
})
|
|
936
|
+
);
|
|
914
937
|
}, [renderStyles]);
|
|
915
938
|
useEffect6(() => {
|
|
916
939
|
const unsubscribes = providerAndSubscribers.map(
|
|
@@ -950,15 +973,23 @@ function stateSorter({ state: stateA }, { state: stateB }) {
|
|
|
950
973
|
function createBreakpointSorter(breakpointsOrder) {
|
|
951
974
|
return ({ breakpoint: breakpointA }, { breakpoint: breakpointB }) => breakpointsOrder.indexOf(breakpointA) - breakpointsOrder.indexOf(breakpointB);
|
|
952
975
|
}
|
|
953
|
-
function
|
|
976
|
+
function safeGetKey(provider) {
|
|
977
|
+
try {
|
|
978
|
+
return provider.getKey();
|
|
979
|
+
} catch {
|
|
980
|
+
return null;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function createProviderSubscriber2({ provider, renderStyles, setStyleItems, getCache }) {
|
|
954
984
|
return abortPreviousRuns(
|
|
955
985
|
(abortController, previous, current) => signalizedProcess(abortController.signal).then((_, signal) => {
|
|
986
|
+
const cache = getCache();
|
|
956
987
|
const hasDiffInfo = current !== void 0 && previous !== void 0;
|
|
957
988
|
const hasCache = cache.orderedIds.length > 0;
|
|
958
989
|
if (hasDiffInfo && hasCache) {
|
|
959
|
-
return updateItems(previous, current, signal);
|
|
990
|
+
return updateItems(cache, previous, current, signal);
|
|
960
991
|
}
|
|
961
|
-
return createItems(signal);
|
|
992
|
+
return createItems(cache, signal);
|
|
962
993
|
}).then((items) => {
|
|
963
994
|
setStyleItems((prev) => ({
|
|
964
995
|
...prev,
|
|
@@ -966,7 +997,7 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cach
|
|
|
966
997
|
}));
|
|
967
998
|
}).execute()
|
|
968
999
|
);
|
|
969
|
-
async function updateItems(previous, current, signal) {
|
|
1000
|
+
async function updateItems(cache, previous, current, signal) {
|
|
970
1001
|
const changedIds = getChangedStyleIds(previous, current);
|
|
971
1002
|
cache.orderedIds = provider.actions.all().map((style) => style.id).reverse();
|
|
972
1003
|
if (changedIds.length > 0) {
|
|
@@ -981,7 +1012,7 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cach
|
|
|
981
1012
|
}
|
|
982
1013
|
return getOrderedItems(cache);
|
|
983
1014
|
}
|
|
984
|
-
async function createItems(signal) {
|
|
1015
|
+
async function createItems(cache, signal) {
|
|
985
1016
|
const allStyles = provider.actions.all();
|
|
986
1017
|
const styles = [...allStyles].reverse().map((style) => {
|
|
987
1018
|
return {
|
|
@@ -991,7 +1022,7 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cach
|
|
|
991
1022
|
});
|
|
992
1023
|
return renderStyles({ styles: breakToBreakpoints(styles), signal }).then((rendered) => {
|
|
993
1024
|
rebuildCache(cache, allStyles, rendered);
|
|
994
|
-
return
|
|
1025
|
+
return getOrderedItems(cache);
|
|
995
1026
|
});
|
|
996
1027
|
}
|
|
997
1028
|
function breakToBreakpoints(styles) {
|
|
@@ -1376,14 +1407,74 @@ var plainTransformer = createTransformer((value) => {
|
|
|
1376
1407
|
return value;
|
|
1377
1408
|
});
|
|
1378
1409
|
|
|
1379
|
-
// src/transformers/shared/
|
|
1410
|
+
// src/transformers/shared/svg-src-transformer.ts
|
|
1411
|
+
import DOMPurify from "dompurify";
|
|
1380
1412
|
import { getMediaAttachment as getMediaAttachment2 } from "@elementor/wp-media";
|
|
1413
|
+
var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
|
|
1414
|
+
function processSvgContent(svgText) {
|
|
1415
|
+
const sanitized = DOMPurify.sanitize(svgText, {
|
|
1416
|
+
USE_PROFILES: { svg: true, svgFilters: true }
|
|
1417
|
+
});
|
|
1418
|
+
const parser = new DOMParser();
|
|
1419
|
+
const doc = parser.parseFromString(sanitized, "image/svg+xml");
|
|
1420
|
+
const svgElement = doc.querySelector("svg");
|
|
1421
|
+
if (!svgElement) {
|
|
1422
|
+
return null;
|
|
1423
|
+
}
|
|
1424
|
+
svgElement.setAttribute("fill", "currentColor");
|
|
1425
|
+
const existingStyle = svgElement.getAttribute("style") ?? "";
|
|
1426
|
+
const trimmed = existingStyle.trim();
|
|
1427
|
+
const merged = trimmed ? `${trimmed.replace(/;$/, "")}; ${SVG_INLINE_STYLES}` : SVG_INLINE_STYLES;
|
|
1428
|
+
svgElement.setAttribute("style", merged);
|
|
1429
|
+
return svgElement.outerHTML;
|
|
1430
|
+
}
|
|
1431
|
+
async function fetchSvgContent(url, signal) {
|
|
1432
|
+
try {
|
|
1433
|
+
const response = await fetch(url, { signal });
|
|
1434
|
+
if (!response.ok) {
|
|
1435
|
+
return null;
|
|
1436
|
+
}
|
|
1437
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1438
|
+
const isSvg = contentType.includes("svg") || contentType.includes("xml") || url.endsWith(".svg");
|
|
1439
|
+
if (!isSvg) {
|
|
1440
|
+
return null;
|
|
1441
|
+
}
|
|
1442
|
+
return await response.text();
|
|
1443
|
+
} catch {
|
|
1444
|
+
return null;
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
function resolveSvgSrcId(id) {
|
|
1448
|
+
if (typeof id !== "number" || id <= 0) {
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
return id;
|
|
1452
|
+
}
|
|
1453
|
+
var svgSrcTransformer = createTransformer(async (value, { signal }) => {
|
|
1454
|
+
const id = resolveSvgSrcId(value.id);
|
|
1455
|
+
const urlFromValue = typeof value.url === "string" ? value.url : null;
|
|
1456
|
+
let url = urlFromValue;
|
|
1457
|
+
if (id && !urlFromValue) {
|
|
1458
|
+
const attachment = await getMediaAttachment2({ id });
|
|
1459
|
+
url = attachment?.url ?? null;
|
|
1460
|
+
}
|
|
1461
|
+
const resolvedUrl = typeof url === "string" ? url : null;
|
|
1462
|
+
if (!resolvedUrl) {
|
|
1463
|
+
return { html: null, url: null };
|
|
1464
|
+
}
|
|
1465
|
+
const svgText = await fetchSvgContent(resolvedUrl, signal);
|
|
1466
|
+
const html = svgText ? processSvgContent(svgText) : null;
|
|
1467
|
+
return { html, url: resolvedUrl };
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
// src/transformers/shared/video-src-transformer.ts
|
|
1471
|
+
import { getMediaAttachment as getMediaAttachment3 } from "@elementor/wp-media";
|
|
1381
1472
|
var videoSrcTransformer = createTransformer(async (value) => {
|
|
1382
1473
|
const { id, url } = value;
|
|
1383
1474
|
if (!id) {
|
|
1384
1475
|
return { id: null, url };
|
|
1385
1476
|
}
|
|
1386
|
-
const attachment = await
|
|
1477
|
+
const attachment = await getMediaAttachment3({ id });
|
|
1387
1478
|
return {
|
|
1388
1479
|
id,
|
|
1389
1480
|
url: attachment?.url ?? url
|
|
@@ -1392,7 +1483,7 @@ var videoSrcTransformer = createTransformer(async (value) => {
|
|
|
1392
1483
|
|
|
1393
1484
|
// src/init-settings-transformers.ts
|
|
1394
1485
|
function initSettingsTransformers() {
|
|
1395
|
-
settingsTransformersRegistry.register("classes", createClassesTransformer()).register("link", linkTransformer).register("query", queryTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).register("video-src", videoSrcTransformer).register("attributes", attributesTransformer).register("date-time", dateTimeTransformer).register("html-v2", htmlV2Transformer).register("html-v3", htmlV3Transformer).registerFallback(plainTransformer);
|
|
1486
|
+
settingsTransformersRegistry.register("classes", createClassesTransformer()).register("link", linkTransformer).register("query", queryTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).register("svg-src", svgSrcTransformer).register("video-src", videoSrcTransformer).register("attributes", attributesTransformer).register("date-time", dateTimeTransformer).register("html-v2", htmlV2Transformer).register("html-v3", htmlV3Transformer).registerFallback(plainTransformer);
|
|
1396
1487
|
}
|
|
1397
1488
|
|
|
1398
1489
|
// src/transformers/styles/background-color-overlay-transformer.ts
|
|
@@ -1591,6 +1682,9 @@ var shadowTransformer = createTransformer((value) => {
|
|
|
1591
1682
|
|
|
1592
1683
|
// src/transformers/styles/size-transformer.ts
|
|
1593
1684
|
var sizeTransformer = createTransformer((value) => {
|
|
1685
|
+
if (value.unit === "auto") {
|
|
1686
|
+
return "auto";
|
|
1687
|
+
}
|
|
1594
1688
|
return value.unit === "custom" ? value.size : `${value.size}${value.unit}`;
|
|
1595
1689
|
});
|
|
1596
1690
|
|
|
@@ -1974,6 +2068,7 @@ function createTemplatedElementView({
|
|
|
1974
2068
|
this._lastResolvedSettingsHash = settingsHash;
|
|
1975
2069
|
const context = {
|
|
1976
2070
|
id: this.model.get("id"),
|
|
2071
|
+
interaction_id: this.getInteractionId(),
|
|
1977
2072
|
type,
|
|
1978
2073
|
settings,
|
|
1979
2074
|
base_styles: baseStylesDictionary
|
|
@@ -2008,6 +2103,11 @@ function createTemplatedElementView({
|
|
|
2008
2103
|
_openEditingPanel(options) {
|
|
2009
2104
|
this._doAfterRender(() => super._openEditingPanel(options));
|
|
2010
2105
|
}
|
|
2106
|
+
getInteractionId() {
|
|
2107
|
+
const originId = this.model.get("originId");
|
|
2108
|
+
const id = this.model.get("id");
|
|
2109
|
+
return originId ?? id;
|
|
2110
|
+
}
|
|
2011
2111
|
};
|
|
2012
2112
|
}
|
|
2013
2113
|
|
|
@@ -2040,10 +2140,11 @@ function createNestedTemplatedElementType({
|
|
|
2040
2140
|
}
|
|
2041
2141
|
function buildEditorAttributes(model) {
|
|
2042
2142
|
const id = model.get("id");
|
|
2143
|
+
const originId = model.get("originId");
|
|
2043
2144
|
const cid = model.cid ?? "";
|
|
2044
2145
|
const attrs = {
|
|
2045
2146
|
"data-model-cid": cid,
|
|
2046
|
-
"data-interaction-id": id,
|
|
2147
|
+
"data-interaction-id": originId ?? id,
|
|
2047
2148
|
"x-ignore": "true"
|
|
2048
2149
|
};
|
|
2049
2150
|
return Object.entries(attrs).map(([key, value]) => `${key}="${value}"`).join(" ");
|
|
@@ -2077,6 +2178,9 @@ function createNestedTemplatedElementView({
|
|
|
2077
2178
|
invalidateRenderCache() {
|
|
2078
2179
|
this._lastResolvedSettingsHash = null;
|
|
2079
2180
|
},
|
|
2181
|
+
renderOnChange() {
|
|
2182
|
+
this.render();
|
|
2183
|
+
},
|
|
2080
2184
|
render() {
|
|
2081
2185
|
this._abortController?.abort();
|
|
2082
2186
|
this._abortController = new AbortController();
|
|
@@ -2120,6 +2224,7 @@ function createNestedTemplatedElementView({
|
|
|
2120
2224
|
this._lastResolvedSettingsHash = settingsHash;
|
|
2121
2225
|
const context = {
|
|
2122
2226
|
id: model.get("id"),
|
|
2227
|
+
interaction_id: this.getInteractionId(),
|
|
2123
2228
|
type,
|
|
2124
2229
|
settings,
|
|
2125
2230
|
base_styles: baseStylesDictionary,
|
|
@@ -2249,13 +2354,20 @@ function createNestedTemplatedElementView({
|
|
|
2249
2354
|
},
|
|
2250
2355
|
_openEditingPanel(options) {
|
|
2251
2356
|
this._doAfterRender(() => parentOpenEditingPanel.call(this, options));
|
|
2357
|
+
},
|
|
2358
|
+
getInteractionId() {
|
|
2359
|
+
const originId = this.model.get("originId");
|
|
2360
|
+
const id = this.model.get("id");
|
|
2361
|
+
return originId ?? id;
|
|
2252
2362
|
}
|
|
2253
2363
|
});
|
|
2254
2364
|
}
|
|
2255
2365
|
|
|
2366
|
+
// src/legacy/replacements/manager.ts
|
|
2367
|
+
import { createRoot } from "react-dom/client";
|
|
2368
|
+
|
|
2256
2369
|
// src/legacy/replacements/inline-editing/inline-editing-elements.tsx
|
|
2257
2370
|
import * as React6 from "react";
|
|
2258
|
-
import { createRoot } from "react-dom/client";
|
|
2259
2371
|
import { getContainer, getElementLabel, getElementType as getElementType2 } from "@elementor/editor-elements";
|
|
2260
2372
|
import {
|
|
2261
2373
|
htmlV3PropTypeUtil as htmlV3PropTypeUtil2,
|
|
@@ -2278,6 +2390,8 @@ var ReplacementBase = class {
|
|
|
2278
2390
|
type;
|
|
2279
2391
|
id;
|
|
2280
2392
|
refreshView;
|
|
2393
|
+
reactRoot;
|
|
2394
|
+
reactContainer;
|
|
2281
2395
|
constructor(settings) {
|
|
2282
2396
|
this.getSetting = settings.getSetting;
|
|
2283
2397
|
this.setSetting = settings.setSetting;
|
|
@@ -2285,6 +2399,8 @@ var ReplacementBase = class {
|
|
|
2285
2399
|
this.type = settings.type;
|
|
2286
2400
|
this.id = settings.id;
|
|
2287
2401
|
this.refreshView = settings.refreshView;
|
|
2402
|
+
this.reactRoot = settings.reactRoot;
|
|
2403
|
+
this.reactContainer = settings.reactContainer;
|
|
2288
2404
|
}
|
|
2289
2405
|
static getTypes() {
|
|
2290
2406
|
return null;
|
|
@@ -2305,7 +2421,7 @@ var ReplacementBase = class {
|
|
|
2305
2421
|
|
|
2306
2422
|
// src/legacy/replacements/inline-editing/canvas-inline-editor.tsx
|
|
2307
2423
|
import * as React5 from "react";
|
|
2308
|
-
import { useEffect as useEffect8, useLayoutEffect, useState as useState5 } from "react";
|
|
2424
|
+
import { useCallback as useCallback2, useEffect as useEffect8, useLayoutEffect, useState as useState5 } from "react";
|
|
2309
2425
|
import { InlineEditor, InlineEditorToolbar } from "@elementor/editor-controls";
|
|
2310
2426
|
import { Box as Box2, ThemeProvider } from "@elementor/ui";
|
|
2311
2427
|
import { autoUpdate as autoUpdate2, flip, FloatingPortal as FloatingPortal2, useFloating as useFloating2 } from "@floating-ui/react";
|
|
@@ -2335,7 +2451,8 @@ var INLINE_EDITING_PROPERTY_PER_TYPE = {
|
|
|
2335
2451
|
"e-button": "text",
|
|
2336
2452
|
"e-form-label": "text",
|
|
2337
2453
|
"e-heading": "title",
|
|
2338
|
-
"e-paragraph": "paragraph"
|
|
2454
|
+
"e-paragraph": "paragraph",
|
|
2455
|
+
"e-form-submit-button": "text"
|
|
2339
2456
|
};
|
|
2340
2457
|
var getInlineEditorElement = (elementWrapper, expectedTag) => {
|
|
2341
2458
|
return !expectedTag ? null : elementWrapper.querySelector(expectedTag);
|
|
@@ -2353,6 +2470,11 @@ var useOnClickOutsideIframe = (handleUnmount) => {
|
|
|
2353
2470
|
};
|
|
2354
2471
|
var useRenderToolbar = (ownerDocument, id) => {
|
|
2355
2472
|
const [anchor, setAnchor] = useState4(null);
|
|
2473
|
+
useEffect7(() => {
|
|
2474
|
+
if (!anchor) {
|
|
2475
|
+
removeToolbarAnchor(ownerDocument, id);
|
|
2476
|
+
}
|
|
2477
|
+
}, [anchor, ownerDocument, id]);
|
|
2356
2478
|
const onSelectionEnd = (view) => {
|
|
2357
2479
|
const hasSelection = !view.state.selection.empty;
|
|
2358
2480
|
removeToolbarAnchor(ownerDocument, id);
|
|
@@ -2362,7 +2484,10 @@ var useRenderToolbar = (ownerDocument, id) => {
|
|
|
2362
2484
|
setAnchor(null);
|
|
2363
2485
|
}
|
|
2364
2486
|
};
|
|
2365
|
-
|
|
2487
|
+
const clearAnchor = useCallback(() => {
|
|
2488
|
+
setAnchor(null);
|
|
2489
|
+
}, []);
|
|
2490
|
+
return { onSelectionEnd, anchor, clearAnchor };
|
|
2366
2491
|
};
|
|
2367
2492
|
var createAnchorBasedOnSelection = (ownerDocument, id) => {
|
|
2368
2493
|
const frameWindow = ownerDocument.defaultView;
|
|
@@ -2429,46 +2554,59 @@ var horizontalShifterMiddleware = {
|
|
|
2429
2554
|
};
|
|
2430
2555
|
|
|
2431
2556
|
// src/legacy/replacements/inline-editing/canvas-inline-editor.tsx
|
|
2432
|
-
var EDITOR_WRAPPER_SELECTOR = "inline-editor-wrapper";
|
|
2433
2557
|
var CanvasInlineEditor = ({
|
|
2434
2558
|
elementClasses,
|
|
2435
2559
|
initialValue,
|
|
2436
2560
|
expectedTag,
|
|
2437
2561
|
rootElement,
|
|
2562
|
+
contentElement,
|
|
2438
2563
|
id,
|
|
2439
2564
|
setValue,
|
|
2440
|
-
|
|
2565
|
+
requestDestroy
|
|
2441
2566
|
}) => {
|
|
2567
|
+
const [active, setActive] = useState5(true);
|
|
2442
2568
|
const [editor, setEditor] = useState5(null);
|
|
2443
|
-
const { onSelectionEnd, anchor: toolbarAnchor } = useRenderToolbar(rootElement.ownerDocument, id);
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2569
|
+
const { onSelectionEnd, anchor: toolbarAnchor, clearAnchor } = useRenderToolbar(rootElement.ownerDocument, id);
|
|
2570
|
+
useEffect8(() => {
|
|
2571
|
+
if (!active) {
|
|
2572
|
+
clearAnchor();
|
|
2573
|
+
requestDestroy();
|
|
2574
|
+
}
|
|
2575
|
+
}, [active, clearAnchor, requestDestroy]);
|
|
2576
|
+
const dismiss = useCallback2(() => {
|
|
2577
|
+
setEditor(null);
|
|
2578
|
+
setActive(false);
|
|
2579
|
+
}, []);
|
|
2580
|
+
useOnClickOutsideIframe(dismiss);
|
|
2581
|
+
useEffect8(() => {
|
|
2582
|
+
const ownerDocument = contentElement.ownerDocument;
|
|
2583
|
+
const handleClickAway = (event) => {
|
|
2584
|
+
if (contentElement.contains(event.target)) {
|
|
2585
|
+
return;
|
|
2586
|
+
}
|
|
2587
|
+
dismiss();
|
|
2588
|
+
};
|
|
2589
|
+
ownerDocument.addEventListener("mousedown", handleClickAway);
|
|
2590
|
+
return () => ownerDocument.removeEventListener("mousedown", handleClickAway);
|
|
2591
|
+
}, [contentElement, dismiss]);
|
|
2592
|
+
if (!active) {
|
|
2593
|
+
return null;
|
|
2594
|
+
}
|
|
2595
|
+
return /* @__PURE__ */ React5.createElement(ThemeProvider, null, /* @__PURE__ */ React5.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React5.createElement(
|
|
2458
2596
|
InlineEditor,
|
|
2459
2597
|
{
|
|
2460
2598
|
onEditorCreate: setEditor,
|
|
2599
|
+
mountElement: contentElement,
|
|
2461
2600
|
editorProps: {
|
|
2462
2601
|
attributes: {
|
|
2463
|
-
style: "outline: none;
|
|
2602
|
+
style: "outline: none; display: inherit; justify-content: inherit; align-items: inherit; flex-direction: inherit; text-align: inherit;"
|
|
2464
2603
|
}
|
|
2465
2604
|
},
|
|
2466
2605
|
elementClasses,
|
|
2467
2606
|
value: initialValue,
|
|
2468
2607
|
setValue,
|
|
2469
|
-
onBlur,
|
|
2608
|
+
onBlur: dismiss,
|
|
2470
2609
|
autofocus: true,
|
|
2471
|
-
expectedTag,
|
|
2472
2610
|
onSelectionEnd
|
|
2473
2611
|
}
|
|
2474
2612
|
), toolbarAnchor && editor && /* @__PURE__ */ React5.createElement(InlineEditingToolbar, { anchor: toolbarAnchor, editor, id }));
|
|
@@ -2497,7 +2635,18 @@ var InlineEditingToolbar = ({ anchor, editor, id }) => {
|
|
|
2497
2635
|
refs.setReference(anchor);
|
|
2498
2636
|
return () => refs.setReference(null);
|
|
2499
2637
|
}, [anchor, refs]);
|
|
2500
|
-
return /* @__PURE__ */ React5.createElement(FloatingPortal2, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React5.createElement(
|
|
2638
|
+
return /* @__PURE__ */ React5.createElement(FloatingPortal2, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React5.createElement(
|
|
2639
|
+
Box2,
|
|
2640
|
+
{
|
|
2641
|
+
ref: refs.setFloating,
|
|
2642
|
+
role: "presentation",
|
|
2643
|
+
style: {
|
|
2644
|
+
...floatingStyles,
|
|
2645
|
+
pointerEvents: "none"
|
|
2646
|
+
}
|
|
2647
|
+
},
|
|
2648
|
+
/* @__PURE__ */ React5.createElement(InlineEditorToolbar, { editor, elementId: id })
|
|
2649
|
+
));
|
|
2501
2650
|
};
|
|
2502
2651
|
|
|
2503
2652
|
// src/legacy/replacements/inline-editing/inline-editing-eligibility.ts
|
|
@@ -2531,8 +2680,8 @@ var isInlineEditingAllowed = ({ rawValue, propTypeFromSchema }) => {
|
|
|
2531
2680
|
// src/legacy/replacements/inline-editing/inline-editing-elements.tsx
|
|
2532
2681
|
var HISTORY_DEBOUNCE_WAIT = 800;
|
|
2533
2682
|
var InlineEditingReplacement = class extends ReplacementBase {
|
|
2534
|
-
inlineEditorRoot = null;
|
|
2535
2683
|
handlerAttached = false;
|
|
2684
|
+
editing = false;
|
|
2536
2685
|
getReplacementKey() {
|
|
2537
2686
|
return "inline-editing";
|
|
2538
2687
|
}
|
|
@@ -2540,7 +2689,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
2540
2689
|
return Object.keys(INLINE_EDITING_PROPERTY_PER_TYPE);
|
|
2541
2690
|
}
|
|
2542
2691
|
isEditingModeActive() {
|
|
2543
|
-
return
|
|
2692
|
+
return this.editing;
|
|
2544
2693
|
}
|
|
2545
2694
|
shouldRenderReplacement() {
|
|
2546
2695
|
return this.isInlineEditingEligible() && getCurrentEditMode() === "edit";
|
|
@@ -2583,8 +2732,8 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
2583
2732
|
resetInlineEditorRoot() {
|
|
2584
2733
|
this.element.removeEventListener("click", this.handleRenderInlineEditor);
|
|
2585
2734
|
this.handlerAttached = false;
|
|
2586
|
-
this.
|
|
2587
|
-
this.
|
|
2735
|
+
this.reactRoot.render(null);
|
|
2736
|
+
this.editing = false;
|
|
2588
2737
|
}
|
|
2589
2738
|
unmountInlineEditor() {
|
|
2590
2739
|
this.resetInlineEditorRoot();
|
|
@@ -2695,12 +2844,16 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
2695
2844
|
if (this.isEditingModeActive()) {
|
|
2696
2845
|
this.resetInlineEditorRoot();
|
|
2697
2846
|
}
|
|
2698
|
-
const
|
|
2847
|
+
const contentElement = this.element.children?.[0];
|
|
2848
|
+
if (!contentElement) {
|
|
2849
|
+
return;
|
|
2850
|
+
}
|
|
2851
|
+
const elementClasses = contentElement.classList.toString();
|
|
2699
2852
|
const propValue = this.getExtractedContentValue();
|
|
2700
2853
|
const expectedTag = this.getExpectedTag();
|
|
2701
|
-
|
|
2702
|
-
this.
|
|
2703
|
-
this.
|
|
2854
|
+
contentElement.innerHTML = "";
|
|
2855
|
+
this.editing = true;
|
|
2856
|
+
this.reactRoot.render(
|
|
2704
2857
|
/* @__PURE__ */ React6.createElement(
|
|
2705
2858
|
CanvasInlineEditor,
|
|
2706
2859
|
{
|
|
@@ -2708,9 +2861,10 @@ var InlineEditingReplacement = class extends ReplacementBase {
|
|
|
2708
2861
|
initialValue: propValue,
|
|
2709
2862
|
expectedTag,
|
|
2710
2863
|
rootElement: this.element,
|
|
2864
|
+
contentElement,
|
|
2711
2865
|
id: this.id,
|
|
2712
2866
|
setValue: this.setContentValue.bind(this),
|
|
2713
|
-
|
|
2867
|
+
requestDestroy: this.unmountInlineEditor.bind(this)
|
|
2714
2868
|
}
|
|
2715
2869
|
)
|
|
2716
2870
|
);
|
|
@@ -2739,16 +2893,24 @@ var createViewWithReplacements = (options) => {
|
|
|
2739
2893
|
return class extends TemplatedView {
|
|
2740
2894
|
#replacement = null;
|
|
2741
2895
|
#config;
|
|
2896
|
+
#reactContainer;
|
|
2897
|
+
#reactRoot;
|
|
2742
2898
|
constructor(...args) {
|
|
2743
2899
|
super(...args);
|
|
2744
2900
|
const settings = this.model.get("settings");
|
|
2901
|
+
this.#reactContainer = this.el.ownerDocument.createElement("div");
|
|
2902
|
+
this.#reactContainer.style.display = "none";
|
|
2903
|
+
this.el.ownerDocument.body.appendChild(this.#reactContainer);
|
|
2904
|
+
this.#reactRoot = createRoot(this.#reactContainer);
|
|
2745
2905
|
this.#config = {
|
|
2746
2906
|
getSetting: settings.get.bind(settings),
|
|
2747
2907
|
setSetting: settings.set.bind(settings),
|
|
2748
2908
|
element: this.el,
|
|
2749
2909
|
type: this?.model?.get("widgetType") ?? this.container?.model?.get("elType") ?? null,
|
|
2750
2910
|
id: this?.model?.get("id") ?? null,
|
|
2751
|
-
refreshView: this.refreshView.bind(this)
|
|
2911
|
+
refreshView: this.refreshView.bind(this),
|
|
2912
|
+
reactRoot: this.#reactRoot,
|
|
2913
|
+
reactContainer: this.#reactContainer
|
|
2752
2914
|
};
|
|
2753
2915
|
}
|
|
2754
2916
|
refreshView() {
|
|
@@ -2769,6 +2931,8 @@ var createViewWithReplacements = (options) => {
|
|
|
2769
2931
|
}
|
|
2770
2932
|
onDestroy() {
|
|
2771
2933
|
this.#triggerAltMethod("onDestroy");
|
|
2934
|
+
this.#reactRoot.unmount();
|
|
2935
|
+
this.#reactContainer.remove();
|
|
2772
2936
|
}
|
|
2773
2937
|
_afterRender() {
|
|
2774
2938
|
this.#triggerAltMethod("_afterRender");
|
|
@@ -2907,7 +3071,7 @@ function initTabsModelExtensions() {
|
|
|
2907
3071
|
import { __privateListenTo as listenTo, commandEndEvent as commandEndEvent4 } from "@elementor/editor-v1-adapters";
|
|
2908
3072
|
var DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
|
|
2909
3073
|
var initDocumentStructureResource = (reg) => {
|
|
2910
|
-
const {
|
|
3074
|
+
const { resource, sendResourceUpdated } = reg;
|
|
2911
3075
|
let currentDocumentStructure = null;
|
|
2912
3076
|
const updateDocumentStructure = () => {
|
|
2913
3077
|
const structure = getDocumentStructure();
|
|
@@ -2929,17 +3093,23 @@ var initDocumentStructureResource = (reg) => {
|
|
|
2929
3093
|
updateDocumentStructure
|
|
2930
3094
|
);
|
|
2931
3095
|
updateDocumentStructure();
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
3096
|
+
resource(
|
|
3097
|
+
"document-structure",
|
|
3098
|
+
DOCUMENT_STRUCTURE_URI,
|
|
3099
|
+
{
|
|
3100
|
+
description: "Document structure."
|
|
3101
|
+
},
|
|
3102
|
+
async () => {
|
|
3103
|
+
return {
|
|
3104
|
+
contents: [
|
|
3105
|
+
{
|
|
3106
|
+
uri: DOCUMENT_STRUCTURE_URI,
|
|
3107
|
+
text: JSON.stringify(getDocumentStructure(), null, 2)
|
|
3108
|
+
}
|
|
3109
|
+
]
|
|
3110
|
+
};
|
|
3111
|
+
}
|
|
3112
|
+
);
|
|
2943
3113
|
};
|
|
2944
3114
|
function getDocumentStructure() {
|
|
2945
3115
|
const extendedWindow = window;
|
|
@@ -2979,6 +3149,7 @@ function extractElementData(element) {
|
|
|
2979
3149
|
}
|
|
2980
3150
|
|
|
2981
3151
|
// src/mcp/tools/build-composition/tool.ts
|
|
3152
|
+
import { getCurrentDocument } from "@elementor/editor-documents";
|
|
2982
3153
|
import {
|
|
2983
3154
|
createElement as createElement8,
|
|
2984
3155
|
deleteElement,
|
|
@@ -3409,6 +3580,16 @@ var CompositionBuilder = class _CompositionBuilder {
|
|
|
3409
3580
|
}
|
|
3410
3581
|
};
|
|
3411
3582
|
|
|
3583
|
+
// src/mcp/utils/get-composition-target-container.ts
|
|
3584
|
+
import { COMPONENT_DOCUMENT_TYPE } from "@elementor/editor-documents";
|
|
3585
|
+
function getCompositionTargetContainer(documentContainer, documentType) {
|
|
3586
|
+
const firstChild = documentContainer.children?.[0];
|
|
3587
|
+
if (documentType === COMPONENT_DOCUMENT_TYPE && firstChild) {
|
|
3588
|
+
return firstChild;
|
|
3589
|
+
}
|
|
3590
|
+
return documentContainer;
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3412
3593
|
// src/mcp/tools/build-composition/prompt.ts
|
|
3413
3594
|
import { toolPrompts } from "@elementor/editor-mcp";
|
|
3414
3595
|
var generatePrompt = () => {
|
|
@@ -3604,6 +3785,8 @@ var initBuildCompositionsTool = (reg) => {
|
|
|
3604
3785
|
const errors = [];
|
|
3605
3786
|
const rootContainers = [];
|
|
3606
3787
|
const documentContainer = getContainer3("document");
|
|
3788
|
+
const currentDocument = getCurrentDocument();
|
|
3789
|
+
const targetContainer = getCompositionTargetContainer(documentContainer, currentDocument?.type.value);
|
|
3607
3790
|
try {
|
|
3608
3791
|
const compositionBuilder = CompositionBuilder.fromXMLString(xmlStructure, {
|
|
3609
3792
|
createElement: createElement8,
|
|
@@ -3616,7 +3799,7 @@ var initBuildCompositionsTool = (reg) => {
|
|
|
3616
3799
|
configErrors,
|
|
3617
3800
|
invalidStyles,
|
|
3618
3801
|
rootContainers: generatedRootContainers
|
|
3619
|
-
} = compositionBuilder.build(
|
|
3802
|
+
} = compositionBuilder.build(targetContainer);
|
|
3620
3803
|
rootContainers.push(...generatedRootContainers);
|
|
3621
3804
|
generatedXML = new XMLSerializer().serializeToString(compositionBuilder.getXML());
|
|
3622
3805
|
if (configErrors.length) {
|
|
@@ -4000,14 +4183,12 @@ var initGetElementConfigTool = (reg) => {
|
|
|
4000
4183
|
var initCanvasMcp = (reg) => {
|
|
4001
4184
|
const { setMCPDescription } = reg;
|
|
4002
4185
|
setMCPDescription(
|
|
4003
|
-
`Everything related to
|
|
4186
|
+
`Everything related to V4 ( Atomic ) canvas.
|
|
4004
4187
|
# Canvas workflow for new compositions
|
|
4005
|
-
-
|
|
4006
|
-
-
|
|
4007
|
-
-
|
|
4008
|
-
|
|
4009
|
-
- Build valid XML with minimal inline styles (layout/positioning only)
|
|
4010
|
-
- Apply global classes to elements`
|
|
4188
|
+
- Configure elements settings and styles
|
|
4189
|
+
- Build compositions/sections out of V4 atomic elements using context aware designs using the website resources
|
|
4190
|
+
- Get and retrieve element configuration values
|
|
4191
|
+
`
|
|
4011
4192
|
);
|
|
4012
4193
|
initWidgetsSchemaResource(reg);
|
|
4013
4194
|
initDocumentStructureResource(reg);
|