@elementor/editor-canvas 3.35.0-418 → 3.35.0-420

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
@@ -19,6 +19,8 @@ type DomRenderer = {
19
19
  render: TwingEnvironment['render'];
20
20
  };
21
21
 
22
+ type RenderContext<T = unknown> = Record<string, T>;
23
+ type NamespacedRenderContext<T = RenderContext> = Record<string, T | undefined>;
22
24
  type LegacyWindow = Window & {
23
25
  elementor: {
24
26
  createBackboneElementsCollection: (children: unknown) => BackboneCollection<ElementModel>;
@@ -61,6 +63,7 @@ declare class ElementView {
61
63
  children: {
62
64
  length: number;
63
65
  findByIndex: (index: number) => ElementView;
66
+ each: (callback: (view: ElementView) => void) => void;
64
67
  };
65
68
  constructor(...args: unknown[]);
66
69
  onRender(...args: unknown[]): void;
@@ -87,11 +90,16 @@ declare class ElementView {
87
90
  _isRendering: boolean;
88
91
  resetChildViewContainer(): void;
89
92
  isRendered: boolean;
93
+ _currentRenderPromise?: Promise<void>;
90
94
  options?: {
91
95
  model: BackboneModel<ElementModel>;
92
96
  };
93
97
  ui(): Record<string, unknown>;
94
98
  events(): Record<string, unknown>;
99
+ _parent?: ElementView;
100
+ getRenderContext(): NamespacedRenderContext | undefined;
101
+ getResolverRenderContext(): RenderContext | undefined;
102
+ getNamespaceKey(): string;
95
103
  }
96
104
  type JQueryElement = {
97
105
  find: (selector: string) => JQueryElement;
@@ -157,21 +165,12 @@ type ElementLegacyType = {
157
165
  };
158
166
  declare function registerElementType(type: string, elementTypeGenerator: ElementLegacyType[keyof ElementLegacyType]): void;
159
167
 
160
- declare class RenderContext<TContext extends Record<string, unknown>> {
161
- private key;
162
- private context;
163
- constructor(key: string, initialContext: TContext);
164
- get(): TContext;
165
- set(context: TContext): void;
166
- update(updates: TContext): void;
167
- delete(): void;
168
- clear(): void;
169
- }
170
-
171
- type UnbrandedTransformer<TValue> = (value: TValue, options: {
168
+ type TransformerOptions<TContext extends RenderContext = RenderContext> = {
172
169
  key: string;
173
170
  signal?: AbortSignal;
174
- }) => unknown;
171
+ renderContext?: TContext;
172
+ };
173
+ type UnbrandedTransformer<TValue> = (value: TValue, options: TransformerOptions) => unknown;
175
174
  type Transformer<TValue> = UnbrandedTransformer<TValue> & {
176
175
  __transformer: true;
177
176
  };
@@ -199,10 +198,11 @@ type ResolveArgs = {
199
198
  props: Props;
200
199
  schema?: PropsSchema;
201
200
  signal?: AbortSignal;
201
+ renderContext?: RenderContext;
202
202
  };
203
203
  type ResolvedProps = Record<string, unknown>;
204
204
  type PropsResolver = ReturnType<typeof createPropsResolver>;
205
- declare function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }: CreatePropResolverArgs): ({ props, schema, signal }: ResolveArgs) => Promise<ResolvedProps>;
205
+ declare function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }: CreatePropResolverArgs): ({ props, schema, signal, renderContext }: ResolveArgs) => Promise<ResolvedProps>;
206
206
 
207
207
  declare const settingsTransformersRegistry: {
208
208
  register(type: _elementor_editor_props.PropTypeKey, transformer: AnyTransformer): /*elided*/ any;
@@ -264,4 +264,4 @@ declare const UnknownStyleStateError: {
264
264
  isError(error: unknown): error is Error;
265
265
  };
266
266
 
267
- export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, type LegacyWindow, type PropsResolver, RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, endDragElementFromPanel, getCanvasIframeDocument, init, isAtomicWidget, registerElementType, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry };
267
+ export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, type LegacyWindow, type NamespacedRenderContext, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, endDragElementFromPanel, getCanvasIframeDocument, init, isAtomicWidget, registerElementType, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry };
package/dist/index.d.ts CHANGED
@@ -19,6 +19,8 @@ type DomRenderer = {
19
19
  render: TwingEnvironment['render'];
20
20
  };
21
21
 
