@elementor/editor-canvas 0.15.3 → 0.17.0

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.
Files changed (33) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +45 -0
  3. package/dist/index.d.mts +4 -1
  4. package/dist/index.d.ts +4 -1
  5. package/dist/index.js +448 -281
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +437 -267
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +7 -6
  10. package/src/__tests__/styles-prop-resolver.test.ts +1 -0
  11. package/src/components/__tests__/style-renderer.test.tsx +65 -0
  12. package/src/components/style-renderer.tsx +32 -0
  13. package/src/hooks/__tests__/use-style-items.test.ts +136 -0
  14. package/src/hooks/__tests__/use-style-prop-resolver.test.ts +51 -0
  15. package/src/hooks/use-on-mount.ts +13 -0
  16. package/src/hooks/use-style-items.ts +78 -0
  17. package/src/hooks/use-style-prop-resolver.ts +22 -0
  18. package/src/hooks/use-style-renderer.ts +19 -0
  19. package/src/index.ts +1 -0
  20. package/src/init.tsx +9 -2
  21. package/src/legacy/create-element-type.ts +14 -0
  22. package/src/legacy/create-templated-element-type.ts +1 -1
  23. package/src/legacy/types.ts +9 -0
  24. package/src/prevent-link-in-link-commands.ts +132 -0
  25. package/src/renderers/__tests__/{render-styles.test.ts → create-styles-renderer.test.ts} +35 -19
  26. package/src/renderers/{render-styles.ts → create-styles-renderer.ts} +35 -32
  27. package/src/sync/{get-canvas-iframe-body.ts → get-canvas-iframe-head.ts} +2 -2
  28. package/src/sync/types.ts +7 -0
  29. package/src/utils/abort-previous-runs.ts +16 -0
  30. package/src/__tests__/init-styles-renderer.test.ts +0 -112
  31. package/src/init-styles-renderer.ts +0 -84
  32. /package/src/{legacy → utils}/__tests__/signalized-process.test.ts +0 -0
  33. /package/src/{legacy → utils}/signalized-process.ts +0 -0
package/dist/index.mjs CHANGED
@@ -132,6 +132,151 @@ function useElementsDom() {
132
132
  );
133
133
  }
134
134
 
