@elementor/editor-canvas 4.0.0 → 4.0.1

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
@@ -1,5 +1,6 @@
1
1
  import { V1Element, V1ElementConfig, V1ElementModelProps } from '@elementor/editor-elements';
2
2
  import { TwingArrayLoader, TwingEnvironment } from '@elementor/twing';
3
+ import { Root } from 'react-dom/client';
3
4
  import * as _elementor_editor_props from '@elementor/editor-props';
4
5
  import { Props, PropValue, PropType, PropTypeKey, PropsSchema, AnyTransformable } from '@elementor/editor-props';
5
6
  import * as _elementor_utils from '@elementor/utils';
@@ -204,6 +205,8 @@ type ReplacementSettings = {
204
205
  id: string;
205
206
  element: HTMLElement;
206
207
  refreshView: () => void;
208
+ reactRoot: Root;
209
+ reactContainer: HTMLElement;
207
210
  };
208
211
 
209
212
  type CreateTemplatedElementTypeOptions = {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { V1Element, V1ElementConfig, V1ElementModelProps } from '@elementor/editor-elements';
2
2
  import { TwingArrayLoader, TwingEnvironment } from '@elementor/twing';
3
+ import { Root } from 'react-dom/client';
3
4
  import * as _elementor_editor_props from '@elementor/editor-props';
4
5
  import { Props, PropValue, PropType, PropTypeKey, PropsSchema, AnyTransformable } from '@elementor/editor-props';
5
6
  import * as _elementor_utils from '@elementor/utils';
@@ -204,6 +205,8 @@ type ReplacementSettings = {
204
205
  id: string;
205
206
  element: HTMLElement;
206
207
  refreshView: () => void;
208
+ reactRoot: Root;
209
+ reactContainer: HTMLElement;
207
210
  };
208
211
 
209
212
  type CreateTemplatedElementTypeOptions = {
package/dist/index.js CHANGED
@@ -944,22 +944,30 @@ function useStyleItems() {
944
944
  const [styleItems, setStyleItems] = (0, import_react10.useState)({});
945
945
  const styleItemsCacheRef = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
946
946
  const providerAndSubscribers = (0, import_react10.useMemo)(() => {
947
- return import_editor_styles_repository2.stylesRepository.getProviders().map((provider) => {
948
- const providerKey = provider.getKey();
947
+ const createEmptyCache = () => {
948
+ return { orderedIds: [], itemsById: /* @__PURE__ */ new Map() };
949
+ };
950
+ const getCache = (provider) => {
951
+ const providerKey = safeGetKey(provider);
952
+ if (!providerKey) {
953
+ return createEmptyCache();
954
+ }
949
955
  if (!styleItemsCacheRef.current.has(providerKey)) {
950
- styleItemsCacheRef.current.set(providerKey, { orderedIds: [], itemsById: /* @__PURE__ */ new Map() });
956
+ styleItemsCacheRef.current.set(providerKey, createEmptyCache());
951
957
  }
952
- const cache = styleItemsCacheRef.current.get(providerKey);
953
- return {
958
+ return styleItemsCacheRef.current.get(providerKey);
959
+ };
960
+ return import_editor_styles_repository2.stylesRepository.getProviders().map(
961
+ (provider) => ({
954
962
  provider,
955
963
  subscriber: createProviderSubscriber2({
956
964
  provider,
957
965
  renderStyles,
958
966
  setStyleItems,
959
- cache
967
+ getCache: () => getCache(provider)
960
968
  })
961
- };
962
- });
969
+ })
970
+ );
963
971
  }, [renderStyles]);
964
972
  (0, import_react10.useEffect)(() => {
965
973
  const unsubscribes = providerAndSubscribers.map(
@@ -999,15 +1007,23 @@ function stateSorter({ state: stateA }, { state: stateB }) {
999
1007
  function createBreakpointSorter(breakpointsOrder) {
1000
1008
  return ({ breakpoint: breakpointA }, { breakpoint: breakpointB }) => breakpointsOrder.indexOf(breakpointA) - breakpointsOrder.indexOf(breakpointB);
1001
1009
  }
1002
- function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cache }) {
1010
+ function safeGetKey(provider) {
1011
+ try {
1012
+ return provider.getKey();
1013
+ } catch {
1014
+ return null;
1015
+ }
1016
+ }
1017
+ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, getCache }) {
1003
1018
  return abortPreviousRuns(
1004
1019
  (abortController, previous, current) => signalizedProcess(abortController.signal).then((_, signal) => {
1020
+ const cache = getCache();
1005
1021
  const hasDiffInfo = current !== void 0 && previous !== void 0;
1006
1022
  const hasCache = cache.orderedIds.length > 0;
1007
1023
  if (hasDiffInfo && hasCache) {
1008
- return updateItems(previous, current, signal);
1024
+ return updateItems(cache, previous, current, signal);
1009
1025
  }
1010
- return createItems(signal);
1026
+ return createItems(cache, signal);
1011
1027
  }).then((items) => {
1012
1028
  setStyleItems((prev) => ({
1013
1029
  ...prev,
@@ -1015,7 +1031,7 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cach
1015
1031
  }));
1016
1032
  }).execute()
1017
1033
  );
1018
- async function updateItems(previous, current, signal) {
1034
+ async function updateItems(cache, previous, current, signal) {
1019
1035
  const changedIds = getChangedStyleIds(previous, current);
1020
1036
  cache.orderedIds = provider.actions.all().map((style) => style.id).reverse();
1021
1037
  if (changedIds.length > 0) {
@@ -1030,7 +1046,7 @@ function createProviderSubscriber2({ provider, renderStyles, setStyleItems, cach
1030
1046
  }
1031
1047
  return getOrderedItems(cache);
1032
1048
  }
1033
- async function createItems(signal) {
1049
+ async function createItems(cache, signal) {
1034
1050
  const allStyles = provider.actions.all();
1035
1051
  const styles = [...allStyles].reverse().map((style) => {
1036
1052
  return {
@@ -1425,14 +1441,74 @@ var plainTransformer = createTransformer((value) => {
1425
1441
  return value;
1426
1442
  });
1427
1443
 
1428
- // src/transformers/shared/video-src-transformer.ts
1444
+ // src/transformers/shared/svg-src-transformer.ts
1445
+ var import_dompurify = __toESM(require("dompurify"));
1429
1446
  var import_wp_media2 = require("@elementor/wp-media");
1447
+ var SVG_INLINE_STYLES = "width: 100%; height: 100%; overflow: unset;";
1448
+ function processSvgContent(svgText) {
1449
+ const sanitized = import_dompurify.default.sanitize(svgText, {
1450
+ USE_PROFILES: { svg: true, svgFilters: true }
1451
+ });
1452
+ const parser = new DOMParser();
1453
+ const doc = parser.parseFromString(sanitized, "image/svg+xml");
1454
+ const svgElement = doc.querySelector("svg");
1455
+ if (!svgElement) {
1456
+ return null;
1457
+ }
1458
+ svgElement.setAttribute("fill", "currentColor");
1459
+ const existingStyle = svgElement.getAttribute("style") ?? "";
1460
+ const trimmed = existingStyle.trim();
1461
+ const merged = trimmed ? `${trimmed.replace(/;$/, "")}; ${SVG_INLINE_STYLES}` : SVG_INLINE_STYLES;
1462
+ svgElement.setAttribute("style", merged);
1463
+ return svgElement.outerHTML;
1464
+ }
1465
+ async function fetchSvgContent(url, signal) {
1466
+ try {
1467
+ const response = await fetch(url, { signal });
1468
+ if (!response.ok) {
1469
+ return null;
1470
+ }
1471
+ const contentType = response.headers.get("content-type") ?? "";
1472
+ const isSvg = contentType.includes("svg") || contentType.includes("xml") || url.endsWith(".svg");
1473
+ if (!isSvg) {
1474
+ return null;
1475
+ }
1476
+ return await response.text();
1477
+ } catch {
1478
+ return null;
1479
+ }
1480
+ }
1481
+ function resolveSvgSrcId(id) {
1482
+ if (typeof id !== "number" || id <= 0) {
1483
+ return null;
1484
+ }
1485
+ return id;
1486
+ }
1487
+ var svgSrcTransformer = createTransformer(async (value, { signal }) => {
1488
+ const id = resolveSvgSrcId(value.id);
1489
+ const urlFromValue = typeof value.url === "string" ? value.url : null;
1490
+ let url = urlFromValue;
1491
+ if (id && !urlFromValue) {
1492
+ const attachment = await (0, import_wp_media2.getMediaAttachment)({ id });
1493
+ url = attachment?.url ?? null;
1494
+ }
1495
+ const resolvedUrl = typeof url === "string" ? url : null;
1496
+ if (!resolvedUrl) {
1497
+ return { html: null, url: null };
1498
+ }
1499
+ const svgText = await fetchSvgContent(resolvedUrl, signal);
1500
+ const html = svgText ? processSvgContent(svgText) : null;
1501
+ return { html, url: resolvedUrl };
1502
+ });
1503
+
1504
+ // src/transformers/shared/video-src-transformer.ts
1505
+ var import_wp_media3 = require("@elementor/wp-media");
1430
1506
  var videoSrcTransformer = createTransformer(async (value) => {
1431
1507
  const { id, url } = value;
1432
1508
  if (!id) {
1433
1509
  return { id: null, url };
1434
1510
  }
1435
- const attachment = await (0, import_wp_media2.getMediaAttachment)({ id });
1511
+ const attachment = await (0, import_wp_media3.getMediaAttachment)({ id });
1436
1512
  return {
1437
1513
  id,
1438
1514
  url: attachment?.url ?? url
@@ -1441,7 +1517,7 @@ var videoSrcTransformer = createTransformer(async (value) => {
1441
1517
 
1442
1518
  // src/init-settings-transformers.ts
1443
1519
  function initSettingsTransformers() {
1444
- 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);
1520
+ 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);
1445
1521
  }
1446
1522
 
1447
1523
  // src/transformers/styles/background-color-overlay-transformer.ts
@@ -2321,9 +2397,11 @@ function createNestedTemplatedElementView({
2321
2397
  });
2322
2398
  }
2323
2399
 
2400
+ // src/legacy/replacements/manager.ts
2401
+ var import_client = require("react-dom/client");
2402
+
2324
2403
  // src/legacy/replacements/inline-editing/inline-editing-elements.tsx
2325
2404
  var React6 = __toESM(require("react"));
2326
- var import_client = require("react-dom/client");
2327
2405
  var import_editor_elements5 = require("@elementor/editor-elements");
2328
2406
  var import_editor_props4 = require("@elementor/editor-props");
2329
2407
  var import_editor_v1_adapters11 = require("@elementor/editor-v1-adapters");
@@ -2342,6 +2420,8 @@ var ReplacementBase = class {
2342
2420
  type;
2343
2421
  id;
2344
2422
  refreshView;
2423
+ reactRoot;
2424
+ reactContainer;
2345
2425
  constructor(settings) {
2346
2426
  this.getSetting = settings.getSetting;
2347
2427
  this.setSetting = settings.setSetting;
@@ -2349,6 +2429,8 @@ var ReplacementBase = class {
2349
2429
  this.type = settings.type;
2350
2430
  this.id = settings.id;
2351
2431
  this.refreshView = settings.refreshView;
2432
+ this.reactRoot = settings.reactRoot;
2433
+ this.reactContainer = settings.reactContainer;
2352
2434
  }
2353
2435
  static getTypes() {
2354
2436
  return null;
@@ -2399,7 +2481,8 @@ var INLINE_EDITING_PROPERTY_PER_TYPE = {
2399
2481
  "e-button": "text",
2400
2482
  "e-form-label": "text",
2401
2483
  "e-heading": "title",
2402
- "e-paragraph": "paragraph"
2484
+ "e-paragraph": "paragraph",
2485
+ "e-form-submit-button": "text"
2403
2486
  };
2404
2487
  var getInlineEditorElement = (elementWrapper, expectedTag) => {
2405
2488
  return !expectedTag ? null : elementWrapper.querySelector(expectedTag);
@@ -2417,6 +2500,11 @@ var useOnClickOutsideIframe = (handleUnmount) => {
2417
2500
  };
2418
2501
  var useRenderToolbar = (ownerDocument, id) => {
2419
2502
  const [anchor, setAnchor] = (0, import_react11.useState)(null);
2503
+ (0, import_react11.useEffect)(() => {
2504
+ if (!anchor) {
2505
+ removeToolbarAnchor(ownerDocument, id);
2506
+ }
2507
+ }, [anchor, ownerDocument, id]);
2420
2508
  const onSelectionEnd = (view) => {
2421
2509
  const hasSelection = !view.state.selection.empty;
2422
2510
  removeToolbarAnchor(ownerDocument, id);
@@ -2426,7 +2514,10 @@ var useRenderToolbar = (ownerDocument, id) => {
2426
2514
  setAnchor(null);
2427
2515
  }
2428
2516
  };
2429
- return { onSelectionEnd, anchor };
2517
+ const clearAnchor = (0, import_react11.useCallback)(() => {
2518
+ setAnchor(null);
2519
+ }, []);
2520
+ return { onSelectionEnd, anchor, clearAnchor };
2430
2521
  };
2431
2522
  var createAnchorBasedOnSelection = (ownerDocument, id) => {
2432
2523
  const frameWindow = ownerDocument.defaultView;
@@ -2493,46 +2584,59 @@ var horizontalShifterMiddleware = {
2493
2584
  };
2494
2585
 
2495
2586
  // src/legacy/replacements/inline-editing/canvas-inline-editor.tsx
2496
- var EDITOR_WRAPPER_SELECTOR = "inline-editor-wrapper";
2497
2587
  var CanvasInlineEditor = ({
2498
2588
  elementClasses,
2499
2589
  initialValue,
2500
2590
  expectedTag,
2501
2591
  rootElement,
2592
+ contentElement,
2502
2593
  id,
2503
2594
  setValue,
2504
- ...props
2595
+ requestDestroy
2505
2596
  }) => {
2597
+ const [active, setActive] = (0, import_react12.useState)(true);
2506
2598
  const [editor, setEditor] = (0, import_react12.useState)(null);
2507
- const { onSelectionEnd, anchor: toolbarAnchor } = useRenderToolbar(rootElement.ownerDocument, id);
2508
- const onBlur = () => {
2509
- removeToolbarAnchor(rootElement.ownerDocument, id);
2510
- props.onBlur();
2511
- };
2512
- useOnClickOutsideIframe(onBlur);
2513
- return /* @__PURE__ */ React5.createElement(import_ui4.ThemeProvider, null, /* @__PURE__ */ React5.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React5.createElement("style", null, `
2514
- .ProseMirror > * {
2515
- height: 100%;
2516
- }
2517
- .${EDITOR_WRAPPER_SELECTOR} .ProseMirror > button[contenteditable="true"] {
2518
- height: auto;
2519
- cursor: text;
2520
- }
2521
- `), /* @__PURE__ */ React5.createElement(
2599
+ const { onSelectionEnd, anchor: toolbarAnchor, clearAnchor } = useRenderToolbar(rootElement.ownerDocument, id);
2600
+ (0, import_react12.useEffect)(() => {
2601
+ if (!active) {
2602
+ clearAnchor();
2603
+ requestDestroy();
2604
+ }
2605
+ }, [active, clearAnchor, requestDestroy]);
2606
+ const dismiss = (0, import_react12.useCallback)(() => {
2607
+ setEditor(null);
2608
+ setActive(false);
2609
+ }, []);
2610
+ useOnClickOutsideIframe(dismiss);
2611
+ (0, import_react12.useEffect)(() => {
2612
+ const ownerDocument = contentElement.ownerDocument;
2613
+ const handleClickAway = (event) => {
2614
+ if (contentElement.contains(event.target)) {
2615
+ return;
2616
+ }
2617
+ dismiss();
2618
+ };
2619
+ ownerDocument.addEventListener("mousedown", handleClickAway);
2620
+ return () => ownerDocument.removeEventListener("mousedown", handleClickAway);
2621
+ }, [contentElement, dismiss]);
2622
+ if (!active) {
2623
+ return null;
2624
+ }
2625
+ return /* @__PURE__ */ React5.createElement(import_ui4.ThemeProvider, null, /* @__PURE__ */ React5.createElement(InlineEditingOverlay, { expectedTag, rootElement, id }), /* @__PURE__ */ React5.createElement(
2522
2626
  import_editor_controls2.InlineEditor,
2523
2627
  {
2524
2628
  onEditorCreate: setEditor,
2629
+ mountElement: contentElement,
2525
2630
  editorProps: {
2526
2631
  attributes: {
2527
- style: "outline: none;overflow-wrap: normal;height:100%"
2632
+ style: "outline: none; display: inherit; justify-content: inherit; align-items: inherit; flex-direction: inherit; text-align: inherit;"
2528
2633
  }
2529
2634
  },
2530
2635
  elementClasses,
2531
2636
  value: initialValue,
2532
2637
  setValue,
2533
- onBlur,
2638
+ onBlur: dismiss,
2534
2639
  autofocus: true,
2535
- expectedTag,
2536
2640
  onSelectionEnd
2537
2641
  }
2538
2642
  ), toolbarAnchor && editor && /* @__PURE__ */ React5.createElement(InlineEditingToolbar, { anchor: toolbarAnchor, editor, id }));
@@ -2561,7 +2665,18 @@ var InlineEditingToolbar = ({ anchor, editor, id }) => {
2561
2665
  refs.setReference(anchor);
2562
2666
  return () => refs.setReference(null);
2563
2667
  }, [anchor, refs]);
2564
- return /* @__PURE__ */ React5.createElement(import_react13.FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React5.createElement(import_ui4.Box, { ref: refs.setFloating, role: "presentation", style: { ...floatingStyles, pointerEvents: "none" } }, /* @__PURE__ */ React5.createElement(import_editor_controls2.InlineEditorToolbar, { editor, elementId: id })));
2668
+ return /* @__PURE__ */ React5.createElement(import_react13.FloatingPortal, { id: CANVAS_WRAPPER_ID }, /* @__PURE__ */ React5.createElement(
2669
+ import_ui4.Box,
2670
+ {
2671
+ ref: refs.setFloating,
2672
+ role: "presentation",
2673
+ style: {
2674
+ ...floatingStyles,
2675
+ pointerEvents: "none"
2676
+ }
2677
+ },
2678
+ /* @__PURE__ */ React5.createElement(import_editor_controls2.InlineEditorToolbar, { editor, elementId: id })
2679
+ ));
2565
2680
  };
2566
2681
 
2567
2682
  // src/legacy/replacements/inline-editing/inline-editing-eligibility.ts
@@ -2595,8 +2710,8 @@ var isInlineEditingAllowed = ({ rawValue, propTypeFromSchema }) => {
2595
2710
  // src/legacy/replacements/inline-editing/inline-editing-elements.tsx
2596
2711
  var HISTORY_DEBOUNCE_WAIT = 800;
2597
2712
  var InlineEditingReplacement = class extends ReplacementBase {
2598
- inlineEditorRoot = null;
2599
2713
  handlerAttached = false;
2714
+ editing = false;
2600
2715
  getReplacementKey() {
2601
2716
  return "inline-editing";
2602
2717
  }
@@ -2604,7 +2719,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
2604
2719
  return Object.keys(INLINE_EDITING_PROPERTY_PER_TYPE);
2605
2720
  }
2606
2721
  isEditingModeActive() {
2607
- return !!this.inlineEditorRoot;
2722
+ return this.editing;
2608
2723
  }
2609
2724
  shouldRenderReplacement() {
2610
2725
  return this.isInlineEditingEligible() && (0, import_editor_v1_adapters11.getCurrentEditMode)() === "edit";
@@ -2647,8 +2762,8 @@ var InlineEditingReplacement = class extends ReplacementBase {
2647
2762
  resetInlineEditorRoot() {
2648
2763
  this.element.removeEventListener("click", this.handleRenderInlineEditor);
2649
2764
  this.handlerAttached = false;
2650
- this.inlineEditorRoot?.unmount?.();
2651
- this.inlineEditorRoot = null;
2765
+ this.reactRoot.render(null);
2766
+ this.editing = false;
2652
2767
  }
2653
2768
  unmountInlineEditor() {
2654
2769
  this.resetInlineEditorRoot();
@@ -2759,12 +2874,16 @@ var InlineEditingReplacement = class extends ReplacementBase {
2759
2874
  if (this.isEditingModeActive()) {
2760
2875
  this.resetInlineEditorRoot();
2761
2876
  }
2762
- const elementClasses = this.element.children?.[0]?.classList.toString() ?? "";
2877
+ const contentElement = this.element.children?.[0];
2878
+ if (!contentElement) {
2879
+ return;
2880
+ }
2881
+ const elementClasses = contentElement.classList.toString();
2763
2882
  const propValue = this.getExtractedContentValue();
2764
2883
  const expectedTag = this.getExpectedTag();
2765
- this.element.innerHTML = "";
2766
- this.inlineEditorRoot = (0, import_client.createRoot)(this.element);
2767
- this.inlineEditorRoot.render(
2884
+ contentElement.innerHTML = "";
2885
+ this.editing = true;
2886
+ this.reactRoot.render(
2768
2887
  /* @__PURE__ */ React6.createElement(
2769
2888
  CanvasInlineEditor,
2770
2889
  {
@@ -2772,9 +2891,10 @@ var InlineEditingReplacement = class extends ReplacementBase {
2772
2891
  initialValue: propValue,
2773
2892
  expectedTag,
2774
2893
  rootElement: this.element,
2894
+ contentElement,
2775
2895
  id: this.id,
2776
2896
  setValue: this.setContentValue.bind(this),
2777
- onBlur: this.unmountInlineEditor.bind(this)
2897
+ requestDestroy: this.unmountInlineEditor.bind(this)
2778
2898
  }
2779
2899
  )
2780
2900
  );
@@ -2803,16 +2923,24 @@ var createViewWithReplacements = (options) => {
2803
2923
  return class extends TemplatedView {
2804
2924
  #replacement = null;
2805
2925
  #config;
2926
+ #reactContainer;
2927
+ #reactRoot;
2806
2928
  constructor(...args) {
2807
2929
  super(...args);
2808
2930
  const settings = this.model.get("settings");
2931
+ this.#reactContainer = this.el.ownerDocument.createElement("div");
2932
+ this.#reactContainer.style.display = "none";
2933
+ this.el.ownerDocument.body.appendChild(this.#reactContainer);
2934
+ this.#reactRoot = (0, import_client.createRoot)(this.#reactContainer);
2809
2935
  this.#config = {
2810
2936
  getSetting: settings.get.bind(settings),
2811
2937
  setSetting: settings.set.bind(settings),
2812
2938
  element: this.el,
2813
2939
  type: this?.model?.get("widgetType") ?? this.container?.model?.get("elType") ?? null,
2814
2940
  id: this?.model?.get("id") ?? null,
2815
- refreshView: this.refreshView.bind(this)
2941
+ refreshView: this.refreshView.bind(this),
2942
+ reactRoot: this.#reactRoot,
2943
+ reactContainer: this.#reactContainer
2816
2944
  };
2817
2945
  }
2818
2946
  refreshView() {
@@ -2833,6 +2961,8 @@ var createViewWithReplacements = (options) => {
2833
2961
  }
2834
2962
  onDestroy() {
2835
2963
  this.#triggerAltMethod("onDestroy");
2964
+ this.#reactRoot.unmount();
2965
+ this.#reactContainer.remove();
2836
2966
  }
2837
2967
  _afterRender() {
2838
2968
  this.#triggerAltMethod("_afterRender");