@elementor/editor-canvas 4.2.0-883 → 4.2.0-885

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -4,6 +4,7 @@ import { Root } from 'react-dom/client';
4
4
  import * as _elementor_editor_props from '@elementor/editor-props';
5
5
  import { Props, PropValue, PropType, PropTypeKey, PropsSchema, AnyTransformable } from '@elementor/editor-props';
6
6
  import { StyleVariables, StyleDefinitionsMap, StyleDefinitionID, StyleDefinitionState } from '@elementor/editor-styles';
7
+ import * as React$1 from 'react';
7
8
  import * as _elementor_utils from '@elementor/utils';
8
9
 
9
10
  declare const BREAKPOINTS_SCHEMA_URI = "elementor://breakpoints/list";
@@ -292,6 +293,8 @@ type ResolvedProps = Record<string, unknown>;
292
293
  type PropsResolver = ReturnType<typeof createPropsResolver>;
293
294
  declare function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }: CreatePropResolverArgs): ({ props, schema, signal, renderContext }: ResolveArgs) => Promise<ResolvedProps>;
294
295
 
296
+ declare function waitForChildrenToComplete(view: Pick<ElementView, 'children'>): Promise<void>;
297
+
295
298
  declare const settingsTransformersRegistry: {
296
299
  register(type: _elementor_editor_props.PropTypeKey, transformer: AnyTransformer): /*elided*/ any;
297
300
  registerFallback(transformer: AnyTransformer): /*elided*/ any;
@@ -326,6 +329,14 @@ type ImportedGlobalStylesPayload = {
326
329
 
327
330
  declare const DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
328
331
 
332
+ type SpotlightBackdropProps = {
333
+ canvas: Document;
334
+ element: HTMLElement | null;
335
+ onExit: () => void;
336
+ ariaLabel: string;
337
+ };
338
+ declare function SpotlightBackdrop({ canvas, element, onExit, ariaLabel }: SpotlightBackdropProps): React$1.JSX.Element;
339
+
329
340
  declare function createTransformer<TValue = never>(cb: TValue extends AnyTransformable ? 'Transformable values are invalid, use the actual value instead.' : UnbrandedTransformer<TValue>): Transformer<NoInfer<TValue>>;
330
341
 
331
342
  declare const isGridTrackProperty: (cssProperty: string) => boolean;
@@ -364,6 +375,10 @@ declare const UnknownStyleStateError: {
364
375
  isError(error: unknown): error is Error;
365
376
  };
366
377
 
378
+ declare function useCanvasDocument(): Document | null | undefined;
379
+
380
+ declare function useEscapeOnCanvas(canvasDocument: Document | null | undefined, onEscape: () => void): void;
381
+
367
382
  declare function doAfterRender(elementIds: string[], callback: (elementIds: string[]) => void): void;
368
383
 
369
- export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type ContextMenuAction, type ContextMenuEventData, type CreateNestedTemplatedElementTypeOptions, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload, type LegacyWindow, type NamespacedRenderContext, type NestedTemplatedElementConfig, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, TemplatedElementView, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, canBeNestedTemplated, createNestedTemplatedElementType, createNestedTemplatedElementView, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, doAfterRender, endDragElementFromPanel, formatGridTrackRepeat, init, isAtomicWidget, isGridTrackProperty, registerElementType, registerModelExtensions, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry, stylesInheritanceTransformersRegistry };
384
+ export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type ContextMenuAction, type ContextMenuEventData, type CreateNestedTemplatedElementTypeOptions, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload, type LegacyWindow, type NamespacedRenderContext, type NestedTemplatedElementConfig, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, SpotlightBackdrop, TemplatedElementView, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, canBeNestedTemplated, createNestedTemplatedElementType, createNestedTemplatedElementView, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, doAfterRender, endDragElementFromPanel, formatGridTrackRepeat, init, isAtomicWidget, isGridTrackProperty, registerElementType, registerModelExtensions, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry, stylesInheritanceTransformersRegistry, useCanvasDocument, useEscapeOnCanvas, waitForChildrenToComplete };
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import { Root } from 'react-dom/client';
4
4
  import * as _elementor_editor_props from '@elementor/editor-props';
5
5
  import { Props, PropValue, PropType, PropTypeKey, PropsSchema, AnyTransformable } from '@elementor/editor-props';
6
6
  import { StyleVariables, StyleDefinitionsMap, StyleDefinitionID, StyleDefinitionState } from '@elementor/editor-styles';
7
+ import * as React$1 from 'react';
7
8
  import * as _elementor_utils from '@elementor/utils';
8
9
 