135
+ // src/components/style-renderer.tsx
136
+ import * as React3 from "react";
137
+ import { __privateUseListenTo as useListenTo2, commandEndEvent } from "@elementor/editor-v1-adapters";
138
+ import { Portal } from "@elementor/ui";
139
+
140
+ // src/hooks/use-style-items.ts
141
+ import { useEffect as useEffect4, useMemo as useMemo3, useState as useState2 } from "react";
142
+ import { stylesRepository } from "@elementor/editor-styles-repository";
143
+ import { registerDataHook } from "@elementor/editor-v1-adapters";
144
+
145
+ // src/utils/abort-previous-runs.ts
146
+ function abortPreviousRuns(cb) {
147
+ let abortController = null;
148
+ return (...args) => {
149
+ if (abortController) {
150
+ abortController.abort();
151
+ }
152
+ abortController = new AbortController();
153
+ return cb(abortController, ...args);
154
+ };
155
+ }
156
+
157
+ // src/utils/signalized-process.ts
158
+ function signalizedProcess(signal, steps = []) {
159
+ return {
160
+ then: (cb) => {
161
+ steps.push(cb);
162
+ return signalizedProcess(signal, steps);
163
+ },
164
+ execute: async () => {
165
+ let lastResult;
166
+ for (const step of steps) {
167
+ if (signal.aborted) {
168
+ break;
169
+ }
170
+ lastResult = await step(lastResult, signal);
171
+ }
172
+ }
173
+ };
174
+ }
175
+
176
+ // src/hooks/use-on-mount.ts
177
+ import { useEffect as useEffect3, useRef } from "react";
178
+ function useOnMount(cb) {
179
+ const mounted = useRef(false);
180
+ useEffect3(() => {
181
+ if (!mounted.current) {
182
+ mounted.current = true;
183
+ cb();
184
+ }
185
+ }, []);
186
+ }
187
+
188
+ // src/hooks/use-style-prop-resolver.ts
189
+ import { useMemo } from "react";
190
+ import { getStylesSchema } from "@elementor/editor-styles";
191
+
192
+ // src/renderers/create-props-resolver.ts
193
+ import {
194
+ isTransformable
195
+ } from "@elementor/editor-props";
196
+
197
+ // src/renderers/multi-props.ts
198
+ var isMultiProps = (propValue) => {
199
+ return !!propValue && typeof propValue === "object" && "$$multi-props" in propValue && propValue["$$multi-props"] === true;
200
+ };
201
+ var createMultiPropsValue = (props) => {
202
+ return {
203
+ "$$multi-props": true,
204
+ value: props
205
+ };
206
+ };
207
+ var getMultiPropsValue = (multiProps) => {
208
+ return multiProps.value;
209
+ };
210
+
211
+ // src/renderers/create-props-resolver.ts
212
+ var TRANSFORM_DEPTH_LIMIT = 3;
213
+ function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }) {
214
+ async function resolve({ props, schema, signal }) {
215
+ schema = schema ?? initialSchema;
216
+ const promises = Promise.all(
217
+ Object.entries(schema).map(async ([key, type]) => {
218
+ const value = props[key] ?? type.default;
219
+ const transformed = await transform({ value, key, type, signal });
220
+ onPropResolve?.({ key, value: transformed });
221
+ if (isMultiProps(transformed)) {
222
+ return getMultiPropsValue(transformed);
223
+ }
224
+ return { [key]: transformed };
225
+ })
226
+ );
227
+ return Object.assign({}, ...(await promises).filter(Boolean));
228
+ }
229
+ async function transform({ value, key, type, signal, depth = 0 }) {
230
+ if (value === null || value === void 0) {
231
+ return null;
232
+ }
233
+ if (!isTransformable(value)) {
234
+ return value;
235
+ }
236
+ if (depth > TRANSFORM_DEPTH_LIMIT) {
237
+ return null;
238
+ }
239
+ if (value.disabled === true) {
240
+ return null;
241
+ }
242
+ if (type.kind === "union") {
243
+ type = type.prop_types[value.$$type];
244
+ if (!type) {
245
+ return null;
246
+ }
247
+ }
248
+ if (value.$$type !== type.key) {
249
+ return null;
250
+ }
251
+ let resolvedValue = value.value;
252
+ if (type.kind === "object") {
253
+ resolvedValue = await resolve({
254
+ props: resolvedValue,
255
+ schema: type.shape,
256
+ signal
257
+ });
258
+ }
259
+ if (type.kind === "array") {
260
+ resolvedValue = await Promise.all(
261
+ resolvedValue.map(
262
+ (item) => transform({ value: item, key, type: type.item_prop_type, depth, signal })
263
+ )
264
+ );
265
+ }
266
+ const transformer = transformers.get(value.$$type);
267
+ if (!transformer) {
268
+ return null;
269
+ }
270
+ try {
271
+ const transformed = await transformer(resolvedValue, { key, signal });
272
+ return transform({ value: transformed, key, type, signal, depth: depth + 1 });
273
+ } catch {
274
+ return null;
275
+ }
276
+ }
277
+ return resolve;
278
+ }
279
+
135
280
  // src/transformers/create-transformers-registry.ts
136
281
  function createTransformersRegistry() {
137
282
  const transformers = {};
@@ -151,6 +296,176 @@ function createTransformersRegistry() {
151
296
  };
152
297
  }
153
298
 
