@elementor/editor-canvas 4.4.0-1134 → 4.4.0-1136

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.js CHANGED
@@ -1795,6 +1795,7 @@ var import_i18n = require("@wordpress/i18n");
1795
1795
  // src/form-structure/utils.ts
1796
1796
  var import_editor_elements4 = require("@elementor/editor-elements");
1797
1797
  var FORM_ELEMENT_TYPE = "e-form";
1798
+ var FORM_HIDDEN_FIELD_ELEMENT_TYPE = "e-form-hidden";
1798
1799
  var FORM_FIELD_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1799
1800
  "e-form-input",
1800
1801
  "e-form-textarea",
@@ -1805,7 +1806,8 @@ var FORM_FIELD_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1805
1806
  "e-form-radio-button",
1806
1807
  "e-form-file-upload",
1807
1808
  "e-form-date-picker",
1808
- "e-form-time-picker"
1809
+ "e-form-time-picker",
1810
+ FORM_HIDDEN_FIELD_ELEMENT_TYPE
1809
1811
  ]);
1810
1812
  function getArgsElementType(args) {
1811
1813
  return args.model?.widgetType || args.model?.elType;
@@ -1922,25 +1924,49 @@ function handleBlockedFormField() {
1922
1924
  (0, import_editor_notifications.notify)(FORM_FIELDS_OUTSIDE_ALERT);
1923
1925
  }
1924
1926
 
1925
- // src/form-structure/prevent-form-nesting-commands.ts
1927
+ // src/form-structure/hidden-field-hint.ts
1926
1928
  var import_editor_notifications2 = require("@elementor/editor-notifications");
1927
1929
  var import_editor_v1_adapters12 = require("@elementor/editor-v1-adapters");
1928
1930
  var import_i18n2 = require("@wordpress/i18n");
1931
+ var MOVE_COMMAND = "document/elements/move";
1932
+ var notificationCounter = 0;
1933
+ function createHiddenFieldNotification() {
1934
+ return {
1935
+ type: "default",
1936
+ message: (0, import_i18n2.__)("Hidden field added - invisible on your form. Manage it in the Structure panel.", "elementor"),
1937
+ id: `hidden-field-added-${++notificationCounter}`
1938
+ };
1939
+ }
1940
+ function initHiddenFieldHint() {
1941
+ (0, import_editor_v1_adapters12.registerDataHook)("after", "document/elements/create", (args, _result, options) => {
1942
+ if (options?.commandsCurrentTrace?.includes(MOVE_COMMAND)) {
1943
+ return;
1944
+ }
1945
+ if (getArgsElementType(args) === FORM_HIDDEN_FIELD_ELEMENT_TYPE) {
1946
+ (0, import_editor_notifications2.notify)(createHiddenFieldNotification());
1947
+ }
1948
+ });
1949
+ }
1950
+
1951
+ // src/form-structure/prevent-form-nesting-commands.ts
1952
+ var import_editor_notifications3 = require("@elementor/editor-notifications");
1953
+ var import_editor_v1_adapters13 = require("@elementor/editor-v1-adapters");
1954
+ var import_i18n3 = require("@wordpress/i18n");
1929
1955
  var FORM_NESTING_ALERT = {
1930
1956
  type: "default",
1931
- message: (0, import_i18n2.__)("Forms can't be nested. Create separate forms instead.", "elementor"),
1957
+ message: (0, import_i18n3.__)("Forms can't be nested. Create separate forms instead.", "elementor"),
1932
1958
  id: "form-nesting-blocked"
1933
1959
  };
1934
1960
  function initFormNestingPrevention() {
1935
- (0, import_editor_v1_adapters12.blockCommand)({
1961
+ (0, import_editor_v1_adapters13.blockCommand)({
1936
1962
  command: "document/elements/create",
1937
1963
  condition: blockFormCreate
1938
1964
  });
1939
- (0, import_editor_v1_adapters12.blockCommand)({
1965
+ (0, import_editor_v1_adapters13.blockCommand)({
1940
1966
  command: "document/elements/move",
1941
1967
  condition: blockFormMove
1942
1968
  });
1943
- (0, import_editor_v1_adapters12.blockCommand)({
1969
+ (0, import_editor_v1_adapters13.blockCommand)({
1944
1970
  command: "document/elements/paste",
1945
1971
  condition: blockFormPaste
1946
1972
  });
@@ -1984,7 +2010,7 @@ function blockFormPaste(args) {
1984
2010
  return false;
1985
2011
  }
1986
2012
  function handleBlockedFormField2() {
1987
- (0, import_editor_notifications2.notify)(FORM_NESTING_ALERT);
2013
+ (0, import_editor_notifications3.notify)(FORM_NESTING_ALERT);
1988
2014
  }
1989
2015
 
1990
2016
  // src/settings-transformers-registry.ts
@@ -2674,7 +2700,7 @@ function initStyleTransformers() {
2674
2700
 
2675
2701
  // src/legacy/init-legacy-views.ts
2676
2702
  var import_editor_elements8 = require("@elementor/editor-elements");
2677
- var import_editor_v1_adapters14 = require("@elementor/editor-v1-adapters");
2703
+ var import_editor_v1_adapters15 = require("@elementor/editor-v1-adapters");
2678
2704
 
2679
2705
  // src/renderers/create-dom-renderer.ts
2680
2706
  var import_twing = require("@elementor/twing");
@@ -3425,8 +3451,8 @@ var import_client = require("react-dom/client");
3425
3451
  var React11 = __toESM(require("react"));
3426
3452
  var import_editor_elements7 = require("@elementor/editor-elements");
3427
3453
  var import_editor_props4 = require("@elementor/editor-props");
3428
- var import_editor_v1_adapters13 = require("@elementor/editor-v1-adapters");
3429
- var import_i18n3 = require("@wordpress/i18n");
3454
+ var import_editor_v1_adapters14 = require("@elementor/editor-v1-adapters");
3455
+ var import_i18n4 = require("@wordpress/i18n");
3430
3456
 
3431
3457
  // src/legacy/replacements/base.ts
3432
3458
  var TRIGGER_TIMING = {
@@ -3743,7 +3769,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
3743
3769
  return this.editing;
3744
3770
  }
3745
3771
  shouldRenderReplacement() {
3746
- return this.isInlineEditingEligible() && (0, import_editor_v1_adapters13.getCurrentEditMode)() === "edit";
3772
+ return this.isInlineEditingEligible() && (0, import_editor_v1_adapters14.getCurrentEditMode)() === "edit";
3747
3773
  }
3748
3774
  handleRenderInlineEditor = () => {
3749
3775
  if (this.isEditingModeActive() || !this.isInlineEditingEligible()) {
@@ -3830,7 +3856,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
3830
3856
  setContentValue(value) {
3831
3857
  const settingKey = this.getInlineEditablePropertyName();
3832
3858
  const valueToSave = this.createContentPropValue(value);
3833
- (0, import_editor_v1_adapters13.undoable)(
3859
+ (0, import_editor_v1_adapters14.undoable)(
3834
3860
  {
3835
3861
  do: () => {
3836
3862
  const prevValue = this.getInlineEditablePropValue();
@@ -3844,7 +3870,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
3844
3870
  {
3845
3871
  title: (0, import_editor_elements7.getElementLabel)(this.id),
3846
3872
  // translators: %s is the name of the property that was edited.
3847
- subtitle: (0, import_i18n3.__)("%s edited", "elementor").replace(
3873
+ subtitle: (0, import_i18n4.__)("%s edited", "elementor").replace(
3848
3874
  "%s",
3849
3875
  this.getInlineEditablePropTypeKey() ?? "Inline editing"
3850
3876
  ),
@@ -3872,7 +3898,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
3872
3898
  return null;
3873
3899
  }
3874
3900
  runCommand(key, value) {
3875
- (0, import_editor_v1_adapters13.__privateRunCommandSync)(
3901
+ (0, import_editor_v1_adapters14.__privateRunCommandSync)(
3876
3902
  "document/elements/set-settings",
3877
3903
  {
3878
3904
  container: (0, import_editor_elements7.getContainer)(this.id),
@@ -3882,7 +3908,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
3882
3908
  },
3883
3909
  { internal: true }
3884
3910
  );
3885
- (0, import_editor_v1_adapters13.__privateRunCommandSync)("document/save/set-is-modified", { status: true }, { internal: true });
3911
+ (0, import_editor_v1_adapters14.__privateRunCommandSync)("document/save/set-is-modified", { status: true }, { internal: true });
3886
3912
  }
3887
3913
  getExpectedTag() {
3888
3914
  const tagPropType = this.getTagPropType();
@@ -4047,12 +4073,12 @@ function registerModelExtensions(type, extensions) {
4047
4073
  }
4048
4074
  function registerElementType(type, elementTypeGenerator) {
4049
4075
  elementsLegacyTypes[type] = elementTypeGenerator;
4050
- if ((0, import_editor_v1_adapters14.__privateIsReady)()) {
4076
+ if ((0, import_editor_v1_adapters15.__privateIsReady)()) {
4051
4077
  registerElementInLegacyManager(type, createDomRenderer());
4052
4078
  }
4053
4079
  }
4054
4080
  function initLegacyViews() {
4055
- (0, import_editor_v1_adapters14.__privateListenTo)((0, import_editor_v1_adapters14.v1ReadyEvent)(), () => {
4081
+ (0, import_editor_v1_adapters15.__privateListenTo)((0, import_editor_v1_adapters15.v1ReadyEvent)(), () => {
4056
4082
  const widgetsCache = (0, import_editor_elements8.getWidgetsCache)() ?? {};
4057
4083
  const renderer = createDomRenderer();
4058
4084
  registerProPromotionTypes(widgetsCache);
@@ -4190,9 +4216,9 @@ function initTabsModelExtensions() {
4190
4216
  var import_editor_props8 = require("@elementor/editor-props");
4191
4217
 
4192
4218
  // src/mcp/icon-library-experiment.ts
4193
- var import_editor_v1_adapters15 = require("@elementor/editor-v1-adapters");
4219
+ var import_editor_v1_adapters16 = require("@elementor/editor-v1-adapters");
4194
4220
  var ICON_LIBRARY_EXPERIMENT = "e_svg_library";
4195
- var isIconLibraryActive = () => (0, import_editor_v1_adapters15.isExperimentActive)(ICON_LIBRARY_EXPERIMENT);
4221
+ var isIconLibraryActive = () => (0, import_editor_v1_adapters16.isExperimentActive)(ICON_LIBRARY_EXPERIMENT);
4196
4222
 
4197
4223
  // src/mcp/resources/available-widgets-resource.ts
4198
4224
  var import_http_client3 = require("@elementor/http-client");
@@ -4270,7 +4296,7 @@ var initBestPracticesResource = (reg) => {
4270
4296
 
4271
4297
  // src/mcp/resources/document-structure-resource.ts
4272
4298
  var import_editor_elements9 = require("@elementor/editor-elements");
4273
- var import_editor_v1_adapters16 = require("@elementor/editor-v1-adapters");
4299
+ var import_editor_v1_adapters17 = require("@elementor/editor-v1-adapters");
4274
4300
  var DOCUMENT_STRUCTURE_URI = "elementor://document/structure";
4275
4301
  var initDocumentStructureResource = (reg) => {
4276
4302
  const { resource, sendResourceUpdated } = reg;
@@ -4283,15 +4309,15 @@ var initDocumentStructureResource = (reg) => {
4283
4309
  sendResourceUpdated({ uri: DOCUMENT_STRUCTURE_URI });
4284
4310
  }
4285
4311
  };
4286
- (0, import_editor_v1_adapters16.__privateListenTo)(
4312
+ (0, import_editor_v1_adapters17.__privateListenTo)(
4287
4313
  [
4288
- (0, import_editor_v1_adapters16.commandEndEvent)("document/elements/create"),
4289
- (0, import_editor_v1_adapters16.commandEndEvent)("document/elements/delete"),
4290
- (0, import_editor_v1_adapters16.commandEndEvent)("document/elements/move"),
4291
- (0, import_editor_v1_adapters16.commandEndEvent)("document/elements/copy"),
4292
- (0, import_editor_v1_adapters16.commandEndEvent)("document/elements/paste"),
4293
- (0, import_editor_v1_adapters16.commandEndEvent)("editor/documents/attach-preview"),
4294
- (0, import_editor_v1_adapters16.commandEndEvent)("editor/documents/switch")
4314
+ (0, import_editor_v1_adapters17.commandEndEvent)("document/elements/create"),
4315
+ (0, import_editor_v1_adapters17.commandEndEvent)("document/elements/delete"),
4316
+ (0, import_editor_v1_adapters17.commandEndEvent)("document/elements/move"),
4317
+ (0, import_editor_v1_adapters17.commandEndEvent)("document/elements/copy"),
4318
+ (0, import_editor_v1_adapters17.commandEndEvent)("document/elements/paste"),
4319
+ (0, import_editor_v1_adapters17.commandEndEvent)("editor/documents/attach-preview"),
4320
+ (0, import_editor_v1_adapters17.commandEndEvent)("editor/documents/switch")
4295
4321
  ],
4296
4322
  updateDocumentStructure
4297
4323
  );
@@ -4394,7 +4420,7 @@ var initDynamicTagsResource = (reg) => {
4394
4420
  };
4395
4421
 
4396
4422
  // src/mcp/resources/editor-state-resource.ts
4397
- var import_editor_v1_adapters17 = require("@elementor/editor-v1-adapters");
4423
+ var import_editor_v1_adapters18 = require("@elementor/editor-v1-adapters");
4398
4424
  var CURRENTLY_VIEWED_SCREEN = "The user is currently viewing the Elementor editor";
4399
4425
  var PAGE_CONTENT_CHARACTER_LIMIT = 500;
4400
4426
  var PREVIEW_TEXT_NODE_MIN_LENGTH = 2;
@@ -4415,8 +4441,8 @@ var initEditorStateResource = (reg) => {
4415
4441
  lastSerializedState = serialized;
4416
4442
  sendResourceUpdated({ uri: EDITOR_STATE_URI });
4417
4443
  };
4418
- (0, import_editor_v1_adapters17.__privateListenTo)(
4419
- [(0, import_editor_v1_adapters17.commandEndEvent)("editor/documents/switch"), (0, import_editor_v1_adapters17.commandEndEvent)("editor/documents/attach-preview")],
4444
+ (0, import_editor_v1_adapters18.__privateListenTo)(
4445
+ [(0, import_editor_v1_adapters18.commandEndEvent)("editor/documents/switch"), (0, import_editor_v1_adapters18.commandEndEvent)("editor/documents/attach-preview")],
4420
4446
  notifyIfChanged
4421
4447
  );
4422
4448
  lastSerializedState = JSON.stringify(buildState());
@@ -4490,7 +4516,7 @@ function getPageTitle() {
4490
4516
  }
4491
4517
 
4492
4518
  // src/mcp/resources/general-context-resource.ts
4493
- var import_editor_v1_adapters18 = require("@elementor/editor-v1-adapters");
4519
+ var import_editor_v1_adapters19 = require("@elementor/editor-v1-adapters");
4494
4520
  var GENERAL_CONTEXT_URI = "elementor://context/general";
4495
4521
  var initGeneralContextResource = (reg) => {
4496
4522
  const { resource, sendResourceUpdated } = reg;
@@ -4551,11 +4577,11 @@ var initGeneralContextResource = (reg) => {
4551
4577
  };
4552
4578
  }
4553
4579
  );
4554
- (0, import_editor_v1_adapters18.__privateListenTo)(
4580
+ (0, import_editor_v1_adapters19.__privateListenTo)(
4555
4581
  [
4556
- (0, import_editor_v1_adapters18.commandEndEvent)("editor/documents/switch"),
4557
- (0, import_editor_v1_adapters18.commandEndEvent)("editor/documents/attach-preview"),
4558
- (0, import_editor_v1_adapters18.commandEndEvent)("document/elements/settings")
4582
+ (0, import_editor_v1_adapters19.commandEndEvent)("editor/documents/switch"),
4583
+ (0, import_editor_v1_adapters19.commandEndEvent)("editor/documents/attach-preview"),
4584
+ (0, import_editor_v1_adapters19.commandEndEvent)("document/elements/settings")
4559
4585
  ],
4560
4586
  pushUpdateIfChanged
4561
4587
  );
@@ -4564,7 +4590,7 @@ var initGeneralContextResource = (reg) => {
4564
4590
 
4565
4591
  // src/mcp/resources/selected-element-resource.ts
4566
4592
  var import_editor_elements10 = require("@elementor/editor-elements");
4567
- var import_editor_v1_adapters19 = require("@elementor/editor-v1-adapters");
4593
+ var import_editor_v1_adapters20 = require("@elementor/editor-v1-adapters");
4568
4594
  var SELECTED_ELEMENT_URI = "elementor://context/selected-element";
4569
4595
  var initSelectedElementResource = (reg) => {
4570
4596
  const { resource, sendResourceUpdated } = reg;
@@ -4595,11 +4621,11 @@ var initSelectedElementResource = (reg) => {
4595
4621
  }
4596
4622
  publishIfChanged(readSelectionFromEditor());
4597
4623
  };
4598
- (0, import_editor_v1_adapters19.__privateListenTo)(
4624
+ (0, import_editor_v1_adapters20.__privateListenTo)(
4599
4625
  [
4600
- (0, import_editor_v1_adapters19.commandEndEvent)("document/elements/select"),
4601
- (0, import_editor_v1_adapters19.commandEndEvent)("document/elements/deselect-all"),
4602
- (0, import_editor_v1_adapters19.commandEndEvent)("document/elements/settings")
4626
+ (0, import_editor_v1_adapters20.commandEndEvent)("document/elements/select"),
4627
+ (0, import_editor_v1_adapters20.commandEndEvent)("document/elements/deselect-all"),
4628
+ (0, import_editor_v1_adapters20.commandEndEvent)("document/elements/settings")
4603
4629
  ],
4604
4630
  onCommand
4605
4631
  );
@@ -4717,7 +4743,7 @@ var import_editor_props7 = require("@elementor/editor-props");
4717
4743
  var import_editor_elements12 = require("@elementor/editor-elements");
4718
4744
  var import_editor_props6 = require("@elementor/editor-props");
4719
4745
  var import_editor_styles4 = require("@elementor/editor-styles");
4720
- var import_editor_v1_adapters21 = require("@elementor/editor-v1-adapters");
4746
+ var import_editor_v1_adapters22 = require("@elementor/editor-v1-adapters");
4721
4747
 
4722
4748
  // src/mcp/utils/merge-custom-css.ts
4723
4749
  var CUSTOM_CSS_SEPARATOR = "\n";
@@ -4786,11 +4812,11 @@ function resolveCanonicalPropKeys(elementType, props) {
4786
4812
  }
4787
4813
 
4788
4814
  // src/mcp/utils/resolve-dynamic-tag.ts
4789
- var import_editor_v1_adapters20 = require("@elementor/editor-v1-adapters");
4815
+ var import_editor_v1_adapters21 = require("@elementor/editor-v1-adapters");
4790
4816
  var DYNAMIC_PROP_TYPE_KEY = "dynamic";
4791
4817
  var OMITTED_DYNAMIC_SETTING_KEYS = ["fallback"];
4792
4818
  var getAtomicDynamicTags = () => {
4793
- const config = (0, import_editor_v1_adapters20.getElementorConfig)();
4819
+ const config = (0, import_editor_v1_adapters21.getElementorConfig)();
4794
4820
  return config.atomicDynamicTags?.tags ?? {};
4795
4821
  };
4796
4822
  var getDynamicTagNamesByCategories = (categories) => {
@@ -4991,7 +5017,7 @@ Expected Schema: ${jsonSchema}`
4991
5017
  },
4992
5018
  withHistory: false
4993
5019
  });
4994
- (0, import_editor_v1_adapters21.__privateRunCommandSync)("document/save/set-is-modified", { status: true }, { internal: true });
5020
+ (0, import_editor_v1_adapters22.__privateRunCommandSync)("document/save/set-is-modified", { status: true }, { internal: true });
4995
5021
  };
4996
5022
 
4997
5023
  // src/mcp/tools/configure-element/prompt.ts
@@ -5601,15 +5627,15 @@ Note: The "size" property controls image resolution/loading, not visual size. Se
5601
5627
 
5602
5628
  // src/prevent-link-in-link-commands.ts
5603
5629
  var import_editor_elements14 = require("@elementor/editor-elements");
5604
- var import_editor_notifications3 = require("@elementor/editor-notifications");
5605
- var import_editor_v1_adapters22 = require("@elementor/editor-v1-adapters");
5606
- var import_i18n4 = require("@wordpress/i18n");
5630
+ var import_editor_notifications4 = require("@elementor/editor-notifications");
5631
+ var import_editor_v1_adapters23 = require("@elementor/editor-v1-adapters");
5632
+ var import_i18n5 = require("@wordpress/i18n");
5607
5633
  function initLinkInLinkPrevention() {
5608
- (0, import_editor_v1_adapters22.blockCommand)({
5634
+ (0, import_editor_v1_adapters23.blockCommand)({
5609
5635
  command: "document/elements/paste",
5610
5636
  condition: blockLinkInLinkPaste
5611
5637
  });
5612
- (0, import_editor_v1_adapters22.blockCommand)({
5638
+ (0, import_editor_v1_adapters23.blockCommand)({
5613
5639
  command: "document/elements/move",
5614
5640
  condition: blockLinkInLinkMove
5615
5641
  });
@@ -5637,7 +5663,7 @@ function blockLinkInLinkPaste(args) {
5637
5663
  const sourceElements = data.clipboard.elements;
5638
5664
  const notification = {
5639
5665
  type: "default",
5640
- message: (0, import_i18n4.__)(
5666
+ message: (0, import_i18n5.__)(
5641
5667
  "To paste a link to this element, first remove the link from it's parent container.",
5642
5668
  "elementor"
5643
5669
  ),
@@ -5646,7 +5672,7 @@ function blockLinkInLinkPaste(args) {
5646
5672
  };
5647
5673
  const blocked = shouldBlock(sourceElements, targetElements);
5648
5674
  if (blocked) {
5649
- (0, import_editor_notifications3.notify)(notification);
5675
+ (0, import_editor_notifications4.notify)(notification);
5650
5676
  }
5651
5677
  return blocked;
5652
5678
  }
@@ -5656,13 +5682,13 @@ function blockLinkInLinkMove(args) {
5656
5682
  const targetElement = target;
5657
5683
  const notification = {
5658
5684
  type: "default",
5659
- message: (0, import_i18n4.__)("To drag a link to this element, first remove the link from it's parent container.", "elementor"),
5685
+ message: (0, import_i18n5.__)("To drag a link to this element, first remove the link from it's parent container.", "elementor"),
5660
5686
  id: "move-in-link-blocked",
5661
5687
  additionalActionProps: [learnMoreActionProps]
5662
5688
  };
5663
5689
  const isBlocked = shouldBlock(sourceElements, [targetElement]);
5664
5690
  if (isBlocked) {
5665
- (0, import_editor_notifications3.notify)(notification);
5691
+ (0, import_editor_notifications4.notify)(notification);
5666
5692
  }
5667
5693
  return isBlocked;
5668
5694
  }
@@ -5685,12 +5711,12 @@ function shouldBlock(sourceElements, targetElements) {
5685
5711
  // src/style-commands/paste-style.ts
5686
5712
  var import_editor_elements17 = require("@elementor/editor-elements");
5687
5713
  var import_editor_props10 = require("@elementor/editor-props");
5688
- var import_editor_v1_adapters24 = require("@elementor/editor-v1-adapters");
5714
+ var import_editor_v1_adapters25 = require("@elementor/editor-v1-adapters");
5689
5715
 
5690
5716
  // src/utils/command-utils.ts
5691
5717
  var import_editor_elements15 = require("@elementor/editor-elements");
5692
5718
  var import_editor_props9 = require("@elementor/editor-props");
5693
- var import_i18n5 = require("@wordpress/i18n");
5719
+ var import_i18n6 = require("@wordpress/i18n");
5694
5720
  function hasAtomicWidgets(args) {
5695
5721
  const { containers = [args.container] } = args;
5696
5722
  return containers.some(isAtomicWidget);
@@ -5726,15 +5752,15 @@ function getClipboardElements(storageKey = "clipboard") {
5726
5752
  }
5727
5753
  }
5728
5754
  function getTitleForContainers(containers) {
5729
- return containers.length > 1 ? (0, import_i18n5.__)("Elements", "elementor") : (0, import_editor_elements15.getElementLabel)(containers[0].id);
5755
+ return containers.length > 1 ? (0, import_i18n6.__)("Elements", "elementor") : (0, import_editor_elements15.getElementLabel)(containers[0].id);
5730
5756
  }
5731
5757
 
5732
5758
  // src/style-commands/undoable-actions/paste-element-style.ts
5733
5759
  var import_editor_elements16 = require("@elementor/editor-elements");
5734
5760
  var import_editor_styles_repository4 = require("@elementor/editor-styles-repository");
5735
- var import_editor_v1_adapters23 = require("@elementor/editor-v1-adapters");
5736
- var import_i18n6 = require("@wordpress/i18n");
5737
- var undoablePasteElementStyle = () => (0, import_editor_v1_adapters23.undoable)(
5761
+ var import_editor_v1_adapters24 = require("@elementor/editor-v1-adapters");
5762
+ var import_i18n7 = require("@wordpress/i18n");
5763
+ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters24.undoable)(
5738
5764
  {
5739
5765
  do: ({ containers, newStyle }) => {
5740
5766
  return containers.map((container) => {
@@ -5803,19 +5829,19 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters23.undoable)(
5803
5829
  },
5804
5830
  {
5805
5831
  title: ({ containers }) => getTitleForContainers(containers),
5806
- subtitle: (0, import_i18n6.__)("Style Pasted", "elementor")
5832
+ subtitle: (0, import_i18n7.__)("Style Pasted", "elementor")
5807
5833
  }
5808
5834
  );
5809
5835
 
5810
5836
  // src/style-commands/paste-style.ts
5811
5837
  function initPasteStyleCommand() {
5812
5838
  const pasteElementStyleCommand = undoablePasteElementStyle();
5813
- (0, import_editor_v1_adapters24.blockCommand)({
5839
+ (0, import_editor_v1_adapters25.blockCommand)({
5814
5840
  command: "document/elements/paste-style",
5815
5841
  condition: hasAtomicWidgets
5816
5842
  });
5817
- (0, import_editor_v1_adapters24.__privateListenTo)(
5818
- (0, import_editor_v1_adapters24.commandStartEvent)("document/elements/paste-style"),
5843
+ (0, import_editor_v1_adapters25.__privateListenTo)(
5844
+ (0, import_editor_v1_adapters25.commandStartEvent)("document/elements/paste-style"),
5819
5845
  (e) => pasteStyles(e.args, pasteElementStyleCommand)
5820
5846
  );
5821
5847
  }
@@ -5866,14 +5892,14 @@ function pasteClasses(containers, classes) {
5866
5892
  }
5867
5893
 
5868
5894
  // src/style-commands/reset-style.ts
5869
- var import_editor_v1_adapters26 = require("@elementor/editor-v1-adapters");
5895
+ var import_editor_v1_adapters27 = require("@elementor/editor-v1-adapters");
5870
5896
 
5871
5897
  // src/style-commands/undoable-actions/reset-element-style.ts
5872
5898
  var import_editor_elements18 = require("@elementor/editor-elements");
5873
5899
  var import_editor_styles_repository5 = require("@elementor/editor-styles-repository");
5874
- var import_editor_v1_adapters25 = require("@elementor/editor-v1-adapters");
5875
- var import_i18n7 = require("@wordpress/i18n");
5876
- var undoableResetElementStyle = () => (0, import_editor_v1_adapters25.undoable)(
5900
+ var import_editor_v1_adapters26 = require("@elementor/editor-v1-adapters");
5901
+ var import_i18n8 = require("@wordpress/i18n");
5902
+ var undoableResetElementStyle = () => (0, import_editor_v1_adapters26.undoable)(
5877
5903
  {
5878
5904
  do: ({ containers }) => {
5879
5905
  return containers.map((container) => {
@@ -5910,19 +5936,19 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters25.undoable)(
5910
5936
  },
5911
5937
  {
5912
5938
  title: ({ containers }) => getTitleForContainers(containers),
5913
- subtitle: (0, import_i18n7.__)("Style Reset", "elementor")
5939
+ subtitle: (0, import_i18n8.__)("Style Reset", "elementor")
5914
5940
  }
5915
5941
  );
5916
5942
 
5917
5943
  // src/style-commands/reset-style.ts
5918
5944
  function initResetStyleCommand() {
5919
5945
  const resetElementStyles = undoableResetElementStyle();
5920
- (0, import_editor_v1_adapters26.blockCommand)({
5946
+ (0, import_editor_v1_adapters27.blockCommand)({
5921
5947
  command: "document/elements/reset-style",
5922
5948
  condition: hasAtomicWidgets
5923
5949
  });
5924
- (0, import_editor_v1_adapters26.__privateListenTo)(
5925
- (0, import_editor_v1_adapters26.commandStartEvent)("document/elements/reset-style"),
5950
+ (0, import_editor_v1_adapters27.__privateListenTo)(
5951
+ (0, import_editor_v1_adapters27.commandStartEvent)("document/elements/reset-style"),
5926
5952
  (e) => resetStyles(e.args, resetElementStyles)
5927
5953
  );
5928
5954
  }
@@ -5948,6 +5974,7 @@ function init() {
5948
5974
  initLinkInLinkPrevention();
5949
5975
  initFormNestingPrevention();
5950
5976
  initFormAncestorEnforcement();
5977
+ initHiddenFieldHint();
5951
5978
  initViewReplacements();
5952
5979
  initLegacyViews();
5953
5980
  initSettingsTransformers();
@@ -6071,9 +6098,9 @@ function getRectClipPath(rect, viewport) {
6071
6098
  }
6072
6099
 
6073
6100
  // src/hooks/use-canvas-document.ts
6074
- var import_editor_v1_adapters27 = require("@elementor/editor-v1-adapters");
6101
+ var import_editor_v1_adapters28 = require("@elementor/editor-v1-adapters");
6075
6102
  function useCanvasDocument() {
6076
- return (0, import_editor_v1_adapters27.__privateUseListenTo)((0, import_editor_v1_adapters27.commandEndEvent)("editor/documents/attach-preview"), () => (0, import_editor_v1_adapters27.getCanvasIframeDocument)());
6103
+ return (0, import_editor_v1_adapters28.__privateUseListenTo)((0, import_editor_v1_adapters28.commandEndEvent)("editor/documents/attach-preview"), () => (0, import_editor_v1_adapters28.getCanvasIframeDocument)());
6077
6104
  }
6078
6105
 
6079
6106
  // src/hooks/use-escape-on-canvas.ts
package/dist/index.mjs CHANGED
@@ -1747,6 +1747,7 @@ import { __ } from "@wordpress/i18n";
1747
1747
  // src/form-structure/utils.ts
1748
1748
  import { getAllDescendants } from "@elementor/editor-elements";
1749
1749
  var FORM_ELEMENT_TYPE = "e-form";
1750
+ var FORM_HIDDEN_FIELD_ELEMENT_TYPE = "e-form-hidden";
1750
1751
  var FORM_FIELD_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1751
1752
  "e-form-input",
1752
1753
  "e-form-textarea",
@@ -1757,7 +1758,8 @@ var FORM_FIELD_ELEMENT_TYPES = /* @__PURE__ */ new Set([
1757
1758
  "e-form-radio-button",
1758
1759
  "e-form-file-upload",
1759
1760
  "e-form-date-picker",
1760
- "e-form-time-picker"
1761
+ "e-form-time-picker",
1762
+ FORM_HIDDEN_FIELD_ELEMENT_TYPE
1761
1763
  ]);
1762
1764
  function getArgsElementType(args) {
1763
1765
  return args.model?.widgetType || args.model?.elType;
@@ -1874,13 +1876,37 @@ function handleBlockedFormField() {
1874
1876
  notify(FORM_FIELDS_OUTSIDE_ALERT);
1875
1877
  }
1876
1878
 
1877
- // src/form-structure/prevent-form-nesting-commands.ts
1879
+ // src/form-structure/hidden-field-hint.ts
1878
1880
  import { notify as notify2 } from "@elementor/editor-notifications";
1879
- import { blockCommand as blockCommand2 } from "@elementor/editor-v1-adapters";
1881
+ import { registerDataHook as registerDataHook3 } from "@elementor/editor-v1-adapters";
1880
1882
  import { __ as __2 } from "@wordpress/i18n";
1883
+ var MOVE_COMMAND = "document/elements/move";
1884
+ var notificationCounter = 0;
1885
+ function createHiddenFieldNotification() {
1886
+ return {
1887
+ type: "default",
1888
+ message: __2("Hidden field added - invisible on your form. Manage it in the Structure panel.", "elementor"),
1889
+ id: `hidden-field-added-${++notificationCounter}`
1890
+ };
1891
+ }
1892
+ function initHiddenFieldHint() {
1893
+ registerDataHook3("after", "document/elements/create", (args, _result, options) => {
1894
+ if (options?.commandsCurrentTrace?.includes(MOVE_COMMAND)) {
1895
+ return;
1896
+ }
1897
+ if (getArgsElementType(args) === FORM_HIDDEN_FIELD_ELEMENT_TYPE) {
1898
+ notify2(createHiddenFieldNotification());
1899
+ }
1900
+ });
1901
+ }
1902
+
1903
+ // src/form-structure/prevent-form-nesting-commands.ts
1904
+ import { notify as notify3 } from "@elementor/editor-notifications";
1905
+ import { blockCommand as blockCommand2 } from "@elementor/editor-v1-adapters";
1906
+ import { __ as __3 } from "@wordpress/i18n";
1881
1907
  var FORM_NESTING_ALERT = {
1882
1908
  type: "default",
1883
- message: __2("Forms can't be nested. Create separate forms instead.", "elementor"),
1909
+ message: __3("Forms can't be nested. Create separate forms instead.", "elementor"),
1884
1910
  id: "form-nesting-blocked"
1885
1911
  };
1886
1912
  function initFormNestingPrevention() {
@@ -1936,7 +1962,7 @@ function blockFormPaste(args) {
1936
1962
  return false;
1937
1963
  }
1938
1964
  function handleBlockedFormField2() {
1939
- notify2(FORM_NESTING_ALERT);
1965
+ notify3(FORM_NESTING_ALERT);
1940
1966
  }
1941
1967
 
1942
1968
  // src/settings-transformers-registry.ts
@@ -3393,7 +3419,7 @@ import {
3393
3419
  stringPropTypeUtil as stringPropTypeUtil2
3394
3420
  } from "@elementor/editor-props";
3395
3421
  import { __privateRunCommandSync as runCommandSync, getCurrentEditMode, undoable } from "@elementor/editor-v1-adapters";
3396
- import { __ as __3 } from "@wordpress/i18n";
3422
+ import { __ as __4 } from "@wordpress/i18n";
3397
3423
 
3398
3424
  // src/legacy/replacements/base.ts
3399
3425
  var TRIGGER_TIMING = {
@@ -3815,7 +3841,7 @@ var InlineEditingReplacement = class extends ReplacementBase {
3815
3841
  {
3816
3842
  title: getElementLabel(this.id),
3817
3843
  // translators: %s is the name of the property that was edited.
3818
- subtitle: __3("%s edited", "elementor").replace(
3844
+ subtitle: __4("%s edited", "elementor").replace(
3819
3845
  "%s",
3820
3846
  this.getInlineEditablePropTypeKey() ?? "Inline editing"
3821
3847
  ),
@@ -5587,9 +5613,9 @@ import {
5587
5613
  getAnchoredDescendantId,
5588
5614
  isElementAnchored
5589
5615
  } from "@elementor/editor-elements";
5590
- import { notify as notify3 } from "@elementor/editor-notifications";
5616
+ import { notify as notify4 } from "@elementor/editor-notifications";
5591
5617
  import { blockCommand as blockCommand3 } from "@elementor/editor-v1-adapters";
5592
- import { __ as __4 } from "@wordpress/i18n";
5618
+ import { __ as __5 } from "@wordpress/i18n";
5593
5619
  function initLinkInLinkPrevention() {
5594
5620
  blockCommand3({
5595
5621
  command: "document/elements/paste",
@@ -5623,7 +5649,7 @@ function blockLinkInLinkPaste(args) {
5623
5649
  const sourceElements = data.clipboard.elements;
5624
5650
  const notification = {
5625
5651
  type: "default",
5626
- message: __4(
5652
+ message: __5(
5627
5653
  "To paste a link to this element, first remove the link from it's parent container.",
5628
5654
  "elementor"
5629
5655
  ),
@@ -5632,7 +5658,7 @@ function blockLinkInLinkPaste(args) {
5632
5658
  };
5633
5659
  const blocked = shouldBlock(sourceElements, targetElements);
5634
5660
  if (blocked) {
5635
- notify3(notification);
5661
+ notify4(notification);
5636
5662
  }
5637
5663
  return blocked;
5638
5664
  }
@@ -5642,13 +5668,13 @@ function blockLinkInLinkMove(args) {
5642
5668
  const targetElement = target;
5643
5669
  const notification = {
5644
5670
  type: "default",
5645
- message: __4("To drag a link to this element, first remove the link from it's parent container.", "elementor"),
5671
+ message: __5("To drag a link to this element, first remove the link from it's parent container.", "elementor"),
5646
5672
  id: "move-in-link-blocked",
5647
5673
  additionalActionProps: [learnMoreActionProps]
5648
5674
  };
5649
5675
  const isBlocked = shouldBlock(sourceElements, [targetElement]);
5650
5676
  if (isBlocked) {
5651
- notify3(notification);
5677
+ notify4(notification);
5652
5678
  }
5653
5679
  return isBlocked;
5654
5680
  }
@@ -5680,7 +5706,7 @@ import {
5680
5706
  // src/utils/command-utils.ts
5681
5707
  import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
5682
5708
  import { CLASSES_PROP_KEY } from "@elementor/editor-props";
5683
- import { __ as __5 } from "@wordpress/i18n";
5709
+ import { __ as __6 } from "@wordpress/i18n";
5684
5710
  function hasAtomicWidgets(args) {
5685
5711
  const { containers = [args.container] } = args;
5686
5712
  return containers.some(isAtomicWidget);
@@ -5716,7 +5742,7 @@ function getClipboardElements(storageKey = "clipboard") {
5716
5742
  }
5717
5743
  }
5718
5744
  function getTitleForContainers(containers) {
5719
- return containers.length > 1 ? __5("Elements", "elementor") : getElementLabel2(containers[0].id);
5745
+ return containers.length > 1 ? __6("Elements", "elementor") : getElementLabel2(containers[0].id);
5720
5746
  }
5721
5747
 
5722
5748
  // src/style-commands/undoable-actions/paste-element-style.ts
@@ -5728,7 +5754,7 @@ import {
5728
5754
  } from "@elementor/editor-elements";
5729
5755
  import { ELEMENTS_STYLES_RESERVED_LABEL } from "@elementor/editor-styles-repository";
5730
5756
  import { undoable as undoable2 } from "@elementor/editor-v1-adapters";
5731
- import { __ as __6 } from "@wordpress/i18n";
5757
+ import { __ as __7 } from "@wordpress/i18n";
5732
5758
  var undoablePasteElementStyle = () => undoable2(
5733
5759
  {
5734
5760
  do: ({ containers, newStyle }) => {
@@ -5798,7 +5824,7 @@ var undoablePasteElementStyle = () => undoable2(
5798
5824
  },
5799
5825
  {
5800
5826
  title: ({ containers }) => getTitleForContainers(containers),
5801
- subtitle: __6("Style Pasted", "elementor")
5827
+ subtitle: __7("Style Pasted", "elementor")
5802
5828
  }
5803
5829
  );
5804
5830
 
@@ -5871,7 +5897,7 @@ import {
5871
5897
  import { createElementStyle as createElementStyle3, deleteElementStyle as deleteElementStyle2, getElementStyles as getElementStyles3 } from "@elementor/editor-elements";
5872
5898
  import { ELEMENTS_STYLES_RESERVED_LABEL as ELEMENTS_STYLES_RESERVED_LABEL2 } from "@elementor/editor-styles-repository";
5873
5899
  import { undoable as undoable3 } from "@elementor/editor-v1-adapters";
5874
- import { __ as __7 } from "@wordpress/i18n";
5900
+ import { __ as __8 } from "@wordpress/i18n";
5875
5901
  var undoableResetElementStyle = () => undoable3(
5876
5902
  {
5877
5903
  do: ({ containers }) => {
@@ -5909,7 +5935,7 @@ var undoableResetElementStyle = () => undoable3(
5909
5935
  },
5910
5936
  {
5911
5937
  title: ({ containers }) => getTitleForContainers(containers),
5912
- subtitle: __7("Style Reset", "elementor")
5938
+ subtitle: __8("Style Reset", "elementor")
5913
5939
  }
5914
5940
  );
5915
5941
 
@@ -5947,6 +5973,7 @@ function init() {
5947
5973
  initLinkInLinkPrevention();
5948
5974
  initFormNestingPrevention();
5949
5975
  initFormAncestorEnforcement();
5976
+ initHiddenFieldHint();
5950
5977
  initViewReplacements();
5951
5978
  initLegacyViews();
5952
5979
  initSettingsTransformers();
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.4.0-1134",
4
+ "version": "4.4.0-1136",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,26 +37,26 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.4.0-1134",
41
- "@elementor/editor-controls": "4.4.0-1134",
42
- "@elementor/editor-documents": "4.4.0-1134",
43
- "@elementor/editor-elements": "4.4.0-1134",
44
- "@elementor/editor-interactions": "4.4.0-1134",
45
- "@elementor/editor-mcp": "4.4.0-1134",
46
- "@elementor/editor-notifications": "4.4.0-1134",
47
- "@elementor/editor-props": "4.4.0-1134",
48
- "@elementor/editor-responsive": "4.4.0-1134",
49
- "@elementor/editor-styles": "4.4.0-1134",
50
- "@elementor/editor-styles-repository": "4.4.0-1134",
51
- "@elementor/editor-ui": "4.4.0-1134",
52
- "@elementor/editor-v1-adapters": "4.4.0-1134",
53
- "@elementor/events": "4.4.0-1134",
54
- "@elementor/http-client": "4.4.0-1134",
55
- "@elementor/schema": "4.4.0-1134",
56
- "@elementor/twing": "4.4.0-1134",
57
- "@elementor/ui": "1.41.2",
58
- "@elementor/utils": "4.4.0-1134",
59
- "@elementor/wp-media": "4.4.0-1134",
40
+ "@elementor/editor": "4.4.0-1136",
41
+ "@elementor/editor-controls": "4.4.0-1136",
42
+ "@elementor/editor-documents": "4.4.0-1136",
43
+ "@elementor/editor-elements": "4.4.0-1136",
44
+ "@elementor/editor-interactions": "4.4.0-1136",
45
+ "@elementor/editor-mcp": "4.4.0-1136",
46
+ "@elementor/editor-notifications": "4.4.0-1136",
47
+ "@elementor/editor-props": "4.4.0-1136",
48
+ "@elementor/editor-responsive": "4.4.0-1136",
49
+ "@elementor/editor-styles": "4.4.0-1136",
50
+ "@elementor/editor-styles-repository": "4.4.0-1136",
51
+ "@elementor/editor-ui": "4.4.0-1136",
52
+ "@elementor/editor-v1-adapters": "4.4.0-1136",
53
+ "@elementor/events": "4.4.0-1136",
54
+ "@elementor/http-client": "4.4.0-1136",
55
+ "@elementor/schema": "4.4.0-1136",
56
+ "@elementor/twing": "4.4.0-1136",
57
+ "@elementor/ui": "1.41.3",
58
+ "@elementor/utils": "4.4.0-1136",
59
+ "@elementor/wp-media": "4.4.0-1136",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0",
62
62
  "dompurify": "^3.2.6"
@@ -114,6 +114,16 @@ describe( 'form-structure utils', () => {
114
114
  expect( errors[ 0 ] ).toContain( 'e-form-input' );
115
115
  expect( errors[ 0 ] ).toContain( 'e-form' );
116
116
  } );
117
+ it( 'returns an error when a hidden field has no e-form ancestor (invalid)', () => {
118
+ const xml = parseXml( `
119
+ <e-flexbox>
120
+ <e-form-hidden />
121
+ </e-flexbox>
122
+ ` );
123
+ const errors = collectFormAncestorErrors( xml );
124
+ expect( errors ).toHaveLength( 1 );
125
+ expect( errors[ 0 ] ).toContain( 'e-form-hidden' );
126
+ } );
117
127
  it( 'returns an error for each orphaned form field', () => {
118
128
  const xml = parseXml( `
119
129
  <e-flexbox>
@@ -0,0 +1,137 @@
1
+ import { createHooksRegistry, setupHooksRegistry } from 'test-utils';
2
+ import { notify } from '@elementor/editor-notifications';
3
+
4
+ import { initHiddenFieldHint } from '../hidden-field-hint';
5
+
6
+ jest.mock( '@elementor/editor-notifications', () => ( {
7
+ notify: jest.fn(),
8
+ } ) );
9
+
10
+ const CREATE_COMMAND = 'document/elements/create';
11
+ const MOVE_COMMAND = 'document/elements/move';
12
+ const HIDDEN_FIELD_TYPE = 'e-form-hidden';
13
+
14
+ describe( 'hidden field hint', () => {
15
+ const hooksRegistry = createHooksRegistry();
16
+
17
+ beforeEach( () => {
18
+ jest.mocked( notify ).mockClear();
19
+ setupHooksRegistry( hooksRegistry );
20
+ initHiddenFieldHint();
21
+ } );
22
+
23
+ it( 'should notify when a hidden field is added', () => {
24
+ // Arrange
25
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
26
+
27
+ // Act
28
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
29
+
30
+ // Assert
31
+ expect( notify ).toHaveBeenCalledWith(
32
+ expect.objectContaining( {
33
+ message: 'Hidden field added - invisible on your form. Manage it in the Structure panel.',
34
+ } )
35
+ );
36
+ } );
37
+
38
+ it( 'should use unique notification ids for back-to-back adds (not collapsed by the notification system)', () => {
39
+ // Arrange
40
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
41
+
42
+ // Act
43
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
44
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
45
+
46
+ // Assert
47
+ expect( notify ).toHaveBeenCalledTimes( 2 );
48
+ const firstCallId = jest.mocked( notify ).mock.calls[ 0 ][ 0 ].id;
49
+ const secondCallId = jest.mocked( notify ).mock.calls[ 1 ][ 0 ].id;
50
+ expect( firstCallId ).not.toBe( secondCallId );
51
+ } );
52
+
53
+ it( 'should notify again after remove and re-add (simulated by separate create calls)', () => {
54
+ // Arrange
55
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
56
+
57
+ // Act - first add
58
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
59
+
60
+ // simulate removal (no hook for delete affects this)
61
+
62
+ // Act - re-add
63
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
64
+
65
+ // Assert
66
+ expect( notify ).toHaveBeenCalledTimes( 2 );
67
+ } );
68
+
69
+ it( 'should not notify when another element type is created', () => {
70
+ // Arrange
71
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
72
+
73
+ // Act
74
+ hook?.apply( { model: { widgetType: 'e-form-input' } } );
75
+
76
+ // Assert
77
+ expect( notify ).not.toHaveBeenCalled();
78
+ } );
79
+
80
+ it( 'should not notify when the hidden field is created as part of a move', () => {
81
+ // Arrange
82
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
83
+ const eWindow = window as unknown as { $e: { commands?: { currentTrace?: string[] } } };
84
+ eWindow.$e.commands = { currentTrace: [ MOVE_COMMAND, CREATE_COMMAND ] };
85
+
86
+ // Act
87
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
88
+
89
+ // Assert
90
+ expect( notify ).not.toHaveBeenCalled();
91
+ } );
92
+
93
+ it( 'should not notify on selection (selection does not trigger create command)', () => {
94
+ // Arrange - selection uses a different command path, not document/elements/create
95
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
96
+
97
+ // Act - no create call is made for selection
98
+ // Selection triggers commands like document/elements/toggle-selection, not create
99
+
100
+ // Assert
101
+ expect( hook ).toBeDefined();
102
+ expect( notify ).not.toHaveBeenCalled();
103
+ } );
104
+
105
+ it( 'should notify on paste when it triggers create (current behavior: paste triggers toast)', () => {
106
+ // Arrange
107
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
108
+
109
+ // Act - paste internally calls create, so it will trigger the notification
110
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
111
+
112
+ // Assert
113
+ expect( notify ).toHaveBeenCalledTimes( 1 );
114
+ } );
115
+
116
+ it( 'should notify on duplicate when it triggers create (current behavior: duplicate triggers toast)', () => {
117
+ // Arrange
118
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
119
+
120
+ // Act - duplicate internally calls create, so it will trigger the notification
121
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
122
+
123
+ // Assert
124
+ expect( notify ).toHaveBeenCalledTimes( 1 );
125
+ } );
126
+
127
+ it( 'should notify on undo of delete (undo-delete triggers create, so toast shows)', () => {
128
+ // Arrange
129
+ const hook = hooksRegistry.getByCommand( CREATE_COMMAND );
130
+
131
+ // Act - undo of a delete restores via create command
132
+ hook?.apply( { model: { widgetType: HIDDEN_FIELD_TYPE } } );
133
+
134
+ // Assert
135
+ expect( notify ).toHaveBeenCalledTimes( 1 );
136
+ } );
137
+ } );
@@ -0,0 +1,29 @@
1
+ import { type NotificationData, notify } from '@elementor/editor-notifications';
2
+ import { type HookOptions, registerDataHook } from '@elementor/editor-v1-adapters';
3
+ import { __ } from '@wordpress/i18n';
4
+
5
+ import { type CreateArgs, FORM_HIDDEN_FIELD_ELEMENT_TYPE, getArgsElementType } from './utils';
6
+
7
+ const MOVE_COMMAND = 'document/elements/move';
8
+
9
+ let notificationCounter = 0;
10
+
11
+ function createHiddenFieldNotification(): NotificationData {
12
+ return {
13
+ type: 'default',
14
+ message: __( 'Hidden field added - invisible on your form. Manage it in the Structure panel.', 'elementor' ),
15
+ id: `hidden-field-added-${ ++notificationCounter }`,
16
+ };
17
+ }
18
+
19
+ export function initHiddenFieldHint() {
20
+ registerDataHook( 'after', 'document/elements/create', ( args: CreateArgs, _result, options?: HookOptions ) => {
21
+ if ( options?.commandsCurrentTrace?.includes( MOVE_COMMAND ) ) {
22
+ return;
23
+ }
24
+
25
+ if ( getArgsElementType( args ) === FORM_HIDDEN_FIELD_ELEMENT_TYPE ) {
26
+ notify( createHiddenFieldNotification() );
27
+ }
28
+ } );
29
+ }
@@ -35,6 +35,7 @@ export type StorageContent = {
35
35
  };
36
36
 
37
37
  export const FORM_ELEMENT_TYPE = 'e-form';
38
+ export const FORM_HIDDEN_FIELD_ELEMENT_TYPE = 'e-form-hidden';
38
39
  export const FORM_FIELD_ELEMENT_TYPES = new Set( [
39
40
  'e-form-input',
40
41
  'e-form-textarea',
@@ -46,6 +47,7 @@ export const FORM_FIELD_ELEMENT_TYPES = new Set( [
46
47
  'e-form-file-upload',
47
48
  'e-form-date-picker',
48
49
  'e-form-time-picker',
50
+ FORM_HIDDEN_FIELD_ELEMENT_TYPE,
49
51
  ] );
50
52
 
51
53
  export function getArgsElementType( args: CreateArgs ): string | undefined {
package/src/init.tsx CHANGED
@@ -6,6 +6,7 @@ import { ElementsOverlays } from './components/elements-overlays';
6
6
  import { InteractionsRenderer } from './components/interactions-renderer';
7
7
  import { StyleRenderer } from './components/style-renderer';
8
8
  import { initFormAncestorEnforcement } from './form-structure/enforce-form-ancestor-commands';
9
+ import { initHiddenFieldHint } from './form-structure/hidden-field-hint';
9
10
  import { initFormNestingPrevention } from './form-structure/prevent-form-nesting-commands';
10
11
  import { initSettingsTransformers } from './init-settings-transformers';
11
12
  import { initStyleTransformers } from './init-style-transformers';
@@ -25,6 +26,7 @@ export function init() {
25
26
  initLinkInLinkPrevention();
26
27
  initFormNestingPrevention();
27
28
  initFormAncestorEnforcement();
29
+ initHiddenFieldHint();
28
30
 
29
31
  initViewReplacements();
30
32