9
10
  declare const BREAKPOINTS_SCHEMA_URI = "elementor://breakpoints/list";
@@ -292,6 +293,8 @@ type ResolvedProps = Record<string, unknown>;
292
293
  type PropsResolver = ReturnType<typeof createPropsResolver>;
293
294
  declare function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }: CreatePropResolverArgs): ({ props, schema, signal, renderContext }: ResolveArgs) => Promise<ResolvedProps>;
294
295
 
296
+ declare function waitForChildrenToComplete(view: Pick<ElementView, 'children'>): Promise<void>;
297
+
295
298
  declare const settingsTransformersRegistry: {
296
299
  register(type: _elementor_editor_props.PropTypeKey, transformer: AnyTransformer): /*elided*/ any;
297
300
  registerFallback(transformer: AnyTransformer): /*elided*/ any;
@@ -326,6 +329,14 @@ type ImportedGlobalStylesPayload = {
326
329
 
327
330
  declare const DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
328
331
 
332
+ type SpotlightBackdropProps = {
333
+ canvas: Document;
334
+ element: HTMLElement | null;
335
+ onExit: () => void;
336
+ ariaLabel: string;
337
+ };
338
+ declare function SpotlightBackdrop({ canvas, element, onExit, ariaLabel }: SpotlightBackdropProps): React$1.JSX.Element;
339
+
329
340
  declare function createTransformer<TValue = never>(cb: TValue extends AnyTransformable ? 'Transformable values are invalid, use the actual value instead.' : UnbrandedTransformer<TValue>): Transformer<NoInfer<TValue>>;
330
341
 
331
342
  declare const isGridTrackProperty: (cssProperty: string) => boolean;
@@ -364,6 +375,10 @@ declare const UnknownStyleStateError: {
364
375
  isError(error: unknown): error is Error;
365
376
  };
366
377
 
378
+ declare function useCanvasDocument(): Document | null | undefined;
379
+
380
+ declare function useEscapeOnCanvas(canvasDocument: Document | null | undefined, onEscape: () => void): void;
381
+
367
382
  declare function doAfterRender(elementIds: string[], callback: (elementIds: string[]) => void): void;
368
383
 
369
- export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type ContextMenuAction, type ContextMenuEventData, type CreateNestedTemplatedElementTypeOptions, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload, type LegacyWindow, type NamespacedRenderContext, type NestedTemplatedElementConfig, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, TemplatedElementView, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, canBeNestedTemplated, createNestedTemplatedElementType, createNestedTemplatedElementView, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, doAfterRender, endDragElementFromPanel, formatGridTrackRepeat, init, isAtomicWidget, isGridTrackProperty, registerElementType, registerModelExtensions, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry, stylesInheritanceTransformersRegistry };
384
+ export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type ContextMenuAction, type ContextMenuEventData, type CreateNestedTemplatedElementTypeOptions, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload, type LegacyWindow, type NamespacedRenderContext, type NestedTemplatedElementConfig, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, SpotlightBackdrop, TemplatedElementView, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, canBeNestedTemplated, createNestedTemplatedElementType, createNestedTemplatedElementView, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, doAfterRender, endDragElementFromPanel, formatGridTrackRepeat, init, isAtomicWidget, isGridTrackProperty, registerElementType, registerModelExtensions, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry, stylesInheritanceTransformersRegistry, useCanvasDocument, useEscapeOnCanvas, waitForChildrenToComplete };
package/dist/index.js CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  DOCUMENT_STRUCTURE_URI: () => DOCUMENT_STRUCTURE_URI,
35
35
  GLOBAL_STYLES_IMPORTED_EVENT: () => GLOBAL_STYLES_IMPORTED_EVENT,
36
36
  STYLE_SCHEMA_URI: () => STYLE_SCHEMA_URI,
37
+ SpotlightBackdrop: () => SpotlightBackdrop,
37
38
  UnknownStyleStateError: () => UnknownStyleStateError,
38
39
  UnknownStyleTypeError: () => UnknownStyleTypeError,
39
40
  WIDGET_SCHEMA_URI: () => WIDGET_SCHEMA_URI,
@@ -55,7 +56,10 @@ __export(index_exports, {
55
56
  settingsTransformersRegistry: () => settingsTransformersRegistry,
56
57
  startDragElementFromPanel: () => startDragElementFromPanel,
57
58
  styleTransformersRegistry: () => styleTransformersRegistry,
58
- stylesInheritanceTransformersRegistry: () => stylesInheritanceTransformersRegistry
59
+ stylesInheritanceTransformersRegistry: () => stylesInheritanceTransformersRegistry,
60
+ useCanvasDocument: () => useCanvasDocument,
61
+ useEscapeOnCanvas: () => useEscapeOnCanvas,
62
+ waitForChildrenToComplete: () => waitForChildrenToComplete
59
63
  });