299
+ // src/style-transformers-registry.ts
300
+ var styleTransformersRegistry = createTransformersRegistry();
301
+
302
+ // src/sync/enqueue-font.ts
303
+ var enqueueFont = (fontFamily, context = "preview") => {
304
+ const extendedWindow = window;
305
+ return extendedWindow.elementor?.helpers?.enqueueFont?.(fontFamily, context) ?? null;
306
+ };
307
+
308
+ // src/hooks/use-style-prop-resolver.ts
309
+ function useStylePropResolver() {
310
+ return useMemo(() => {
311
+ return createPropsResolver({
312
+ transformers: styleTransformersRegistry,
313
+ schema: getStylesSchema(),
314
+ onPropResolve: ({ key, value }) => {
315
+ if (key !== "font-family" || typeof value !== "string") {
316
+ return;
317
+ }
318
+ enqueueFont(value);
319
+ }
320
+ });
321
+ }, []);
322
+ }
323
+
324
+ // src/hooks/use-style-renderer.ts
325
+ import { useMemo as useMemo2 } from "react";
326
+ import { useBreakpointsMap } from "@elementor/editor-responsive";
327
+
328
+ // src/renderers/errors.ts
329
+ import { createError } from "@elementor/utils";
330
+ var UnknownStyleTypeError = createError({
331
+ code: "unknown_style_type",
332
+ message: "Unknown style type"
333
+ });
334
+
335
+ // src/renderers/create-styles-renderer.ts
336
+ var SELECTORS_MAP = {
337
+ class: "."
338
+ };
339
+ function createStylesRenderer({ resolve, breakpoints, selectorPrefix = "" }) {
340
+ return async ({ styles, signal }) => {
341
+ const stylesCssPromises = styles.map(async (style) => {
342
+ const variantCssPromises = Object.values(style.variants).map(async (variant) => {
343
+ const css = await propsToCss({ props: variant.props, resolve, signal });
344
+ return createStyleWrapper().forStyle(style).withPrefix(selectorPrefix).withState(variant.meta.state).withMediaQuery(variant.meta.breakpoint ? breakpoints[variant.meta.breakpoint] : null).wrap(css);
345
+ });
346
+ const variantsCss = await Promise.all(variantCssPromises);
347
+ return {
348
+ id: style.id,
349
+ value: variantsCss.join("")
350
+ };
351
+ });
352
+ return await Promise.all(stylesCssPromises);
353
+ };
354
+ }
355
+ function createStyleWrapper(value = "", wrapper) {
356
+ return {
357
+ forStyle: ({ id, type }) => {
358
+ const symbol = SELECTORS_MAP[type];
359
+ if (!symbol) {
360
+ throw new UnknownStyleTypeError({ context: { type } });
361
+ }
362
+ return createStyleWrapper(`${value}${symbol}${id}`, wrapper);
363
+ },
364
+ withPrefix: (prefix) => createStyleWrapper([prefix, value].filter(Boolean).join(" "), wrapper),
365
+ withState: (state) => createStyleWrapper(state ? `${value}:${state}` : value, wrapper),
366
+ withMediaQuery: (breakpoint) => {
367
+ if (!breakpoint?.type) {
368
+ return createStyleWrapper(value, wrapper);
369
+ }
370
+ const size2 = `${breakpoint.type}:${breakpoint.width}px`;
371
+ return createStyleWrapper(value, (css) => `@media(${size2}){${css}}`);
372
+ },
373
+ wrap: (css) => {
374
+ const res = `${value}{${css}}`;
375
+ if (!wrapper) {
376
+ return res;
377
+ }
378
+ return wrapper(res);
379
+ }
380
+ };
381
+ }
382
+ async function propsToCss({ props, resolve, signal }) {
383
+ const transformed = await resolve({ props, signal });
384
+ return Object.entries(transformed).reduce((acc, [propName, propValue]) => {
385
+ if (propValue === null) {
386
+ return acc;
387
+ }
388
+ acc.push(propName + ":" + propValue + ";");
389
+ return acc;
390
+ }, []).join("");
391
+ }
392
+
393
+ // src/hooks/use-style-renderer.ts
394
+ var SELECTOR_PREFIX = ".elementor";
395
+ function useStyleRenderer(resolve) {
396
+ const breakpoints = useBreakpointsMap();
397
+ return useMemo2(() => {
398
+ return createStylesRenderer({
399
+ selectorPrefix: SELECTOR_PREFIX,
400
+ breakpoints,
401
+ resolve
402
+ });
403
+ }, [resolve, breakpoints]);
404
+ }
405
+
406
+ // src/hooks/use-style-items.ts
407
+ function useStyleItems() {
408
+ const resolve = useStylePropResolver();
409
+ const renderStyles = useStyleRenderer(resolve);
410
+ const [styleItems, setStyleItems] = useState2({});
411
+ const providerAndSubscribers = useMemo3(() => {
412
+ return stylesRepository.getProviders().map((provider) => {
413
+ return {
414
+ provider,
415
+ subscriber: createProviderSubscriber({
416
+ provider,
417
+ renderStyles,
418
+ setStyleItems
419
+ })
420
+ };
421
+ });
422
+ }, [renderStyles]);
423
+ useEffect4(() => {
424
+ const unsubscribes = providerAndSubscribers.map(
425
+ ({ provider, subscriber }) => provider.subscribe(subscriber)
426
+ );
427
+ return () => {
428
+ unsubscribes.forEach((unsubscribe) => unsubscribe());
429
+ };
430
+ }, [providerAndSubscribers]);
431
+ useOnMount(() => {
432
+ registerDataHook("after", "editor/documents/attach-preview", async () => {
433
+ const promises = providerAndSubscribers.map(async ({ subscriber }) => subscriber());
434
+ await Promise.all(promises);
435
+ });
436
+ });
437
+ return Object.values(styleItems).sort(({ provider: providerA }, { provider: providerB }) => providerA.priority - providerB.priority).flatMap(({ items }) => items);
438
+ }
439
+ function createProviderSubscriber({ provider, renderStyles, setStyleItems }) {
440
+ return abortPreviousRuns(
441
+ (abortController) => signalizedProcess(abortController.signal).then((_, signal) => renderStyles({ styles: provider.actions.get(), signal })).then((items) => {
442
+ setStyleItems((prev) => ({
443
+ ...prev,
444
+ [provider.key]: { provider, items }
445
+ }));
446
+ }).execute()
447
+ );
448
+ }
449
+
450
+ // src/sync/get-canvas-iframe-head.ts
451
+ function getCanvasIframeHead() {
452
+ const extendedWindow = window;
453
+ return extendedWindow.elementor?.$preview?.[0]?.contentDocument?.head;
454
+ }
455
+
456
+ // src/components/style-renderer.tsx
457
+ function StyleRenderer() {
458
+ const container = usePortalContainer();
459
+ const styleItems = useStyleItems();
460
+ if (!container) {
461
+ return null;
462
+ }
463
+ return /* @__PURE__ */ React3.createElement(Portal, { container }, /* @__PURE__ */ React3.createElement(React3.Fragment, null, styleItems.map((item) => /* @__PURE__ */ React3.createElement("style", { "data-e-style-id": item.id, key: item.id }, item.value))));
464
+ }
465
+ function usePortalContainer() {
466
+ return useListenTo2(commandEndEvent("editor/documents/attach-preview"), () => getCanvasIframeHead());
467
+ }
468
+
154
469
  // src/settings-transformers-registry.ts