22
+ type RenderContext<T = unknown> = Record<string, T>;
23
+ type NamespacedRenderContext<T = RenderContext> = Record<string, T | undefined>;
22
24
  type LegacyWindow = Window & {
23
25
  elementor: {
24
26
  createBackboneElementsCollection: (children: unknown) => BackboneCollection<ElementModel>;
@@ -61,6 +63,7 @@ declare class ElementView {
61
63
  children: {
62
64
  length: number;
63
65
  findByIndex: (index: number) => ElementView;
66
+ each: (callback: (view: ElementView) => void) => void;
64
67
  };
65
68
  constructor(...args: unknown[]);
66
69
  onRender(...args: unknown[]): void;
@@ -87,11 +90,16 @@ declare class ElementView {
87
90
  _isRendering: boolean;
88
91
  resetChildViewContainer(): void;
89
92
  isRendered: boolean;
93
+ _currentRenderPromise?: Promise<void>;
90
94
  options?: {
91
95
  model: BackboneModel<ElementModel>;
92
96
  };
93
97
  ui(): Record<string, unknown>;
94
98
  events(): Record<string, unknown>;
99
+ _parent?: ElementView;
100
+ getRenderContext(): NamespacedRenderContext | undefined;
101
+ getResolverRenderContext(): RenderContext | undefined;
102
+ getNamespaceKey(): string;
95
103
  }
96
104
  type JQueryElement = {
97
105
  find: (selector: string) => JQueryElement;
@@ -157,21 +165,12 @@ type ElementLegacyType = {
157
165
  };
158
166
  declare function registerElementType(type: string, elementTypeGenerator: ElementLegacyType[keyof ElementLegacyType]): void;
159
167
 
160
- declare class RenderContext<TContext extends Record<string, unknown>> {
161
- private key;
162
- private context;
163
- constructor(key: string, initialContext: TContext);
164
- get(): TContext;
165
- set(context: TContext): void;
166
- update(updates: TContext): void;
167
- delete(): void;
168
- clear(): void;
169
- }
170
-
171
- type UnbrandedTransformer<TValue> = (value: TValue, options: {
168
+ type TransformerOptions<TContext extends RenderContext = RenderContext> = {
172
169
  key: string;
173
170
  signal?: AbortSignal;
174
- }) => unknown;
171
+ renderContext?: TContext;
172
+ };
173
+ type UnbrandedTransformer<TValue> = (value: TValue, options: TransformerOptions) => unknown;
175
174
  type Transformer<TValue> = UnbrandedTransformer<TValue> & {
176
175
  __transformer: true;
177
176
  };
@@ -199,10 +198,11 @@ type ResolveArgs = {
199
198
  props: Props;
200
199
  schema?: PropsSchema;
201
200
  signal?: AbortSignal;
201
+ renderContext?: RenderContext;
202
202
  };
203
203
  type ResolvedProps = Record<string, unknown>;
204
204
  type PropsResolver = ReturnType<typeof createPropsResolver>;
205
- declare function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }: CreatePropResolverArgs): ({ props, schema, signal }: ResolveArgs) => Promise<ResolvedProps>;
205
+ declare function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }: CreatePropResolverArgs): ({ props, schema, signal, renderContext }: ResolveArgs) => Promise<ResolvedProps>;
206
206
 
207
207
  declare const settingsTransformersRegistry: {
208
208
  register(type: _elementor_editor_props.PropTypeKey, transformer: AnyTransformer): /*elided*/ any;
@@ -264,4 +264,4 @@ declare const UnknownStyleStateError: {
264
264
  isError(error: unknown): error is Error;
265
265
  };
266
266
 
267
- export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, type LegacyWindow, type PropsResolver, RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, endDragElementFromPanel, getCanvasIframeDocument, init, isAtomicWidget, registerElementType, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry };
267
+ export { type AnyTransformer, BREAKPOINTS_SCHEMA_URI, type BackboneModel, type BackboneModelConstructor, type CreateTemplatedElementTypeOptions, DOCUMENT_STRUCTURE_URI, type ElementModel, ElementType, ElementView, type LegacyWindow, type NamespacedRenderContext, type PropsResolver, type RenderContext, type ReplacementSettings, STYLE_SCHEMA_URI, type TransformerOptions, UnknownStyleStateError, UnknownStyleTypeError, WIDGET_SCHEMA_URI, createPropsResolver, createTemplatedElementView, createTransformer, createTransformersRegistry, endDragElementFromPanel, getCanvasIframeDocument, init, isAtomicWidget, registerElementType, settingsTransformersRegistry, startDragElementFromPanel, styleTransformersRegistry };
package/dist/index.js CHANGED
@@ -32,7 +32,6 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  BREAKPOINTS_SCHEMA_URI: () => BREAKPOINTS_SCHEMA_URI,
34
34
  DOCUMENT_STRUCTURE_URI: () => DOCUMENT_STRUCTURE_URI,
35
- RenderContext: () => RenderContext,
36
35
  STYLE_SCHEMA_URI: () => STYLE_SCHEMA_URI,
37
36
  UnknownStyleStateError: () => UnknownStyleStateError,
38
37
  UnknownStyleTypeError: () => UnknownStyleTypeError,