60
64
  module.exports = __toCommonJS(index_exports);
61
65
 
@@ -5672,6 +5676,137 @@ var getLegacyPanelElementView = ({ settings, ...rest }) => {
5672
5676
  // src/sync/global-styles-imported-event.ts
5673
5677
  var GLOBAL_STYLES_IMPORTED_EVENT = "elementor/global-styles/imported";
5674
5678
 
5679
+ // src/components/spotlight-backdrop.tsx
5680
+ var React7 = __toESM(require("react"));
5681
+
5682
+ // src/hooks/use-element-rect.ts
5683
+ var import_react14 = require("react");
5684
+ var import_utils6 = require("@elementor/utils");
5685
+ function useElementRect(element) {
5686
+ const [rect, setRect] = (0, import_react14.useState)(new DOMRect(0, 0, 0, 0));
5687
+ const onChange = (0, import_utils6.throttle)(
5688
+ () => {
5689
+ setRect(element?.getBoundingClientRect() ?? new DOMRect(0, 0, 0, 0));
5690
+ },
5691
+ 20,
5692
+ true
5693
+ );
5694
+ useScrollListener({ element, onChange });
5695
+ useResizeListener({ element, onChange });
5696
+ useMutationsListener({ element, onChange });
5697
+ (0, import_react14.useEffect)(
5698
+ () => () => {
5699
+ onChange.cancel();
5700
+ },
5701
+ [onChange]
5702
+ );
5703
+ return rect;
5704
+ }
5705
+ function useScrollListener({ element, onChange }) {
5706
+ (0, import_react14.useEffect)(() => {
5707
+ if (!element) {
5708
+ return;
5709
+ }
5710
+ const win = element.ownerDocument?.defaultView;
5711
+ win?.addEventListener("scroll", onChange, { passive: true });
5712
+ return () => {
5713
+ win?.removeEventListener("scroll", onChange);
5714
+ };
5715
+ }, [element, onChange]);
5716
+ }
5717
+ function useResizeListener({ element, onChange }) {
5718
+ (0, import_react14.useEffect)(() => {
5719
+ if (!element) {
5720
+ return;
5721
+ }
5722
+ const resizeObserver = new ResizeObserver(onChange);
5723
+ resizeObserver.observe(element);
5724
+ const win = element.ownerDocument?.defaultView;
5725
+ win?.addEventListener("resize", onChange, { passive: true });
5726
+ return () => {
5727
+ resizeObserver.disconnect();
5728
+ win?.removeEventListener("resize", onChange);
5729
+ };
5730
+ }, [element, onChange]);
5731
+ }
5732
+ function useMutationsListener({ element, onChange }) {
5733
+ (0, import_react14.useEffect)(() => {
5734
+ if (!element) {
5735
+ return;
5736
+ }
5737
+ const mutationObserver = new MutationObserver(onChange);
5738
+ mutationObserver.observe(element, { childList: true, subtree: true });
5739
+ return () => {
5740
+ mutationObserver.disconnect();
5741
+ };
5742
+ }, [element, onChange]);
5743
+ }
5744
+
5745
+ // src/components/spotlight-backdrop.tsx
5746
+ function SpotlightBackdrop({ canvas, element, onExit, ariaLabel }) {
5747
+ const rect = useElementRect(element);
5748
+ const clipPath = element ? getRectClipPath(rect, canvas.defaultView) : void 0;
5749
+ const backdropStyle = {
5750
+ position: "fixed",
5751
+ top: 0,
5752
+ left: 0,
5753
+ width: "100vw",
5754
+ height: "100vh",
5755
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
5756
+ zIndex: 999,
5757
+ pointerEvents: "painted",
5758
+ cursor: "pointer",
5759
+ clipPath
5760
+ };
5761
+ const handleKeyDown = (event) => {
5762
+ if (event.key === "Enter" || event.key === " ") {
5763
+ event.preventDefault();
5764
+ onExit();
5765
+ }
5766
+ };
5767
+ return /* @__PURE__ */ React7.createElement(
5768
+ "div",
5769
+ {
5770
+ style: backdropStyle,
5771
+ onClick: onExit,
5772
+ onKeyDown: handleKeyDown,
5773
+ role: "button",
5774
+ tabIndex: 0,
5775
+ "aria-label": ariaLabel
5776
+ }
5777
+ );
5778
+ }
5779
+ function getRectClipPath(rect, viewport) {
5780
+ const { x, y, width, height } = rect;
5781
+ const { innerWidth: vw, innerHeight: vh } = viewport;
5782
+ return `path(evenodd, 'M 0 0 L ${vw} 0 L ${vw} ${vh} L 0 ${vh} Z M ${x} ${y} L ${x + width} ${y} L ${x + width} ${y + height} L ${x} ${y + height} L ${x} ${y} Z')`;
5783
+ }
5784
+
5785
+ // src/hooks/use-canvas-document.ts
5786
+ var import_editor_v1_adapters25 = require("@elementor/editor-v1-adapters");
5787
+ function useCanvasDocument() {
5788
+ return (0, import_editor_v1_adapters25.__privateUseListenTo)((0, import_editor_v1_adapters25.commandEndEvent)("editor/documents/attach-preview"), () => (0, import_editor_v1_adapters25.getCanvasIframeDocument)());
5789
+ }
5790
+
5791
+ // src/hooks/use-escape-on-canvas.ts
5792
+ var import_react15 = require("react");
5793
+ function useEscapeOnCanvas(canvasDocument, onEscape) {
5794
+ (0, import_react15.useEffect)(() => {
5795
+ if (!canvasDocument) {
5796
+ return;
5797
+ }
5798
+ const handleEsc = (event) => {
5799
+ if (event.key === "Escape") {
5800
+ onEscape();
5801
+ }
5802
+ };
5803
+ canvasDocument.body.addEventListener("keydown", handleEsc);
5804
+ return () => {
5805
+ canvasDocument.body.removeEventListener("keydown", handleEsc);
5806
+ };
5807
+ }, [canvasDocument, onEscape]);
5808
+ }
5809
+
5675
5810
  // src/utils/after-render.ts
5676
5811
  var import_editor_elements22 = require("@elementor/editor-elements");
5677
5812
  function doAfterRender(elementIds, callback) {
@@ -5697,6 +5832,7 @@ function hasDoAfterRender(view) {
5697
5832
  DOCUMENT_STRUCTURE_URI,
5698
5833
  GLOBAL_STYLES_IMPORTED_EVENT,
5699
5834
  STYLE_SCHEMA_URI,
5835
+ SpotlightBackdrop,
5700
5836
  UnknownStyleStateError,
5701
5837
  UnknownStyleTypeError,
5702
5838
  WIDGET_SCHEMA_URI,
@@ -5718,6 +5854,9 @@ function hasDoAfterRender(view) {
5718
5854
  settingsTransformersRegistry,
5719
5855
  startDragElementFromPanel,
5720
5856
  styleTransformersRegistry,
5721
- stylesInheritanceTransformersRegistry
5857
+ stylesInheritanceTransformersRegistry,
5858
+ useCanvasDocument,
5859
+ useEscapeOnCanvas,
5860
+ waitForChildrenToComplete
5722
5861
  });
5723
5862
  //# sourceMappingURL=index.js.map
package/dist/index.mjs CHANGED
@@ -5682,6 +5682,141 @@ var getLegacyPanelElementView = ({ settings, ...rest }) => {
5682
5682
  // src/sync/global-styles-imported-event.ts
5683
5683
  var GLOBAL_STYLES_IMPORTED_EVENT = "elementor/global-styles/imported";
5684
5684
 
5685
+ // src/components/spotlight-backdrop.tsx
5686
+ import * as React7 from "react";
5687
+
5688
+ // src/hooks/use-element-rect.ts
5689
+ import { useEffect as useEffect9, useState as useState6 } from "react";
5690
+ import { throttle } from "@elementor/utils";
5691
+ function useElementRect(element) {
5692
+ const [rect, setRect] = useState6(new DOMRect(0, 0, 0, 0));
5693
+ const onChange = throttle(
5694
+ () => {
5695
+ setRect(element?.getBoundingClientRect() ?? new DOMRect(0, 0, 0, 0));
5696
+ },
5697
+ 20,
5698
+ true
5699
+ );
5700
+ useScrollListener({ element, onChange });
5701
+ useResizeListener({ element, onChange });
5702
+ useMutationsListener({ element, onChange });
5703
+ useEffect9(
5704
+ () => () => {
5705
+ onChange.cancel();
5706
+ },
5707
+ [onChange]
5708
+ );
5709
+ return rect;
5710
+ }
5711
+ function useScrollListener({ element, onChange }) {
5712
+ useEffect9(() => {
5713
+ if (!element) {
5714
+ return;
5715
+ }
5716
+ const win = element.ownerDocument?.defaultView;
5717
+ win?.addEventListener("scroll", onChange, { passive: true });
5718
+ return () => {
5719
+ win?.removeEventListener("scroll", onChange);
5720
+ };
5721
+ }, [element, onChange]);
5722
+ }
5723
+ function useResizeListener({ element, onChange }) {
5724
+ useEffect9(() => {
5725
+ if (!element) {
5726
+ return;
5727
+ }
5728
+ const resizeObserver = new ResizeObserver(onChange);
5729
+ resizeObserver.observe(element);
5730
+ const win = element.ownerDocument?.defaultView;
5731
+ win?.addEventListener("resize", onChange, { passive: true });
5732
+ return () => {
5733
+ resizeObserver.disconnect();
5734
+ win?.removeEventListener("resize", onChange);
5735
+ };
5736
+ }, [element, onChange]);
5737
+ }
5738
+ function useMutationsListener({ element, onChange }) {
5739
+ useEffect9(() => {
5740
+ if (!element) {
5741
+ return;
5742
+ }
5743
+ const mutationObserver = new MutationObserver(onChange);
5744
+ mutationObserver.observe(element, { childList: true, subtree: true });
5745
+ return () => {
5746
+ mutationObserver.disconnect();
5747
+ };
5748
+ }, [element, onChange]);
5749
+ }
5750
+
5751
+ // src/components/spotlight-backdrop.tsx
5752
+ function SpotlightBackdrop({ canvas, element, onExit, ariaLabel }) {
5753
+ const rect = useElementRect(element);
5754
+ const clipPath = element ? getRectClipPath(rect, canvas.defaultView) : void 0;
5755
+ const backdropStyle = {
5756
+ position: "fixed",
5757
+ top: 0,
5758
+ left: 0,
5759
+ width: "100vw",
5760
+ height: "100vh",
5761
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
5762
+ zIndex: 999,
5763
+ pointerEvents: "painted",
5764
+ cursor: "pointer",
5765
+ clipPath
5766
+ };
5767
+ const handleKeyDown = (event) => {
5768
+ if (event.key === "Enter" || event.key === " ") {
5769
+ event.preventDefault();
5770
+ onExit();
5771
+ }
5772
+ };
5773
+ return /* @__PURE__ */ React7.createElement(
5774
+ "div",
5775
+ {
5776
+ style: backdropStyle,
5777
+ onClick: onExit,
5778
+ onKeyDown: handleKeyDown,
5779
+ role: "button",
5780
+ tabIndex: 0,
5781
+ "aria-label": ariaLabel
5782
+ }
5783
+ );
5784
+ }
5785
+ function getRectClipPath(rect, viewport) {
5786
+ const { x, y, width, height } = rect;
5787
+ const { innerWidth: vw, innerHeight: vh } = viewport;
5788
+ return `path(evenodd, 'M 0 0 L ${vw} 0 L ${vw} ${vh} L 0 ${vh} Z M ${x} ${y} L ${x + width} ${y} L ${x + width} ${y + height} L ${x} ${y + height} L ${x} ${y} Z')`;
5789
+ }
5790
+
5791
+ // src/hooks/use-canvas-document.ts
5792
+ import {
5793
+ __privateUseListenTo as useListenTo5,
5794
+ commandEndEvent as commandEndEvent8,
5795
+ getCanvasIframeDocument as getCanvasIframeDocument5
5796
+ } from "@elementor/editor-v1-adapters";
5797
+ function useCanvasDocument() {
5798
+ return useListenTo5(commandEndEvent8("editor/documents/attach-preview"), () => getCanvasIframeDocument5());
5799
+ }
5800
+
5801
+ // src/hooks/use-escape-on-canvas.ts
5802
+ import { useEffect as useEffect10 } from "react";
5803
+ function useEscapeOnCanvas(canvasDocument, onEscape) {
5804
+ useEffect10(() => {
5805
+ if (!canvasDocument) {
5806
+ return;
5807
+ }
5808
+ const handleEsc = (event) => {
5809
+ if (event.key === "Escape") {
5810
+ onEscape();
5811
+ }
5812
+ };
5813
+ canvasDocument.body.addEventListener("keydown", handleEsc);
5814
+ return () => {
5815
+ canvasDocument.body.removeEventListener("keydown", handleEsc);
5816
+ };
5817
+ }, [canvasDocument, onEscape]);
5818
+ }
5819
+
5685
5820
  // src/utils/after-render.ts
5686
5821
  import { getContainer as getContainer8 } from "@elementor/editor-elements";
5687
5822
  function doAfterRender(elementIds, callback) {
@@ -5706,6 +5841,7 @@ export {
5706
5841
  DOCUMENT_STRUCTURE_URI,
5707
5842
  GLOBAL_STYLES_IMPORTED_EVENT,
5708
5843
  STYLE_SCHEMA_URI,
5844
+ SpotlightBackdrop,
5709
5845
  UnknownStyleStateError,
5710
5846
  UnknownStyleTypeError,
5711
5847
  WIDGET_SCHEMA_URI,
@@ -5727,6 +5863,9 @@ export {
5727
5863
  settingsTransformersRegistry,
5728
5864
  startDragElementFromPanel,
5729
5865
  styleTransformersRegistry,
5730
- stylesInheritanceTransformersRegistry
5866
+ stylesInheritanceTransformersRegistry,
5867
+ useCanvasDocument,
5868
+ useEscapeOnCanvas,
5869
+ waitForChildrenToComplete
5731
5870
  };
5732
5871
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "4.2.0-883",
4
+ "version": "4.2.0-885",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,25 +37,25 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.2.0-883",
40
+ "@elementor/editor": "4.2.0-885",
41
41
  "dompurify": "^3.2.6",
42
- "@elementor/editor-controls": "4.2.0-883",
43
- "@elementor/editor-documents": "4.2.0-883",
44
- "@elementor/editor-elements": "4.2.0-883",
45
- "@elementor/editor-interactions": "4.2.0-883",
46
- "@elementor/editor-mcp": "4.2.0-883",
47
- "@elementor/editor-notifications": "4.2.0-883",
48
- "@elementor/editor-props": "4.2.0-883",
49
- "@elementor/editor-responsive": "4.2.0-883",
50
- "@elementor/editor-styles": "4.2.0-883",
51
- "@elementor/editor-styles-repository": "4.2.0-883",
52
- "@elementor/editor-ui": "4.2.0-883",
53
- "@elementor/editor-v1-adapters": "4.2.0-883",
54
- "@elementor/schema": "4.2.0-883",
55
- "@elementor/twing": "4.2.0-883",
42
+ "@elementor/editor-controls": "4.2.0-885",
43
+ "@elementor/editor-documents": "4.2.0-885",
44
+ "@elementor/editor-elements": "4.2.0-885",
45
+ "@elementor/editor-interactions": "4.2.0-885",
46
+ "@elementor/editor-mcp": "4.2.0-885",
47
+ "@elementor/editor-notifications": "4.2.0-885",
48
+ "@elementor/editor-props": "4.2.0-885",
49
+ "@elementor/editor-responsive": "4.2.0-885",
50
+ "@elementor/editor-styles": "4.2.0-885",
51
+ "@elementor/editor-styles-repository": "4.2.0-885",
52
+ "@elementor/editor-ui": "4.2.0-885",
53
+ "@elementor/editor-v1-adapters": "4.2.0-885",
54
+ "@elementor/schema": "4.2.0-885",
55
+ "@elementor/twing": "4.2.0-885",
56
56
  "@elementor/ui": "1.37.5",
57
- "@elementor/utils": "4.2.0-883",
58
- "@elementor/wp-media": "4.2.0-883",
57
+ "@elementor/utils": "4.2.0-885",
58
+ "@elementor/wp-media": "4.2.0-885",
59
59
  "@floating-ui/react": "^0.27.5",
60
60
  "@wordpress/i18n": "^5.13.0"
61
61
  },
@@ -0,0 +1,53 @@
1
+ import * as React from 'react';
2
+ import { renderWithTheme } from 'test-utils';
3
+ import { fireEvent, screen } from '@testing-library/react';
4
+
5
+ import { SpotlightBackdrop } from '../spotlight-backdrop';
6
+
7
+ describe( '<SpotlightBackdrop />', () => {
8
+ it( 'renders a button-role backdrop with the given aria label', () => {
9
+ const onExit = jest.fn();
10
+
11
+ renderWithTheme(
12
+ <SpotlightBackdrop canvas={ document } element={ null } onExit={ onExit } ariaLabel="Exit" />
13
+ );
14
+
15
+ expect( screen.getByRole( 'button', { name: 'Exit' } ) ).toBeInTheDocument();
16
+ } );
17
+
18
+ it( 'calls onExit when clicking the backdrop', () => {
19
+ const onExit = jest.fn();
20
+ renderWithTheme(
21
+ <SpotlightBackdrop canvas={ document } element={ null } onExit={ onExit } ariaLabel="Exit" />
22
+ );
23
+
24
+ fireEvent.click( screen.getByRole( 'button', { name: 'Exit' } ) );
25
+
26
+ expect( onExit ).toHaveBeenCalledTimes( 1 );
27
+ } );
28
+
29
+ it( 'calls onExit when pressing Enter or Space on the backdrop', () => {
30
+ const onExit = jest.fn();
31
+ renderWithTheme(
32
+ <SpotlightBackdrop canvas={ document } element={ null } onExit={ onExit } ariaLabel="Exit" />
33
+ );
34
+ const backdrop = screen.getByRole( 'button', { name: 'Exit' } );
35
+
36
+ fireEvent.keyDown( backdrop, { key: 'Enter' } );
37
+ fireEvent.keyDown( backdrop, { key: ' ' } );
38
+
39
+ expect( onExit ).toHaveBeenCalledTimes( 2 );
40
+ } );
41
+
42
+ it( 'does not apply a clip-path when no element is provided', () => {
43
+ const onExit = jest.fn();
44
+
45
+ renderWithTheme(
46
+ <SpotlightBackdrop canvas={ document } element={ null } onExit={ onExit } ariaLabel="Exit" />
47
+ );
48
+
49
+ expect( screen.getByRole( 'button', { name: 'Exit' } ) ).not.toHaveStyle( {
50
+ clipPath: expect.stringContaining( 'path' ),
51
+ } );
52
+ } );
53
+ } );
@@ -0,0 +1,56 @@
1
+ import * as React from 'react';
2
+ import { type CSSProperties } from 'react';
3
+
4
+ import { useElementRect } from '../hooks/use-element-rect';
5
+
6
+ type SpotlightBackdropProps = {
7
+ canvas: Document;
8
+ element: HTMLElement | null;
9
+ onExit: () => void;
10
+ ariaLabel: string;
11
+ };
12
+
13
+ export function SpotlightBackdrop( { canvas, element, onExit, ariaLabel }: SpotlightBackdropProps ) {
14
+ const rect = useElementRect( element );
15
+ const clipPath = element ? getRectClipPath( rect, canvas.defaultView as Window ) : undefined;
16
+
17
+ const backdropStyle: CSSProperties = {
18
+ position: 'fixed',
19
+ top: 0,
20
+ left: 0,
21
+ width: '100vw',
22
+ height: '100vh',
23
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
24
+ zIndex: 999,
25
+ pointerEvents: 'painted',
26
+ cursor: 'pointer',
27
+ clipPath,
28
+ };
29
+
30
+ const handleKeyDown = ( event: React.KeyboardEvent ) => {
31
+ if ( event.key === 'Enter' || event.key === ' ' ) {
32
+ event.preventDefault();
33
+ onExit();
34
+ }
35
+ };
36
+
37
+ return (
38
+ <div
39
+ style={ backdropStyle }
40
+ onClick={ onExit }
41
+ onKeyDown={ handleKeyDown }
42
+ role="button"
43
+ tabIndex={ 0 }
44
+ aria-label={ ariaLabel }
45
+ />
46
+ );
47
+ }
48
+
49
+ function getRectClipPath( rect: DOMRect, viewport: Window ) {
50
+ const { x, y, width, height } = rect;
51
+ const { innerWidth: vw, innerHeight: vh } = viewport;
52
+
53
+ return `path(evenodd, 'M 0 0 L ${ vw } 0 L ${ vw } ${ vh } L 0 ${ vh } Z M ${ x } ${ y } L ${
54
+ x + width
55
+ } ${ y } L ${ x + width } ${ y + height } L ${ x } ${ y + height } L ${ x } ${ y } Z')`;
56
+ }
@@ -0,0 +1,9 @@
1
+ import {
2
+ __privateUseListenTo as useListenTo,
3
+ commandEndEvent,
4
+ getCanvasIframeDocument,
5
+ } from '@elementor/editor-v1-adapters';
6
+
7
+ export function useCanvasDocument() {
8
+ return useListenTo( commandEndEvent( 'editor/documents/attach-preview' ), () => getCanvasIframeDocument() );
9
+ }
@@ -0,0 +1,81 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { throttle } from '@elementor/utils';
3
+
4
+ export function useElementRect( element: HTMLElement | null ) {
5
+ const [ rect, setRect ] = useState< DOMRect >( new DOMRect( 0, 0, 0, 0 ) );
6
+
7
+ const onChange = throttle(
8
+ () => {
9
+ setRect( element?.getBoundingClientRect() ?? new DOMRect( 0, 0, 0, 0 ) );
10
+ },
11
+ 20,
12
+ true
13
+ );
14
+
15
+ useScrollListener( { element, onChange } );
16
+ useResizeListener( { element, onChange } );
17
+ useMutationsListener( { element, onChange } );
18
+
19
+ useEffect(
20
+ () => () => {
21
+ onChange.cancel();
22
+ },
23
+ [ onChange ]
24
+ );
25
+
26
+ return rect;
27
+ }
28
+
29
+ type ListenerProps = {
30
+ element: HTMLElement | null;
31
+ onChange: () => void;
32
+ };
33
+
34
+ function useScrollListener( { element, onChange }: ListenerProps ) {
35
+ useEffect( () => {
36
+ if ( ! element ) {
37
+ return;
38
+ }
39
+
40
+ const win = element.ownerDocument?.defaultView;
41
+ win?.addEventListener( 'scroll', onChange, { passive: true } );
42
+
43
+ return () => {
44
+ win?.removeEventListener( 'scroll', onChange );
45
+ };
46
+ }, [ element, onChange ] );
47
+ }
48
+
49
+ function useResizeListener( { element, onChange }: ListenerProps ) {
50
+ useEffect( () => {
51
+ if ( ! element ) {
52
+ return;
53
+ }
54
+
55
+ const resizeObserver = new ResizeObserver( onChange );
56
+ resizeObserver.observe( element );
57
+
58
+ const win = element.ownerDocument?.defaultView;
59
+ win?.addEventListener( 'resize', onChange, { passive: true } );
60
+
61
+ return () => {
62
+ resizeObserver.disconnect();
63
+ win?.removeEventListener( 'resize', onChange );
64
+ };
65
+ }, [ element, onChange ] );
66
+ }
67
+
68
+ function useMutationsListener( { element, onChange }: ListenerProps ) {
69
+ useEffect( () => {
70
+ if ( ! element ) {
71
+ return;
72
+ }
73
+
74
+ const mutationObserver = new MutationObserver( onChange );
75
+ mutationObserver.observe( element, { childList: true, subtree: true } );
76
+
77
+ return () => {
78
+ mutationObserver.disconnect();
79
+ };
80
+ }, [ element, onChange ] );
81
+ }
@@ -0,0 +1,21 @@
1
+ import { useEffect } from 'react';
2
+
3
+ export function useEscapeOnCanvas( canvasDocument: Document | null | undefined, onEscape: () => void ) {
4
+ useEffect( () => {
5
+ if ( ! canvasDocument ) {
6
+ return;
7
+ }
8
+
9
+ const handleEsc = ( event: KeyboardEvent ) => {
10
+ if ( event.key === 'Escape' ) {
11
+ onEscape();
12
+ }
13
+ };
14
+
15
+ canvasDocument.body.addEventListener( 'keydown', handleEsc );
16
+
17
+ return () => {
18
+ canvasDocument.body.removeEventListener( 'keydown', handleEsc );
19
+ };
20
+ }, [ canvasDocument, onEscape ] );
21
+ }
package/src/index.ts CHANGED
@@ -16,6 +16,7 @@ export {
16
16
  type NestedTemplatedElementConfig,
17
17
  } from './legacy/create-nested-templated-element-type';
18
18
  export { registerElementType, registerModelExtensions } from './legacy/init-legacy-views';
19
+ export { waitForChildrenToComplete } from './legacy/twig-rendering-utils';
19
20
  export * from './legacy/types';
20
21
  export { createPropsResolver, type PropsResolver } from './renderers/create-props-resolver';
21
22
  export { settingsTransformersRegistry } from './settings-transformers-registry';
@@ -25,6 +26,7 @@ export { GLOBAL_STYLES_IMPORTED_EVENT, type ImportedGlobalStylesPayload } from '
25
26
  export { DOCUMENT_STRUCTURE_URI } from './mcp/resources/document-structure-resource';
26
27
  export { WIDGET_SCHEMA_URI } from './mcp/resources/widgets-schema-resource';
27
28
  export * from './legacy/types';
29
+ export { SpotlightBackdrop } from './components/spotlight-backdrop';
28
30
  export { createTransformer } from './transformers/create-transformer';
29
31
  export { formatGridTrackRepeat, isGridTrackProperty } from './transformers/styles/grid-track-renderer';
30
32
  export {
@@ -33,4 +35,6 @@ export {
33
35
  } from './transformers/create-transformers-registry';
34
36
  export { type AnyTransformer, type TransformerOptions } from './transformers/types';
35
37
  export { UnknownStyleTypeError, UnknownStyleStateError } from './renderers/errors';
38
+ export { useCanvasDocument } from './hooks/use-canvas-document';
39
+ export { useEscapeOnCanvas } from './hooks/use-escape-on-canvas';
36
40
  export { doAfterRender } from './utils/after-render';