155
470
  var settingsTransformersRegistry = createTransformersRegistry();
156
471
 
@@ -215,9 +530,6 @@ function initSettingsTransformers() {
215
530
  settingsTransformersRegistry.register("classes", arrayTransformer).register("link", linkTransformer).register("image", imageTransformer).register("image-src", imageSrcTransformer).registerFallback(plainTransformer);
216
531
  }
217
532
 
218
- // src/style-transformers-registry.ts
219
- var styleTransformersRegistry = createTransformersRegistry();
220
-
221
533
  // src/transformers/styles/background-color-overlay-transformer.ts
222
534
  var backgroundColorOverlayTransformer = createTransformer((value) => {
223
535
  const { color = null } = value;
@@ -279,20 +591,6 @@ var createCombineArrayTransformer = (delimiter) => {
279
591
  return createTransformer((value) => value.filter(Boolean).join(delimiter));
280
592
  };
281
593
 
282
- // src/renderers/multi-props.ts
283
- var isMultiProps = (propValue) => {
284
- return !!propValue && typeof propValue === "object" && "$$multi-props" in propValue && propValue["$$multi-props"] === true;
285
- };
286
- var createMultiPropsValue = (props) => {
287
- return {
288
- "$$multi-props": true,
289
- value: props
290
- };
291
- };
292
- var getMultiPropsValue = (multiProps) => {
293
- return multiProps.value;
294
- };
295
-
296
594
  // src/transformers/styles/create-multi-props-transformer.ts
297
595
  var createMultiPropsTransformer = (keys, keyGenerator) => {
298
596
  return createTransformer((value, { key: propKey }) => {
@@ -347,223 +645,9 @@ function initStyleTransformers() {
347
645
  ).registerFallback(plainTransformer);
348
646
  }
349
647
 
350
- // src/init-styles-renderer.ts
351
- import { getBreakpointsMap } from "@elementor/editor-responsive";
352
- import { getStylesSchema } from "@elementor/editor-styles";
353
- import { stylesRepository } from "@elementor/editor-styles-repository";
354
- import { __privateListenTo as listenTo, registerDataHook, v1ReadyEvent } from "@elementor/editor-v1-adapters";
355
-
356
- // src/renderers/create-props-resolver.ts
357
- import {
358
- isTransformable
359
- } from "@elementor/editor-props";
360
- var TRANSFORM_DEPTH_LIMIT = 3;
361
- function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }) {
362
- async function resolve({ props, schema, signal }) {
363
- schema = schema ?? initialSchema;
364
- const promises = Promise.all(
365
- Object.entries(schema).map(async ([key, type]) => {
366
- const value = props[key] ?? type.default;
367
- const transformed = await transform({ value, key, type, signal });
368
- onPropResolve?.({ key, value: transformed });
369
- if (isMultiProps(transformed)) {
370
- return getMultiPropsValue(transformed);
371
- }
372
- return { [key]: transformed };
373
- })
374
- );
375
- return Object.assign({}, ...(await promises).filter(Boolean));
376
- }
377
- async function transform({ value, key, type, signal, depth = 0 }) {
378
- if (value === null || value === void 0) {
379
- return null;
380
- }
381
- if (!isTransformable(value)) {
382
- return value;
383
- }
384
- if (depth > TRANSFORM_DEPTH_LIMIT) {
385
- return null;
386
- }
387
- if (value.disabled === true) {
388
- return null;
389
- }
390
- if (type.kind === "union") {
391
- type = type.prop_types[value.$$type];
392
- if (!type) {
393
- return null;
394
- }
395
- }
396
- if (value.$$type !== type.key) {
397
- return null;
398
- }
399
- let resolvedValue = value.value;
400
- if (type.kind === "object") {
401
- resolvedValue = await resolve({
402
- props: resolvedValue,
403
- schema: type.shape,
404
- signal
405
- });
406
- }
407
- if (type.kind === "array") {
408
- resolvedValue = await Promise.all(
409
- resolvedValue.map(
410
- (item) => transform({ value: item, key, type: type.item_prop_type, depth, signal })
411
- )
412
- );
413
- }
414
- const transformer = transformers.get(value.$$type);
415
- if (!transformer) {
416
- return null;
417
- }
418
- try {
419
- const transformed = await transformer(resolvedValue, { key, signal });
420
- return transform({ value: transformed, key, type, signal, depth: depth + 1 });
421
- } catch {
422
- return null;
423
- }
424
- }
425
- return resolve;
426
- }
427
-
428
- // src/renderers/errors.ts
429
- import { createError } from "@elementor/utils";
430
- var UnknownStyleTypeError = createError({
431
- code: "unknown_style_type",
432
- message: "Unknown style type"
433
- });
434
-
435
- // src/renderers/render-styles.ts
436
- var SELECTORS_MAP = {
437
- class: "."
438
- };
439
- async function renderStyles({
440
- resolve,
441
- styles,
442
- breakpoints,
443
- selectorPrefix = "",
444
- signal
445
- }) {
446
- const stylesCssPromises = styles.map(async (style) => {
447
- const variantCssPromises = Object.values(style.variants).map(async (variant) => {
448
- const css = await propsToCss({ props: variant.props, resolve, signal });
449
- return createStyleWrapper().forStyle(style).withPrefix(selectorPrefix).withState(variant.meta.state).withMediaQuery(variant.meta.breakpoint ? breakpoints[variant.meta.breakpoint] : null).wrap(css);
450
- });
451
- const variantsCss = await Promise.all(variantCssPromises);
452
- return wrapCssWithStyleElement(style.id, variantsCss.join(""));
453
- });
454
- const stylesCss = await Promise.all(stylesCssPromises);
455
- return stylesCss.join("");
456
- }
457
- function createStyleWrapper(value = "", wrapper) {
458
- return {
459
- forStyle: ({ id, type }) => {
460
- const symbol = SELECTORS_MAP[type];
461
- if (!symbol) {
462
- throw new UnknownStyleTypeError({ context: { type } });
463
- }
464
- return createStyleWrapper(`${value}${symbol}${id}`, wrapper);
465
- },
466
- withPrefix: (prefix) => createStyleWrapper([prefix, value].filter(Boolean).join(" "), wrapper),
467
- withState: (state) => createStyleWrapper(state ? `${value}:${state}` : value, wrapper),
468
- withMediaQuery: (breakpoint) => {
469
- if (!breakpoint?.type) {
470
- return createStyleWrapper(value, wrapper);
471
- }
472
- const size2 = `${breakpoint.type}:${breakpoint.width}px`;
473
- return createStyleWrapper(value, (css) => `@media(${size2}){${css}}`);
474
- },
475
- wrap: (css) => {
476
- const res = `${value}{${css}}`;
477
- if (!wrapper) {
478
- return res;
479
- }
480
- return wrapper(res);
481
- }
482
- };
483
- }
484
- async function propsToCss({ props, resolve, signal }) {
485
- const transformed = await resolve({ props, signal });
486
- return Object.entries(transformed).reduce((acc, [propName, propValue]) => {
487
- if (propValue === null) {
488
- return acc;
489
- }
490
- acc.push(propName + ":" + propValue + ";");
491
- return acc;
492
- }, []).join("");
493
- }
494
- function wrapCssWithStyleElement(id, css) {
495
- return `<style data-style-id="${id}">${css}</style>`;
496
- }
497
-
498
- // src/sync/enqueue-font.ts
499
- var enqueueFont = (fontFamily, context = "preview") => {
500
- const extendedWindow = window;
501
- return extendedWindow.elementor?.helpers?.enqueueFont?.(fontFamily, context) ?? null;
502
- };
503
-
504
- // src/sync/get-canvas-iframe-body.ts
505
- function getCanvasIframeBody() {
506
- const extendedWindow = window;
507
- return extendedWindow.elementor?.$preview?.[0]?.contentDocument?.body;
508
- }
509
-
510
- // src/init-styles-renderer.ts
511
- var WRAPPER_DATA_ATTR = "data-styles-container";
512
- var SELECTOR_PREFIX = ".elementor";
513
- function initStylesRenderer() {
514
- listenTo(v1ReadyEvent(), () => {
515
- let abortController = null;
516
- const resolve = createPropsResolver({
517
- transformers: styleTransformersRegistry,
518
- schema: getStylesSchema(),
519
- onPropResolve: enqueueUsedFonts
520
- });
521
- const injectStyleElements = async () => {
522
- const styleContainer = getStylesContainer();
523
- const styles = stylesRepository.all().reverse();
524
- const breakpoints = getBreakpointsMap();
525
- if (abortController) {
526
- abortController.abort();
527
- }
528
- abortController = new AbortController();
529
- styleContainer.innerHTML = await renderStyles({
530
- styles,
531
- resolve,
532
- breakpoints,
533
- selectorPrefix: SELECTOR_PREFIX,
534
- signal: abortController.signal
535
- });
536
- };
537
- stylesRepository.subscribe(injectStyleElements);
538
- registerDataHook("after", "editor/documents/attach-preview", injectStyleElements);
539
- });
540
- }
541
- function getStylesContainer() {
542
- const preview = getCanvasIframeBody();
543
- const stylesContainer = preview?.querySelector(`[${WRAPPER_DATA_ATTR}]`);
544
- if (stylesContainer) {
545
- return stylesContainer;
546
- }
547
- const el = createStylesContainer();
548
- preview?.prepend(el);
549
- return el;
550
- }
551
- function createStylesContainer() {
552
- const el = document.createElement("div");
553
- el.style.display = "none";
554
- el.setAttribute(WRAPPER_DATA_ATTR, "");
555
- return el;
556
- }
557
- function enqueueUsedFonts({ key, value }) {
558
- if (key !== "font-family" || typeof value !== "string") {
559
- return;
560
- }
561
- enqueueFont(value);
562
- }
563
-
564
648
  // src/legacy/init-legacy-views.ts
565
649
  import { getWidgetsCache } from "@elementor/editor-elements";
566
- import { __privateListenTo, v1ReadyEvent as v1ReadyEvent2 } from "@elementor/editor-v1-adapters";
650
+ import { __privateListenTo, v1ReadyEvent } from "@elementor/editor-v1-adapters";
567
651
 
568
652
  // src/renderers/create-dom-renderer.ts
569
653
  import { createArrayLoader, createEnvironment } from "@elementor/twing";
@@ -629,11 +713,13 @@ function createElementViewClassDeclaration() {
629
713
  onRender(...args) {
630
714
  super.onRender(...args);
631
715
  this.#dispatchEvent("elementor/preview/atomic-widget/render");
716
+ this.#dispatchPreviewEvent("elementor/element/render");
632
717
  }
633
718
  // Dispatch `destroy` event so the overlay layer will be updated
634
719
  onDestroy(...args) {
635
720
  super.onDestroy(...args);
636
721
  this.#dispatchEvent("elementor/preview/atomic-widget/destroy");
722
+ this.#dispatchPreviewEvent("elementor/element/destroy");
637
723
  }
638
724
  attributes() {
639
725
  return {
@@ -667,31 +753,23 @@ function createElementViewClassDeclaration() {
667
753
  })
668
754
  );
669
755
  }
756
+ #dispatchPreviewEvent(eventType) {
757
+ legacyWindow.elementor?.$preview?.[0]?.contentWindow.dispatchEvent(
758
+ new CustomEvent(eventType, {
759
+ detail: {
760
+ id: this.model.get("id"),
761
+ type: this.model.get("widgetType"),
762
+ element: this.getDomElement().get(0)
763
+ }
764
+ })
765
+ );
766
+ }
670
767
  getContextMenuGroups() {
671
768
  return super.getContextMenuGroups().filter((group) => group.name !== "save");
672
769
  }
673
770
  };