@@ -673,12 +672,12 @@ var getMultiPropsValue = (multiProps) => {
673
672
  // src/renderers/create-props-resolver.ts
674
673
  var TRANSFORM_DEPTH_LIMIT = 3;
675
674
  function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }) {
676
- async function resolve({ props, schema: schema2, signal }) {
675
+ async function resolve({ props, schema: schema2, signal, renderContext }) {
677
676
  schema2 = schema2 ?? initialSchema;
678
677
  const promises = Promise.all(
679
678
  Object.entries(schema2).map(async ([key, type]) => {
680
679
  const value = props[key] ?? type.default;
681
- const transformed = await transform({ value, key, type, signal });
680
+ const transformed = await transform({ value, key, type, signal, renderContext });
682
681
  onPropResolve?.({ key, value: transformed });
683
682
  if (isMultiProps(transformed)) {
684
683
  return getMultiPropsValue(transformed);
@@ -688,7 +687,7 @@ function createPropsResolver({ transformers, schema: initialSchema, onPropResolv
688
687
  );
689
688
  return Object.assign({}, ...(await promises).filter(Boolean));
690
689
  }
691
- async function transform({ value, key, type, signal, depth = 0 }) {
690
+ async function transform({ value, key, type, signal, depth = 0, renderContext }) {
692
691
  if (value === null || value === void 0) {
693
692
  return null;
694
693
  }
@@ -721,13 +720,21 @@ function createPropsResolver({ transformers, schema: initialSchema, onPropResolv
721
720
  resolvedValue = await resolve({
722
721
  props: resolvedValue,
723
722
  schema: transformablePropType.shape,
724
- signal
723
+ signal,
724
+ renderContext
725
725
  });
726
726
  }
727
727
  if (transformablePropType.kind === "array") {
728
728
  resolvedValue = await Promise.all(
729
729
  resolvedValue.map(
730
- (item) => transform({ value: item, key, type: transformablePropType.item_prop_type, depth, signal })
730
+ (item) => transform({
731
+ value: item,
732
+ key,
733
+ type: transformablePropType.item_prop_type,
734
+ depth,
735
+ signal,
736
+ renderContext
737
+ })
731
738
  )
732
739
  );
733
740
  }
@@ -736,8 +743,8 @@ function createPropsResolver({ transformers, schema: initialSchema, onPropResolv
736
743
  return null;
737
744
  }
738
745
  try {
739
- const transformed = await transformer(resolvedValue, { key, signal });
740
- return transform({ value: transformed, key, type, signal, depth: depth + 1 });
746
+ const transformed = await transformer(resolvedValue, { key, signal, renderContext });
747
+ return transform({ value: transformed, key, type, signal, depth: depth + 1, renderContext });
741
748
  } catch {
742
749
  return null;
743
750
  }
@@ -1581,22 +1588,45 @@ function createTemplatedElementView({
1581
1588
  });
1582
1589
  return class extends BaseView {
1583
1590
  #abortController = null;
1591
+ #childrenRenderPromises = [];
1584
1592
  getTemplateType() {
1585
1593
  return "twig";
1586
1594
  }
1595
+ getNamespaceKey() {
1596
+ return type;
1597
+ }
1587
1598
  renderOnChange() {
1588
1599
  this.render();
1589
1600
  }
1601
+ getRenderContext() {
1602
+ return this._parent?.getRenderContext?.();
1603
+ }
1604
+ getResolverRenderContext() {
1605
+ return this._parent?.getResolverRenderContext?.();
1606
+ }
1590
1607
  // Override `render` function to support async `_renderTemplate`
1591
1608
  // Note that `_renderChildren` asynchronity is still NOT supported, so only the parent element rendering can be async
1592
1609
  render() {
1593
1610
  this.#abortController?.abort();
1594
1611
  this.#abortController = new AbortController();
1595
- const process = signalizedProcess(this.#abortController.signal).then(() => this._beforeRender()).then(() => this._renderTemplate()).then(() => {
1596
- this._renderChildren();
1597
- this._afterRender();
1612
+ const process = signalizedProcess(this.#abortController.signal).then(() => this._beforeRender()).then(() => this._renderTemplate()).then(() => this._renderChildren()).then(() => this._afterRender());
1613
+ this._currentRenderPromise = process.execute();
1614
+ return this._currentRenderPromise;
1615
+ }
1616
+ async _renderChildren() {
1617
+ super._renderChildren();
1618
+ this.#childrenRenderPromises = [];
1619
+ this.children?.each((childView) => {
1620
+ if (childView._currentRenderPromise) {
1621
+ this.#childrenRenderPromises.push(childView._currentRenderPromise);
1622
+ }
1598
1623
  });
1599
- return process.execute();
1624
+ await this._waitForChildrenToComplete();
1625
+ }
1626
+ async _waitForChildrenToComplete() {
1627
+ if (this.#childrenRenderPromises.length > 0) {
1628
+ await Promise.all(this.#childrenRenderPromises);
1629
+ }
1600
1630
  }
1601
1631
  // Overriding Marionette original `_renderTemplate` method to inject our renderer.
1602
1632
  async _renderTemplate() {
@@ -1605,7 +1635,8 @@ function createTemplatedElementView({
1605
1635
  const settings = this.model.get("settings").toJSON();
1606
1636
  return resolveProps({
1607
1637
  props: settings,
1608
- signal
1638
+ signal,
1639
+ renderContext: this.getResolverRenderContext()
1609
1640
  });
1610
1641
  }).then((settings) => {
1611
1642
  return this.afterSettingsResolve(settings);
@@ -3617,35 +3648,6 @@ function init() {
3617
3648
  );
3618
3649
  }
3619
3650
 
3620
- // src/renderers/render-context.ts
3621
- var RenderContext = class {
3622
- key;
3623
- context = /* @__PURE__ */ new Map();
3624
- constructor(key, initialContext) {
3625
- this.key = key;
3626
- this.context.set(this.key, initialContext);
3627
- }
3628
- get() {
3629
- return this.context.get(this.key);
3630
- }
3631
- set(context) {
3632
- this.context.set(this.key, context);
3633
- }
3634
- update(updates) {
3635
- const currentContext = this.context.get(this.key);
3636
- if (!currentContext) {
3637
- return this.set(updates);
3638
- }
3639
- this.context.set(this.key, { ...currentContext, ...updates });
3640
- }
3641
- delete() {
3642
- this.context.delete(this.key);
3643
- }
3644
- clear() {
3645
- this.context.clear();
3646
- }
3647
- };
3648
-
3649
3651
  // src/sync/drag-element-from-panel.ts
3650
3652
  var DRAG_GROUPS = ["elementor-element"];
3651
3653
  var endDragElementFromPanel = () => {
@@ -3694,7 +3696,6 @@ var getLegacyPanelElementView = ({ settings, ...rest }) => {
3694
3696
  0 && (module.exports = {
3695
3697
  BREAKPOINTS_SCHEMA_URI,
3696
3698
  DOCUMENT_STRUCTURE_URI,
3697
- RenderContext,
3698
3699
  STYLE_SCHEMA_URI,
3699
3700
  UnknownStyleStateError,
3700
3701
  UnknownStyleTypeError,
package/dist/index.mjs CHANGED
@@ -629,12 +629,12 @@ var getMultiPropsValue = (multiProps) => {
629
629
  // src/renderers/create-props-resolver.ts
630
630
  var TRANSFORM_DEPTH_LIMIT = 3;
631
631
  function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }) {
632
- async function resolve({ props, schema: schema2, signal }) {
632
+ async function resolve({ props, schema: schema2, signal, renderContext }) {
633
633
  schema2 = schema2 ?? initialSchema;
634
634
  const promises = Promise.all(
635
635
  Object.entries(schema2).map(async ([key, type]) => {
636
636
  const value = props[key] ?? type.default;
637
- const transformed = await transform({ value, key, type, signal });
637
+ const transformed = await transform({ value, key, type, signal, renderContext });
638
638
  onPropResolve?.({ key, value: transformed });
639
639
  if (isMultiProps(transformed)) {
640
640
  return getMultiPropsValue(transformed);
@@ -644,7 +644,7 @@ function createPropsResolver({ transformers, schema: initialSchema, onPropResolv
644
644
  );
645
645
  return Object.assign({}, ...(await promises).filter(Boolean));
646
646
  }
647
- async function transform({ value, key, type, signal, depth = 0 }) {
647
+ async function transform({ value, key, type, signal, depth = 0, renderContext }) {
648
648
  if (value === null || value === void 0) {
649
649
  return null;
650
650
  }
@@ -677,13 +677,21 @@ function createPropsResolver({ transformers, schema: initialSchema, onPropResolv
677
677
  resolvedValue = await resolve({
678
678
  props: resolvedValue,
679
679
  schema: transformablePropType.shape,
680
- signal
680
+ signal,
681
+ renderContext
681
682
  });
682
683
  }
683
684
  if (transformablePropType.kind === "array") {
684
685
  resolvedValue = await Promise.all(
685
686
  resolvedValue.map(
686
- (item) => transform({ value: item, key, type: transformablePropType.item_prop_type, depth, signal })
687
+ (item) => transform({
688
+ value: item,
689
+ key,
690
+ type: transformablePropType.item_prop_type,
691
+ depth,
692
+ signal,
693
+ renderContext
694
+ })
687
695
  )
688
696
  );
689
697
  }
@@ -692,8 +700,8 @@ function createPropsResolver({ transformers, schema: initialSchema, onPropResolv
692
700
  return null;
693
701
  }
694
702
  try {
695
- const transformed = await transformer(resolvedValue, { key, signal });
696
- return transform({ value: transformed, key, type, signal, depth: depth + 1 });
703
+ const transformed = await transformer(resolvedValue, { key, signal, renderContext });
704
+ return transform({ value: transformed, key, type, signal, depth: depth + 1, renderContext });
697
705
  } catch {
698
706
  return null;
699
707
  }
@@ -1539,22 +1547,45 @@ function createTemplatedElementView({
1539
1547
  });
1540
1548
  return class extends BaseView {
1541
1549
  #abortController = null;
1550
+ #childrenRenderPromises = [];
1542
1551
  getTemplateType() {
1543
1552
  return "twig";
1544
1553
  }
1554
+ getNamespaceKey() {
1555
+ return type;
1556
+ }
1545
1557
  renderOnChange() {
1546
1558
  this.render();
1547
1559
  }
1560
+ getRenderContext() {
1561
+ return this._parent?.getRenderContext?.();
1562
+ }
1563
+ getResolverRenderContext() {
1564
+ return this._parent?.getResolverRenderContext?.();
1565
+ }
1548
1566
  // Override `render` function to support async `_renderTemplate`
1549
1567
  // Note that `_renderChildren` asynchronity is still NOT supported, so only the parent element rendering can be async
1550
1568
  render() {
1551
1569
  this.#abortController?.abort();
1552
1570
  this.#abortController = new AbortController();
1553
- const process = signalizedProcess(this.#abortController.signal).then(() => this._beforeRender()).then(() => this._renderTemplate()).then(() => {
1554
- this._renderChildren();
1555
- this._afterRender();
1571
+ const process = signalizedProcess(this.#abortController.signal).then(() => this._beforeRender()).then(() => this._renderTemplate()).then(() => this._renderChildren()).then(() => this._afterRender());
1572
+ this._currentRenderPromise = process.execute();
1573
+ return this._currentRenderPromise;
1574
+ }
1575
+ async _renderChildren() {
1576
+ super._renderChildren();
1577
+ this.#childrenRenderPromises = [];
1578
+ this.children?.each((childView) => {
1579
+ if (childView._currentRenderPromise) {
1580
+ this.#childrenRenderPromises.push(childView._currentRenderPromise);
1581
+ }
1556
1582
  });
1557
- return process.execute();
1583
+ await this._waitForChildrenToComplete();
1584
+ }
1585
+ async _waitForChildrenToComplete() {
1586
+ if (this.#childrenRenderPromises.length > 0) {
1587
+ await Promise.all(this.#childrenRenderPromises);
1588
+ }
1558
1589
  }
1559
1590
  // Overriding Marionette original `_renderTemplate` method to inject our renderer.
1560
1591
  async _renderTemplate() {
@@ -1563,7 +1594,8 @@ function createTemplatedElementView({
1563
1594
  const settings = this.model.get("settings").toJSON();
1564
1595
  return resolveProps({
1565
1596
  props: settings,
1566
- signal
1597
+ signal,
1598
+ renderContext: this.getResolverRenderContext()
1567
1599
  });
1568
1600
  }).then((settings) => {
1569
1601
  return this.afterSettingsResolve(settings);
@@ -3607,35 +3639,6 @@ function init() {
3607
3639
  );
3608
3640
  }
3609
3641
 
3610
- // src/renderers/render-context.ts
3611
- var RenderContext = class {
3612
- key;
3613
- context = /* @__PURE__ */ new Map();
3614
- constructor(key, initialContext) {
3615
- this.key = key;
3616
- this.context.set(this.key, initialContext);
3617
- }
3618
- get() {
3619
- return this.context.get(this.key);
3620
- }
3621
- set(context) {
3622
- this.context.set(this.key, context);
3623
- }
3624
- update(updates) {
3625
- const currentContext = this.context.get(this.key);
3626
- if (!currentContext) {
3627
- return this.set(updates);
3628
- }
3629
- this.context.set(this.key, { ...currentContext, ...updates });
3630
- }
3631
- delete() {
3632
- this.context.delete(this.key);
3633
- }
3634
- clear() {
3635
- this.context.clear();
3636
- }
3637
- };
3638
-
3639
3642
  // src/sync/drag-element-from-panel.ts
3640
3643
  var DRAG_GROUPS = ["elementor-element"];
3641
3644
  var endDragElementFromPanel = () => {
@@ -3683,7 +3686,6 @@ var getLegacyPanelElementView = ({ settings, ...rest }) => {
3683
3686
  export {
3684
3687
  BREAKPOINTS_SCHEMA_URI,
3685
3688
  DOCUMENT_STRUCTURE_URI,
3686
- RenderContext,
3687
3689
  STYLE_SCHEMA_URI,
3688
3690
  UnknownStyleStateError,
3689
3691
  UnknownStyleTypeError,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "3.35.0-418",
4
+ "version": "3.35.0-420",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,24 +37,24 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "3.35.0-418",
41
- "@elementor/editor-controls": "3.35.0-418",
42
- "@elementor/editor-documents": "3.35.0-418",
43
- "@elementor/editor-elements": "3.35.0-418",
44
- "@elementor/editor-interactions": "3.35.0-418",
45
- "@elementor/editor-mcp": "3.35.0-418",
46
- "@elementor/editor-notifications": "3.35.0-418",
47
- "@elementor/editor-props": "3.35.0-418",
48
- "@elementor/editor-responsive": "3.35.0-418",
49
- "@elementor/editor-styles": "3.35.0-418",
50
- "@elementor/editor-styles-repository": "3.35.0-418",
51
- "@elementor/editor-ui": "3.35.0-418",
52
- "@elementor/editor-v1-adapters": "3.35.0-418",
53
- "@elementor/schema": "3.35.0-418",
54
- "@elementor/twing": "3.35.0-418",
40
+ "@elementor/editor": "3.35.0-420",
41
+ "@elementor/editor-controls": "3.35.0-420",
42
+ "@elementor/editor-documents": "3.35.0-420",
43
+ "@elementor/editor-elements": "3.35.0-420",
44
+ "@elementor/editor-interactions": "3.35.0-420",
45
+ "@elementor/editor-mcp": "3.35.0-420",
46
+ "@elementor/editor-notifications": "3.35.0-420",
47
+ "@elementor/editor-props": "3.35.0-420",
48
+ "@elementor/editor-responsive": "3.35.0-420",
49
+ "@elementor/editor-styles": "3.35.0-420",
50
+ "@elementor/editor-styles-repository": "3.35.0-420",
51
+ "@elementor/editor-ui": "3.35.0-420",
52
+ "@elementor/editor-v1-adapters": "3.35.0-420",
53
+ "@elementor/schema": "3.35.0-420",
54
+ "@elementor/twing": "3.35.0-420",
55
55
  "@elementor/ui": "1.36.17",
56
- "@elementor/utils": "3.35.0-418",
57
- "@elementor/wp-media": "3.35.0-418",
56
+ "@elementor/utils": "3.35.0-420",
57
+ "@elementor/wp-media": "3.35.0-420",
58
58
  "@floating-ui/react": "^0.27.5",
59
59
  "@wordpress/i18n": "^5.13.0"
60
60
  },
package/src/index.ts CHANGED
@@ -10,7 +10,6 @@ export {
10
10
  } from './legacy/create-templated-element-type';
11
11
  export { registerElementType } from './legacy/init-legacy-views';
12
12
  export * from './legacy/types';
13
- export { RenderContext } from './renderers/render-context';
14
13
  export { createPropsResolver, type PropsResolver } from './renderers/create-props-resolver';
15
14
  export { settingsTransformersRegistry } from './settings-transformers-registry';
16
15
  export { styleTransformersRegistry } from './style-transformers-registry';
@@ -21,5 +20,5 @@ export { WIDGET_SCHEMA_URI } from './mcp/resources/widgets-schema-resource';
21
20
  export * from './legacy/types';
22
21
  export { createTransformer } from './transformers/create-transformer';
23
22
  export { createTransformersRegistry } from './transformers/create-transformers-registry';
24
- export { type AnyTransformer } from './transformers/types';
23
+ export { type AnyTransformer, type TransformerOptions } from './transformers/types';
25
24
  export { UnknownStyleTypeError, UnknownStyleStateError } from './renderers/errors';
@@ -5,7 +5,13 @@ import { createPropsResolver } from '../renderers/create-props-resolver';
5
5
  import { settingsTransformersRegistry } from '../settings-transformers-registry';
6
6
  import { signalizedProcess } from '../utils/signalized-process';
7
7
  import { createElementViewClassDeclaration } from './create-element-type';
8
- import { type ElementType, type ElementView, type LegacyWindow } from './types';
8
+ import {
9
+ type ElementType,
10
+ type ElementView,
11
+ type LegacyWindow,
12
+ type NamespacedRenderContext,
13
+ type RenderContext,
14
+ } from './types';
9
15
 
10
16
  export type CreateTemplatedElementTypeOptions = {
11
17
  type: string;
@@ -70,15 +76,28 @@ export function createTemplatedElementView( {
70
76
 
71
77
  return class extends BaseView {
72
78
  #abortController: AbortController | null = null;
79
+ #childrenRenderPromises: Promise< void >[] = [];
73
80
 
74
81
  getTemplateType() {
75
82
  return 'twig';
76
83
  }
77
84
 
85
+ getNamespaceKey() {
86
+ return type;
87
+ }
88
+
78
89
  renderOnChange() {
79
90
  this.render();
80
91
  }
81
92
 
93
+ getRenderContext(): NamespacedRenderContext | undefined {
94
+ return this._parent?.getRenderContext?.();
95
+ }
96
+
97
+ getResolverRenderContext(): RenderContext | undefined {
98
+ return this._parent?.getResolverRenderContext?.();
99
+ }
100
+
82
101
  // Override `render` function to support async `_renderTemplate`
83
102
  // Note that `_renderChildren` asynchronity is still NOT supported, so only the parent element rendering can be async
84
103
  render() {
@@ -88,12 +107,32 @@ export function createTemplatedElementView( {
88
107
  const process = signalizedProcess( this.#abortController.signal )
89
108
  .then( () => this._beforeRender() )
90
109
  .then( () => this._renderTemplate() )
91
- .then( () => {
92
- this._renderChildren();
93
- this._afterRender();
94
- } );
110
+ .then( () => this._renderChildren() )
111
+ .then( () => this._afterRender() );
112
+
113
+ this._currentRenderPromise = process.execute();
114
+
115
+ return this._currentRenderPromise;
116
+ }
117
+
118
+ async _renderChildren() {
119
+ super._renderChildren();
120
+
121
+ this.#childrenRenderPromises = [];
122
+
123
+ this.children?.each( ( childView: ElementView ) => {
124
+ if ( childView._currentRenderPromise ) {
125
+ this.#childrenRenderPromises.push( childView._currentRenderPromise );
126
+ }
127
+ } );
128
+
129
+ await this._waitForChildrenToComplete();
130
+ }
95
131
 
96
- return process.execute();
132
+ async _waitForChildrenToComplete() {
133
+ if ( this.#childrenRenderPromises.length > 0 ) {
134
+ await Promise.all( this.#childrenRenderPromises );
135
+ }
97
136
  }
98
137
 
99
138
  // Overriding Marionette original `_renderTemplate` method to inject our renderer.
@@ -107,6 +146,7 @@ export function createTemplatedElementView( {
107
146
  return resolveProps( {
108
147
  props: settings,
109
148
  signal,
149
+ renderContext: this.getResolverRenderContext(),
110
150
  } );
111
151
  } )
112
152
  .then( ( settings ) => {
@@ -1,6 +1,10 @@
1
1
  import { type V1Element } from '@elementor/editor-elements';
2
2
  import { type Props, type PropValue } from '@elementor/editor-props';
3
3
 
4
+ export type RenderContext< T = unknown > = Record< string, T >;
5
+
6
+ export type NamespacedRenderContext< T = RenderContext > = Record< string, T | undefined >;
7
+
4
8
  export type LegacyWindow = Window & {
5
9
  elementor: {
6
10
  createBackboneElementsCollection: ( children: unknown ) => BackboneCollection< ElementModel >;
@@ -50,6 +54,7 @@ export declare class ElementView {
50
54
  children: {
51
55
  length: number;
52
56
  findByIndex: ( index: number ) => ElementView;
57
+ each: ( callback: ( view: ElementView ) => void ) => void;
53
58
  };
54
59
 
55
60
  constructor( ...args: unknown[] );
@@ -99,6 +104,8 @@ export declare class ElementView {
99
104
 
100
105
  isRendered: boolean;
101
106
 
107
+ _currentRenderPromise?: Promise< void >;
108
+
102
109
  options?: {
103
110
  model: BackboneModel< ElementModel >;
104
111
  };
@@ -106,6 +113,14 @@ export declare class ElementView {
106
113
  ui(): Record< string, unknown >;
107
114
 
108
115
  events(): Record< string, unknown >;
116
+
117
+ _parent?: ElementView;
118
+
119
+ getRenderContext(): NamespacedRenderContext | undefined;
120
+
121
+ getResolverRenderContext(): RenderContext | undefined;
122
+
123
+ getNamespaceKey(): string;
109
124
  }
110
125
 
111
126
  type JQueryElement = {
@@ -290,4 +290,153 @@ describe( 'createPropsResolver', () => {
290
290
  expect( onResolve ).toHaveBeenNthCalledWith( 1, { key: 'int', value: 2 } );
291
291
  expect( onResolve ).toHaveBeenNthCalledWith( 2, { key: 'int2', value: 4 } );
292
292
  } );
293
+
294
+ it( 'should pass renderContext to transformers', async () => {
295
+ // Arrange.
296
+ const CONTEXT_KEY = 'test-key';
297
+ const CONTEXT_VALUE = 'from-context';
298
+
299
+ const transformers = createTransformersRegistry().register(
300
+ 'context-aware',
301
+ createTransformer< { key: string } >( ( value, options ) => {
302
+ return options.renderContext?.[ value.key ] ?? 'fallback';
303
+ } )
304
+ );
305
+
306
+ const resolve = createPropsResolver( {
307
+ transformers,
308
+ schema: {
309
+ text: createMockPropType( { kind: 'plain', key: 'context-aware' } ),
310
+ },
311
+ } );
312
+
313
+ // Act.
314
+ const result = await resolve( {
315
+ props: {
316
+ text: { $$type: 'context-aware', value: { key: CONTEXT_KEY } },
317
+ },
318
+ renderContext: { [ CONTEXT_KEY ]: CONTEXT_VALUE },
319
+ } );
320
+
321
+ // Assert.
322
+ expect( result ).toEqual( { text: CONTEXT_VALUE } );
323
+ } );
324
+
325
+ it( 'should use fallback when renderContext is not provided', async () => {
326
+ // Arrange.
327
+ const transformers = createTransformersRegistry().register(
328
+ 'context-aware',
329
+ createTransformer< { key: string } >( ( value, options ) => {
330
+ return options.renderContext?.[ value.key ] ?? 'fallback';
331
+ } )
332
+ );
333
+
334
+ const resolve = createPropsResolver( {
335
+ transformers,
336
+ schema: {
337
+ text: createMockPropType( { kind: 'plain', key: 'context-aware' } ),
338
+ },
339
+ } );
340
+
341
+ // Act.
342
+ const result = await resolve( {
343
+ props: {
344
+ text: { $$type: 'context-aware', value: { key: 'any-key' } },
345
+ },
346
+ } );
347
+
348
+ // Assert.
349
+ expect( result ).toEqual( { text: 'fallback' } );
350
+ } );
351
+
352
+ it( 'should propagate renderContext through nested object props', async () => {
353
+ // Arrange.
354
+ const CONTEXT_KEY = 'nested-key';
355
+ const CONTEXT_VALUE = 'nested-context';
356
+
357
+ const transformers = createTransformersRegistry()
358
+ .register(
359
+ 'object',
360
+ createTransformer< unknown >( ( value ) => value )
361
+ )
362
+ .register(
363
+ 'context-aware',
364
+ createTransformer< { key: string } >( ( value, options ) => {
365
+ return options.renderContext?.[ value.key ] ?? 'fallback';
366
+ } )
367
+ );
368
+
369
+ const nestedSchema = {
370
+ inner: createMockPropType( { kind: 'plain', key: 'context-aware' } ),
371
+ };
372
+
373
+ const resolve = createPropsResolver( {
374
+ transformers,
375
+ schema: {
376
+ outer: createMockPropType( { kind: 'object', key: 'object', shape: nestedSchema } ),
377
+ },
378
+ } );
379
+
380
+ // Act.
381
+ const result = await resolve( {
382
+ props: {
383
+ outer: {
384
+ $$type: 'object',
385
+ value: {
386
+ inner: { $$type: 'context-aware', value: { key: CONTEXT_KEY } },
387
+ },
388
+ },
389
+ },
390
+ renderContext: { [ CONTEXT_KEY ]: CONTEXT_VALUE },
391
+ } );
392
+
393
+ // Assert.
394
+ expect( result ).toEqual( { outer: { inner: CONTEXT_VALUE } } );
395
+ } );
396
+
397
+ it( 'should propagate renderContext through array props', async () => {
398
+ // Arrange.
399
+ const CONTEXT_KEY = 'array-key';
400
+ const CONTEXT_VALUE = 'array-context';
401
+
402
+ const transformers = createTransformersRegistry()
403
+ .register(
404
+ 'array',
405
+ createTransformer< unknown >( ( value ) => value )
406
+ )
407
+ .register(
408
+ 'context-aware',
409
+ createTransformer< { key: string } >( ( value, options ) => {
410
+ return options.renderContext?.[ value.key ] ?? 'fallback';
411
+ } )
412
+ );
413
+
414
+ const resolve = createPropsResolver( {
415
+ transformers,
416
+ schema: {
417
+ items: createMockPropType( {
418
+ kind: 'array',
419
+ key: 'array',
420
+ item_prop_type: createMockPropType( { kind: 'plain', key: 'context-aware' } ),
421
+ } ),
422
+ },
423
+ } );
424
+
425
+ // Act.
426
+ const result = await resolve( {
427
+ props: {
428
+ items: {
429
+ $$type: 'array',
430
+ value: [
431
+ { $$type: 'context-aware', value: { key: CONTEXT_KEY } },
432
+ { $$type: 'context-aware', value: { key: CONTEXT_KEY } },
433
+ ],
434
+ },
435
+ },
436
+ renderContext: { [ CONTEXT_KEY ]: CONTEXT_VALUE },
437
+ } );
438
+
439
+ // Assert.
440
+ expect( result ).toEqual( { items: [ CONTEXT_VALUE, CONTEXT_VALUE ] } );
441
+ } );
293
442
  } );
@@ -9,6 +9,7 @@ import {
9
9
  type TransformablePropType,
10
10
  } from '@elementor/editor-props';
11
11
 
12
+ import { type RenderContext } from '../legacy/types';
12
13
  import { type TransformersRegistry } from '../transformers/create-transformers-registry';
13
14
  import { getMultiPropsValue, isMultiProps } from './multi-props';
14
15
 
@@ -22,6 +23,7 @@ type ResolveArgs = {
22
23
  props: Props;
23
24
  schema?: PropsSchema;
24
25
  signal?: AbortSignal;
26
+ renderContext?: RenderContext;
25
27
  };
26
28
 
27
29
  type TransformArgs = {
@@ -30,6 +32,7 @@ type TransformArgs = {
30
32
  type: PropType;
31
33
  signal?: AbortSignal;
32
34
  depth?: number;
35
+ renderContext?: RenderContext;
33
36
  };
34
37
 
35
38
  type ResolvedProps = Record< string, unknown >;
@@ -39,14 +42,14 @@ export type PropsResolver = ReturnType< typeof createPropsResolver >;
39
42
  const TRANSFORM_DEPTH_LIMIT = 3;
40
43
 
41
44
  export function createPropsResolver( { transformers, schema: initialSchema, onPropResolve }: CreatePropResolverArgs ) {
42
- async function resolve( { props, schema, signal }: ResolveArgs ): Promise< ResolvedProps > {
45
+ async function resolve( { props, schema, signal, renderContext }: ResolveArgs ): Promise< ResolvedProps > {
43
46
  schema = schema ?? initialSchema;
44
47
 
45
48
  const promises = Promise.all(
46
49
  Object.entries( schema ).map( async ( [ key, type ] ) => {
47
50
  const value = props[ key ] ?? type.default;
48
51
 
49
- const transformed = ( await transform( { value, key, type, signal } ) ) as PropValue;
52
+ const transformed = ( await transform( { value, key, type, signal, renderContext } ) ) as PropValue;
50
53
 
51
54
  onPropResolve?.( { key, value: transformed } );
52
55
 
@@ -61,7 +64,7 @@ export function createPropsResolver( { transformers, schema: initialSchema, onPr
61
64
  return Object.assign( {}, ...( await promises ).filter( Boolean ) );
62
65
  }
63
66
 
64
- async function transform( { value, key, type, signal, depth = 0 }: TransformArgs ) {
67
+ async function transform( { value, key, type, signal, depth = 0, renderContext }: TransformArgs ) {
65
68
  if ( value === null || value === undefined ) {
66
69
  return null;
67
70
  }
@@ -108,13 +111,21 @@ export function createPropsResolver( { transformers, schema: initialSchema, onPr
108
111
  props: resolvedValue,
109
112
  schema: transformablePropType.shape,
110
113
  signal,
114
+ renderContext,
111
115
  } );
112
116
  }
113
117
 
114
118
  if ( transformablePropType.kind === 'array' ) {
115
119
  resolvedValue = await Promise.all(
116
120
  resolvedValue.map( ( item: PropValue ) =>
117
- transform( { value: item, key, type: transformablePropType.item_prop_type, depth, signal } )
121
+ transform( {
122
+ value: item,
123
+ key,
124
+ type: transformablePropType.item_prop_type,
125
+ depth,
126
+ signal,
127
+ renderContext,
128
+ } )
118
129
  )
119
130
  );
120
131
  }
@@ -126,9 +137,9 @@ export function createPropsResolver( { transformers, schema: initialSchema, onPr
126
137
  }
127
138
 
128
139
  try {
129
- const transformed = await transformer( resolvedValue, { key, signal } );
140
+ const transformed = await transformer( resolvedValue, { key, signal, renderContext } );
130
141
 
131
- return transform( { value: transformed, key, type, signal, depth: depth + 1 } );
142
+ return transform( { value: transformed, key, type, signal, depth: depth + 1, renderContext } );
132
143
  } catch {
133
144
  return null;
134
145
  }
@@ -1,10 +1,12 @@
1
- export type UnbrandedTransformer< TValue > = (
2
- value: TValue,
3
- options: {
4
- key: string;
5
- signal?: AbortSignal;
6
- }
7
- ) => unknown;
1
+ import { type RenderContext } from '../legacy/types';
2
+
3
+ export type TransformerOptions< TContext extends RenderContext = RenderContext > = {
4
+ key: string;
5
+ signal?: AbortSignal;
6
+ renderContext?: TContext;
7
+ };
8
+
9
+ export type UnbrandedTransformer< TValue > = ( value: TValue, options: TransformerOptions ) => unknown;
8
10
 
9
11
  export type Transformer< TValue > = UnbrandedTransformer< TValue > & {
10
12
  __transformer: true;
@@ -1,35 +0,0 @@
1
- export class RenderContext< TContext extends Record< string, unknown > > {
2
- private key: string;
3
- private context = new Map< string, TContext >();
4
-
5
- public constructor( key: string, initialContext: TContext ) {
6
- this.key = key;
7
- this.context.set( this.key, initialContext );
8
- }
9
-
10
- public get(): TContext {
11
- return this.context.get( this.key ) as TContext;
12
- }
13
-
14
- public set( context: TContext ) {
15
- this.context.set( this.key, context );
16
- }
17
-
18
- public update( updates: TContext ) {
19
- const currentContext = this.context.get( this.key );
20
-
21
- if ( ! currentContext ) {
22
- return this.set( updates );
23
- }
24
-
25
- this.context.set( this.key, { ...currentContext, ...updates } );
26
- }
27
-
28
- public delete() {
29
- this.context.delete( this.key );
30
- }
31
-
32
- public clear() {
33
- this.context.clear();
34
- }
35
- }