674
771
  }
675
772
 
676
- // src/legacy/signalized-process.ts
677
- function signalizedProcess(signal, steps = []) {
678
- return {
679
- then: (cb) => {
680
- steps.push(cb);
681
- return signalizedProcess(signal, steps);
682
- },
683
- execute: async () => {
684
- let lastResult;
685
- for (const step of steps) {
686
- if (signal.aborted) {
687
- break;
688
- }
689
- lastResult = await step(lastResult, signal);
690
- }
691
- }
692
- };
693
- }
694
-
695
773
  // src/legacy/create-templated-element-type.ts
696
774
  function createTemplatedElementType({ type, renderer, element }) {
697
775
  const legacyWindow = window;
@@ -772,7 +850,7 @@ function createTemplatedElementViewClassDeclaration({
772
850
 
773
851
  // src/legacy/init-legacy-views.ts
774
852
  function initLegacyViews() {
775
- __privateListenTo(v1ReadyEvent2(), () => {
853
+ __privateListenTo(v1ReadyEvent(), () => {
776
854
  const config = getWidgetsCache() ?? {};
777
855
  const legacyWindow = window;
778
856
  const renderer = createDomRenderer();
@@ -786,10 +864,97 @@ function initLegacyViews() {
786
864
  });
787
865
  }
788
866
 
867
+ // src/prevent-link-in-link-commands.ts
868
+ import {
869
+ getAnchoredAncestorId,
870
+ getAnchoredDescendantId,
871
+ isElementAnchored
872
+ } from "@elementor/editor-elements";
873
+ import { notify } from "@elementor/editor-notifications";
874
+ import { blockCommand } from "@elementor/editor-v1-adapters";
875
+ import { __ } from "@wordpress/i18n";
876
+ function initLinkInLinkPrevention() {
877
+ blockCommand({
878
+ command: "document/elements/paste",
879
+ condition: blockLinkInLinkPaste
880
+ });
881
+ blockCommand({
882
+ command: "document/elements/move",
883
+ condition: blockLinkInLinkMove
884
+ });
885
+ }
886
+ var learnMoreActionProps = {
887
+ href: "https://go.elementor.com/element-link-inside-link-infotip",
888
+ target: "_blank",
889
+ color: "inherit",
890
+ variant: "text",
891
+ sx: {
892
+ marginInlineStart: "20px"
893
+ },
894
+ children: "Learn more"
895
+ };
896
+ function blockLinkInLinkPaste(args) {
897
+ const { containers = [args.container], storageType } = args;
898
+ const targetElements = containers;
899
+ if (storageType !== "localstorage") {
900
+ return false;
901
+ }
902
+ const data = window?.elementorCommon?.storage?.get();
903
+ if (!data?.clipboard?.elements) {
904
+ return false;
905
+ }
906
+ const sourceElements = data.clipboard.elements;
907
+ const notification = {
908
+ type: "default",
909
+ message: __(
910
+ "To paste a link to this element, first remove the link from it's parent container.",
911
+ "elementor"
912
+ ),
913
+ id: "paste-in-link-blocked",
914
+ additionalActionProps: [learnMoreActionProps]
915
+ };
916
+ const blocked = shouldBlock(sourceElements, targetElements);
917
+ if (blocked) {
918
+ notify(notification);
919
+ }
920
+ return blocked;
921
+ }
922
+ function blockLinkInLinkMove(args) {
923
+ const { containers = [args.container], target } = args;
924
+ const sourceElements = containers;
925
+ const targetElement = target;
926
+ const notification = {
927
+ type: "default",
928
+ message: __("To drag a link to this element, first remove the link from it's parent container.", "elementor"),
929
+ id: "move-in-link-blocked",
930
+ additionalActionProps: [learnMoreActionProps]
931
+ };
932
+ const isBlocked = shouldBlock(sourceElements, [targetElement]);
933
+ if (isBlocked) {
934
+ notify(notification);
935
+ }
936
+ return isBlocked;
937
+ }
938
+ function shouldBlock(sourceElements, targetElements) {
939
+ if (!sourceElements?.length || !targetElements?.length) {
940
+ return false;
941
+ }
942
+ const isSourceContainsAnAnchor = sourceElements.some((src) => {
943
+ return src?.id ? isElementAnchored(src.id) || !!getAnchoredDescendantId(src.id) : false;
944
+ });
945
+ if (!isSourceContainsAnAnchor) {
946
+ return false;
947
+ }
948
+ const isTargetContainsAnAnchor = targetElements.some((target) => {
949
+ return target?.id ? isElementAnchored(target.id) || !!getAnchoredAncestorId(target.id) : false;
950
+ });
951
+ return isTargetContainsAnAnchor;
952
+ }
953
+
789
954
  // src/style-commands/paste-style.ts
790
955
  import {
791
- __privateListenTo as listenTo2,
792
- blockCommand,
956
+ __privateListenTo as listenTo,
957
+ blockCommand as blockCommand2,
793
958
  commandStartEvent
794
959
  } from "@elementor/editor-v1-adapters";
795
960
 
@@ -802,12 +967,12 @@ import {
802
967
  } from "@elementor/editor-elements";
803
968
  import { LOCAL_STYLES_RESERVED_LABEL } from "@elementor/editor-styles-repository";
804
969
  import { undoable } from "@elementor/editor-v1-adapters";
805
- import { __ as __2 } from "@wordpress/i18n";
970
+ import { __ as __3 } from "@wordpress/i18n";
806
971
 
807
972
  // src/style-commands/utils.ts
808
973
  import { getElementLabel, getWidgetsCache as getWidgetsCache2 } from "@elementor/editor-elements";
809
974
  import { CLASSES_PROP_KEY } from "@elementor/editor-props";
810
- import { __ } from "@wordpress/i18n";
975
+ import { __ as __2 } from "@wordpress/i18n";
811
976
  function hasAtomicWidgets(args) {
812
977
  const { containers = [args.container] } = args;
813
978
  return containers.some(isAtomicWidget);
@@ -843,7 +1008,7 @@ function getClipboardElements(storageKey = "clipboard") {
843
1008
  }
844
1009
  }
845
1010
  function getTitleForContainers(containers) {
846
- return containers.length > 1 ? __("Elements", "elementor") : getElementLabel(containers[0].id);
1011
+ return containers.length > 1 ? __2("Elements", "elementor") : getElementLabel(containers[0].id);
847
1012
  }
848
1013
 
849
1014
  // src/style-commands/undoable-actions/paste-element-style.ts
@@ -915,18 +1080,18 @@ var undoablePasteElementStyle = () => undoable(
915
1080
  },
916
1081
  {
917
1082
  title: ({ containers }) => getTitleForContainers(containers),
918
- subtitle: __2("Style Pasted", "elementor")
1083
+ subtitle: __3("Style Pasted", "elementor")
919
1084
  }
920
1085
  );
921
1086
 
922
1087
  // src/style-commands/paste-style.ts
923
1088
  function initPasteStyleCommand() {
924
1089
  const pasteElementStyleCommand = undoablePasteElementStyle();
925
- blockCommand({
1090
+ blockCommand2({
926
1091
  command: "document/elements/paste-style",
927
1092
  condition: hasAtomicWidgets
928
1093
  });
929
- listenTo2(
1094
+ listenTo(
930
1095
  commandStartEvent("document/elements/paste-style"),
931
1096
  (e) => pasteStyles(e.args, pasteElementStyleCommand)
932
1097
  );
@@ -952,8 +1117,8 @@ function pasteStyles(args, pasteCallback) {
952
1117
 
953
1118
  // src/style-commands/reset-style.ts
954
1119
  import {
955
- __privateListenTo as listenTo3,
956
- blockCommand as blockCommand2,
1120
+ __privateListenTo as listenTo2,
1121
+ blockCommand as blockCommand3,
957
1122
  commandStartEvent as commandStartEvent2
958
1123
  } from "@elementor/editor-v1-adapters";
959
1124
 
@@ -961,7 +1126,7 @@ import {
961
1126
  import { createElementStyle as createElementStyle2, deleteElementStyle as deleteElementStyle2, getElementStyles as getElementStyles2 } from "@elementor/editor-elements";
962
1127
  import { LOCAL_STYLES_RESERVED_LABEL as LOCAL_STYLES_RESERVED_LABEL2 } from "@elementor/editor-styles-repository";
963
1128
  import { undoable as undoable2 } from "@elementor/editor-v1-adapters";
964
- import { __ as __3 } from "@wordpress/i18n";
1129
+ import { __ as __4 } from "@wordpress/i18n";
965
1130
  var undoableResetElementStyle = () => undoable2(
966
1131
  {
967
1132
  do: ({ containers }) => {
@@ -999,18 +1164,18 @@ var undoableResetElementStyle = () => undoable2(
999
1164
  },
1000
1165
  {
1001
1166
  title: ({ containers }) => getTitleForContainers(containers),
1002
- subtitle: __3("Style Reset", "elementor")
1167
+ subtitle: __4("Style Reset", "elementor")
1003
1168
  }
1004
1169
  );
1005
1170
 
1006
1171
  // src/style-commands/reset-style.ts
1007
1172
  function initResetStyleCommand() {
1008
1173
  const resetElementStyles = undoableResetElementStyle();
1009
- blockCommand2({
1174
+ blockCommand3({
1010
1175
  command: "document/elements/reset-style",
1011
1176
  condition: hasAtomicWidgets
1012
1177
  });
1013
- listenTo3(
1178
+ listenTo2(
1014
1179
  commandStartEvent2("document/elements/reset-style"),
1015
1180
  (e) => resetStyles(e.args, resetElementStyles)
1016
1181
  );
@@ -1033,19 +1198,24 @@ function initStyleCommands() {
1033
1198
  // src/init.tsx
1034
1199
  function init() {
1035
1200
  initStyleTransformers();
1036
- initStylesRenderer();
1037
1201
  initStyleCommands();
1202
+ initLinkInLinkPrevention();
1038
1203
  initLegacyViews();
1039
1204
  initSettingsTransformers();
1040
1205
  injectIntoTop({
1041
1206
  id: "elements-overlays",
1042
1207
  component: ElementsOverlays
1043
1208
  });
1209
+ injectIntoTop({
1210
+ id: "canvas-style-render",
1211
+ component: StyleRenderer
1212
+ });
1044
1213
  }
1045
1214
 
1046
1215
  // src/index.ts
1047
1216
  init();
1048
1217
  export {
1218
+ createTransformer,
1049
1219
  settingsTransformersRegistry,
1050
1220
  styleTransformersRegistry
1051
1221
  };