@jsenv/navi 0.9.3 → 0.10.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.
@@ -520,22 +520,26 @@ const createPubSub = (clearOnPublish = false) => {
520
520
 
521
521
  const createValueEffect = (value) => {
522
522
  const callbackSet = new Set();
523
- const previousValueCleanupSet = new Set();
523
+ const valueCleanupSet = new Set();
524
+
525
+ const cleanup = () => {
526
+ for (const valueCleanup of valueCleanupSet) {
527
+ valueCleanup();
528
+ }
529
+ valueCleanupSet.clear();
530
+ };
524
531
 
525
532
  const updateValue = (newValue) => {
526
533
  if (newValue === value) {
527
534
  return;
528
535
  }
529
- for (const cleanup of previousValueCleanupSet) {
530
- cleanup();
531
- }
532
- previousValueCleanupSet.clear();
536
+ cleanup();
533
537
  const oldValue = value;
534
538
  value = newValue;
535
539
  for (const callback of callbackSet) {
536
540
  const returnValue = callback(newValue, oldValue);
537
541
  if (typeof returnValue === "function") {
538
- previousValueCleanupSet.add(returnValue);
542
+ valueCleanupSet.add(returnValue);
539
543
  }
540
544
  }
541
545
  };
@@ -547,7 +551,7 @@ const createValueEffect = (value) => {
547
551
  };
548
552
  };
549
553
 
550
- return [updateValue, addEffect];
554
+ return [updateValue, addEffect, cleanup];
551
555
  };
552
556
 
553
557
  // https://github.com/davidtheclark/tabbable/blob/master/index.js
@@ -11840,7 +11844,9 @@ const openCallout = (
11840
11844
  addTeardown(onClose);
11841
11845
  }
11842
11846
 
11843
- const [updateLevel, addLevelEffect] = createValueEffect(undefined);
11847
+ const [updateLevel, addLevelEffect, cleanupLevelEffects] =
11848
+ createValueEffect(undefined);
11849
+ addTeardown(cleanupLevelEffects);
11844
11850
 
11845
11851
  // Create and add callout to document
11846
11852
  const calloutElement = createCalloutElement();
@@ -12814,10 +12820,25 @@ const REQUIRED_CONSTRAINT = {
12814
12820
  : undefined,
12815
12821
  };
12816
12822
  }
12817
- if (!element.value) {
12818
- return requiredMessage || `Veuillez remplir ce champ.`;
12823
+ if (element.value) {
12824
+ return null;
12819
12825
  }
12820
- return null;
12826
+ if (requiredMessage) {
12827
+ return requiredMessage;
12828
+ }
12829
+ if (element.type === "password") {
12830
+ return element.hasAttribute("data-same-as")
12831
+ ? `Veuillez confirmer le mot de passe.`
12832
+ : `Veuillez saisir un mot de passe.`;
12833
+ }
12834
+ if (element.type === "email") {
12835
+ return element.hasAttribute("data-same-as")
12836
+ ? `Veuillez confirmer l'adresse e-mail`
12837
+ : `Veuillez saisir une adresse e-mail.`;
12838
+ }
12839
+ return element.hasAttribute("data-same-as")
12840
+ ? `Veuillez confirmer le champ précédent`
12841
+ : `Veuillez remplir ce champ.`;
12821
12842
  },
12822
12843
  };
12823
12844
  const PATTERN_CONSTRAINT = {
@@ -12832,19 +12853,19 @@ const PATTERN_CONSTRAINT = {
12832
12853
  return null;
12833
12854
  }
12834
12855
  const regex = new RegExp(pattern);
12835
- if (!regex.test(value)) {
12836
- const patternMessage = input.getAttribute("data-pattern-message");
12837
- if (patternMessage) {
12838
- return patternMessage;
12839
- }
12840
- let message = `Veuillez respecter le format requis.`;
12841
- const title = input.title;
12842
- if (title) {
12843
- message += `<br />${title}`;
12844
- }
12845
- return message;
12856
+ if (regex.test(value)) {
12857
+ return null;
12846
12858
  }
12847
- return null;
12859
+ const patternMessage = input.getAttribute("data-pattern-message");
12860
+ if (patternMessage) {
12861
+ return patternMessage;
12862
+ }
12863
+ let message = `Veuillez respecter le format requis.`;
12864
+ const title = input.title;
12865
+ if (title) {
12866
+ message += `<br />${title}`;
12867
+ }
12868
+ return message;
12848
12869
  },
12849
12870
  };
12850
12871
  // https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/email#validation
@@ -12892,10 +12913,11 @@ const MIN_LENGTH_CONSTRAINT = {
12892
12913
  return null;
12893
12914
  }
12894
12915
  if (valueLength < minLength) {
12916
+ const thisField = generateThisFieldText(element);
12895
12917
  if (valueLength === 1) {
12896
- return `Ce champ doit contenir au moins ${minLength} caractère (il contient actuellement un seul caractère).`;
12918
+ return `${thisField} doit contenir au moins ${minLength} caractère (il contient actuellement un seul caractère).`;
12897
12919
  }
12898
- return `Ce champ doit contenir au moins ${minLength} caractères (il contient actuellement ${valueLength} caractères).`;
12920
+ return `${thisField} doit contenir au moins ${minLength} caractères (il contient actuellement ${valueLength} caractères).`;
12899
12921
  }
12900
12922
  return null;
12901
12923
  },
@@ -12909,6 +12931,14 @@ const INPUT_TYPE_SUPPORTING_MIN_LENGTH_SET = new Set([
12909
12931
  "password",
12910
12932
  ]);
12911
12933
 
12934
+ const generateThisFieldText = (field) => {
12935
+ return field.type === "password"
12936
+ ? "Ce mot de passe"
12937
+ : field.type === "email"
12938
+ ? "Cette adresse e-mail"
12939
+ : "Ce champ";
12940
+ };
12941
+
12912
12942
  const MAX_LENGTH_CONSTRAINT = {
12913
12943
  name: "max_length",
12914
12944
  check: (element) => {
@@ -12928,7 +12958,8 @@ const MAX_LENGTH_CONSTRAINT = {
12928
12958
  const value = element.value;
12929
12959
  const valueLength = value.length;
12930
12960
  if (valueLength > maxLength) {
12931
- return `Ce champ doit contenir au maximum ${maxLength} caractères (il contient actuellement ${valueLength} caractères).`;
12961
+ const thisField = generateThisFieldText(element);
12962
+ return `${thisField} doit contenir au maximum ${maxLength} caractères (il contient actuellement ${valueLength} caractères).`;
12932
12963
  }
12933
12964
  return null;
12934
12965
  },
@@ -13097,6 +13128,154 @@ const READONLY_CONSTRAINT = {
13097
13128
  },
13098
13129
  };
13099
13130
 
13131
+ const SAME_AS_CONSTRAINT = {
13132
+ name: "same_as",
13133
+ check: (element) => {
13134
+ const sameAs = element.getAttribute("data-same-as");
13135
+ if (!sameAs) {
13136
+ return null;
13137
+ }
13138
+
13139
+ const otherElement = document.querySelector(sameAs);
13140
+ if (!otherElement) {
13141
+ console.warn(
13142
+ `Same as constraint: could not find element for selector ${sameAs}`,
13143
+ );
13144
+ return null;
13145
+ }
13146
+
13147
+ const value = element.value;
13148
+ const otherValue = otherElement.value;
13149
+ if (value === "" || otherValue === "") {
13150
+ // don't validate if one of the two values is empty
13151
+ return null;
13152
+ }
13153
+
13154
+ if (value === otherValue) {
13155
+ return null;
13156
+ }
13157
+
13158
+ const message = element.getAttribute("data-same-as-message");
13159
+ if (message) {
13160
+ return message;
13161
+ }
13162
+
13163
+ const type = element.type;
13164
+ if (type === "password") {
13165
+ return `Ce mot de passe doit être identique au précédent.`;
13166
+ }
13167
+ if (type === "email") {
13168
+ return `Cette adresse e-mail doit être identique a la précédente.`;
13169
+ }
13170
+ return `Ce champ doit être identique au précédent.`;
13171
+ },
13172
+ };
13173
+
13174
+ const listenInputChange = (input, callback) => {
13175
+ const [teardown, addTeardown] = createPubSub();
13176
+
13177
+ let valueAtInteraction;
13178
+ const oninput = () => {
13179
+ valueAtInteraction = undefined;
13180
+ };
13181
+ const onkeydown = (e) => {
13182
+ if (e.key === "Enter") {
13183
+ /**
13184
+ * Browser trigger a "change" event right after the enter is pressed
13185
+ * if the input value has changed.
13186
+ * We need to prevent the next change event otherwise we would request action twice
13187
+ */
13188
+ valueAtInteraction = input.value;
13189
+ }
13190
+ if (e.key === "Escape") {
13191
+ /**
13192
+ * Browser trigger a "change" event right after the escape is pressed
13193
+ * if the input value has changed.
13194
+ * We need to prevent the next change event otherwise we would request action when
13195
+ * we actually want to cancel
13196
+ */
13197
+ valueAtInteraction = input.value;
13198
+ }
13199
+ };
13200
+ const onchange = (e) => {
13201
+ if (
13202
+ valueAtInteraction !== undefined &&
13203
+ e.target.value === valueAtInteraction
13204
+ ) {
13205
+ valueAtInteraction = undefined;
13206
+ return;
13207
+ }
13208
+ callback(e);
13209
+ };
13210
+ input.addEventListener("input", oninput);
13211
+ input.addEventListener("keydown", onkeydown);
13212
+ input.addEventListener("change", onchange);
13213
+ addTeardown(() => {
13214
+ input.removeEventListener("input", oninput);
13215
+ input.removeEventListener("keydown", onkeydown);
13216
+ input.removeEventListener("change", onchange);
13217
+ });
13218
+
13219
+ {
13220
+ // Handle programmatic value changes that don't trigger browser change events
13221
+ //
13222
+ // Problem: When input values are set programmatically (not by user typing),
13223
+ // browsers don't fire the 'change' event. However, our application logic
13224
+ // still needs to detect these changes.
13225
+ //
13226
+ // Example scenario:
13227
+ // 1. User starts editing (letter key pressed, value set programmatically)
13228
+ // 2. User doesn't type anything additional (this is the key part)
13229
+ // 3. User clicks outside to finish editing
13230
+ // 4. Without this code, no change event would fire despite the fact that the input value did change from its original state
13231
+ //
13232
+ // This distinction is crucial because:
13233
+ //
13234
+ // - If the user typed additional text after the initial programmatic value,
13235
+ // the browser would fire change events normally
13236
+ // - But when they don't type anything else, the browser considers it as "no user interaction"
13237
+ // even though the programmatic initial value represents a meaningful change
13238
+ //
13239
+ // We achieve this by checking if the input value has changed between focus and blur without any user interaction
13240
+ // if yes we fire the callback because input value did change
13241
+ let valueAtStart = input.value;
13242
+ let interacted = false;
13243
+
13244
+ const onfocus = () => {
13245
+ interacted = false;
13246
+ valueAtStart = input.value;
13247
+ };
13248
+ const oninput = (e) => {
13249
+ if (!e.isTrusted) {
13250
+ // non trusted "input" events will be ignored by the browser when deciding to fire "change" event
13251
+ // we ignore them too
13252
+ return;
13253
+ }
13254
+ interacted = true;
13255
+ };
13256
+ const onblur = (e) => {
13257
+ if (interacted) {
13258
+ return;
13259
+ }
13260
+ if (valueAtStart === input.value) {
13261
+ return;
13262
+ }
13263
+ callback(e);
13264
+ };
13265
+
13266
+ input.addEventListener("focus", onfocus);
13267
+ input.addEventListener("input", oninput);
13268
+ input.addEventListener("blur", onblur);
13269
+ addTeardown(() => {
13270
+ input.removeEventListener("focus", onfocus);
13271
+ input.removeEventListener("input", oninput);
13272
+ input.removeEventListener("blur", onblur);
13273
+ });
13274
+ }
13275
+
13276
+ return teardown;
13277
+ };
13278
+
13100
13279
  /**
13101
13280
  * Custom form validation implementation
13102
13281
  *
@@ -13133,9 +13312,9 @@ const requestAction = (
13133
13312
  target,
13134
13313
  action,
13135
13314
  {
13315
+ actionOrigin,
13136
13316
  event,
13137
13317
  requester = target,
13138
- actionOrigin,
13139
13318
  method = "rerun",
13140
13319
  meta = {},
13141
13320
  confirmMessage,
@@ -13205,12 +13384,8 @@ const requestAction = (
13205
13384
  // Single element validation case
13206
13385
  isValid = validationInterface.checkValidity({ fromRequestAction: true });
13207
13386
  if (!isValid) {
13208
- if (event) {
13209
- event.preventDefault();
13210
- }
13211
13387
  validationInterface.reportValidity();
13212
13388
  }
13213
-
13214
13389
  elementForConfirmation = target;
13215
13390
  elementForDispatch = target;
13216
13391
  }
@@ -13247,6 +13422,15 @@ const requestAction = (
13247
13422
  return true;
13248
13423
  };
13249
13424
 
13425
+ const forwardActionRequested = (e, action, target = e.target) => {
13426
+ requestAction(target, action, {
13427
+ actionOrigin: e.detail?.actionOrigin,
13428
+ event: e.detail?.event || e,
13429
+ requester: e.detail?.requester,
13430
+ meta: e.detail?.meta,
13431
+ });
13432
+ };
13433
+
13250
13434
  const closeValidationMessage = (element, reason) => {
13251
13435
  const validationInterface = element.__validationInterface__;
13252
13436
  if (!validationInterface) {
@@ -13259,6 +13443,7 @@ const closeValidationMessage = (element, reason) => {
13259
13443
  return validationMessage.close(reason);
13260
13444
  };
13261
13445
 
13446
+ const formInstrumentedWeakSet = new WeakSet();
13262
13447
  const installCustomConstraintValidation = (
13263
13448
  element,
13264
13449
  elementReceivingValidationMessage = element,
@@ -13277,20 +13462,25 @@ const installCustomConstraintValidation = (
13277
13462
  validationMessage: null,
13278
13463
  };
13279
13464
 
13280
- const cleanupCallbackSet = new Set();
13465
+ const [teardown, addTeardown] = createPubSub();
13281
13466
  {
13282
13467
  const uninstall = () => {
13283
- for (const cleanupCallback of cleanupCallbackSet) {
13284
- cleanupCallback();
13285
- }
13286
- cleanupCallbackSet.clear();
13468
+ teardown();
13287
13469
  };
13288
13470
  validationInterface.uninstall = uninstall;
13289
13471
  }
13290
13472
 
13473
+ const isForm = element.tagName === "FORM";
13474
+ if (isForm) {
13475
+ formInstrumentedWeakSet.add(element);
13476
+ addTeardown(() => {
13477
+ formInstrumentedWeakSet.delete(element);
13478
+ });
13479
+ }
13480
+
13291
13481
  {
13292
13482
  element.__validationInterface__ = validationInterface;
13293
- cleanupCallbackSet.add(() => {
13483
+ addTeardown(() => {
13294
13484
  delete element.__validationInterface__;
13295
13485
  });
13296
13486
  }
@@ -13299,7 +13489,6 @@ const installCustomConstraintValidation = (
13299
13489
  const cancelEvent = new CustomEvent("cancel", options);
13300
13490
  element.dispatchEvent(cancelEvent);
13301
13491
  };
13302
-
13303
13492
  const closeElementValidationMessage = (reason) => {
13304
13493
  if (validationInterface.validationMessage) {
13305
13494
  validationInterface.validationMessage.close(reason);
@@ -13319,6 +13508,7 @@ const installCustomConstraintValidation = (
13319
13508
  constraintSet.add(MIN_CONSTRAINT);
13320
13509
  constraintSet.add(MAX_CONSTRAINT);
13321
13510
  constraintSet.add(READONLY_CONSTRAINT);
13511
+ constraintSet.add(SAME_AS_CONSTRAINT);
13322
13512
  {
13323
13513
  validationInterface.registerConstraint = (constraint) => {
13324
13514
  if (typeof constraint === "function") {
@@ -13337,6 +13527,8 @@ const installCustomConstraintValidation = (
13337
13527
  let failedConstraintInfo = null;
13338
13528
  const validityInfoMap = new Map();
13339
13529
 
13530
+ const hasTitleAttribute = element.hasAttribute("title");
13531
+
13340
13532
  const resetValidity = ({ fromRequestAction } = {}) => {
13341
13533
  if (fromRequestAction && failedConstraintInfo) {
13342
13534
  for (const [key, customMessage] of customMessageMap) {
@@ -13354,7 +13546,7 @@ const installCustomConstraintValidation = (
13354
13546
  validityInfoMap.clear();
13355
13547
  failedConstraintInfo = null;
13356
13548
  };
13357
- cleanupCallbackSet.add(resetValidity);
13549
+ addTeardown(resetValidity);
13358
13550
 
13359
13551
  const checkValidity = ({ fromRequestAction, skipReadonly } = {}) => {
13360
13552
  resetValidity({ fromRequestAction });
@@ -13399,7 +13591,16 @@ const installCustomConstraintValidation = (
13399
13591
  validityInfoMap.set(constraint, failedConstraintInfo);
13400
13592
  }
13401
13593
 
13402
- if (!failedConstraintInfo) {
13594
+ if (failedConstraintInfo) {
13595
+ if (!hasTitleAttribute) {
13596
+ // when a constraint is failing browser displays that constraint message if the element has no title attribute.
13597
+ // We want to do the same with our message (overriding the browser in the process to get better messages)
13598
+ element.setAttribute("title", failedConstraintInfo.message);
13599
+ }
13600
+ } else {
13601
+ if (!hasTitleAttribute) {
13602
+ element.removeAttribute("title");
13603
+ }
13403
13604
  closeElementValidationMessage("becomes_valid");
13404
13605
  }
13405
13606
 
@@ -13425,9 +13626,9 @@ const installCustomConstraintValidation = (
13425
13626
  if (!skipFocus) {
13426
13627
  element.focus();
13427
13628
  }
13428
- const closeOnCleanup = () => {
13629
+ const removeCloseOnCleanup = addTeardown(() => {
13429
13630
  closeElementValidationMessage("cleanup");
13430
- };
13631
+ });
13431
13632
 
13432
13633
  const anchorElement =
13433
13634
  failedConstraintInfo.target || elementReceivingValidationMessage;
@@ -13438,7 +13639,7 @@ const installCustomConstraintValidation = (
13438
13639
  level: failedConstraintInfo.level,
13439
13640
  closeOnClickOutside: failedConstraintInfo.closeOnClickOutside,
13440
13641
  onClose: () => {
13441
- cleanupCallbackSet.delete(closeOnCleanup);
13642
+ removeCloseOnCleanup();
13442
13643
  validationInterface.validationMessage = null;
13443
13644
  if (failedConstraintInfo) {
13444
13645
  failedConstraintInfo.reportStatus = "closed";
@@ -13450,7 +13651,6 @@ const installCustomConstraintValidation = (
13450
13651
  },
13451
13652
  );
13452
13653
  failedConstraintInfo.reportStatus = "reported";
13453
- cleanupCallbackSet.add(closeOnCleanup);
13454
13654
  };
13455
13655
  validationInterface.checkValidity = checkValidity;
13456
13656
  validationInterface.reportValidity = reportValidity;
@@ -13485,7 +13685,7 @@ const installCustomConstraintValidation = (
13485
13685
  reportValidity();
13486
13686
  }
13487
13687
  };
13488
- cleanupCallbackSet.add(() => {
13688
+ addTeardown(() => {
13489
13689
  customMessageMap.clear();
13490
13690
  });
13491
13691
  Object.assign(validationInterface, {
@@ -13494,6 +13694,7 @@ const installCustomConstraintValidation = (
13494
13694
  });
13495
13695
  }
13496
13696
 
13697
+ checkValidity();
13497
13698
  {
13498
13699
  const oninput = () => {
13499
13700
  customMessageMap.clear();
@@ -13501,7 +13702,7 @@ const installCustomConstraintValidation = (
13501
13702
  checkValidity();
13502
13703
  };
13503
13704
  element.addEventListener("input", oninput);
13504
- cleanupCallbackSet.add(() => {
13705
+ addTeardown(() => {
13505
13706
  element.removeEventListener("input", oninput);
13506
13707
  });
13507
13708
  }
@@ -13513,13 +13714,7 @@ const installCustomConstraintValidation = (
13513
13714
  checkValidity();
13514
13715
  };
13515
13716
  element.addEventListener("actionend", onactionend);
13516
- if (element.form) {
13517
- element.form.addEventListener("actionend", onactionend);
13518
- cleanupCallbackSet.add(() => {
13519
- element.form.removeEventListener("actionend", onactionend);
13520
- });
13521
- }
13522
- cleanupCallbackSet.add(() => {
13717
+ addTeardown(() => {
13523
13718
  element.removeEventListener("actionend", onactionend);
13524
13719
  });
13525
13720
  }
@@ -13529,37 +13724,111 @@ const installCustomConstraintValidation = (
13529
13724
  element.reportValidity = () => {
13530
13725
  reportValidity();
13531
13726
  };
13532
- cleanupCallbackSet.add(() => {
13727
+ addTeardown(() => {
13533
13728
  element.reportValidity = nativeReportValidity;
13534
13729
  });
13535
13730
  }
13536
13731
 
13537
- {
13538
- const onRequestSubmit = (form, e) => {
13539
- if (form !== element.form && form !== element) {
13732
+ request_on_enter: {
13733
+ if (element.tagName !== "INPUT") {
13734
+ // maybe we want it too for checkboxes etc, we'll see
13735
+ break request_on_enter;
13736
+ }
13737
+ const onkeydown = (keydownEvent) => {
13738
+ if (keydownEvent.defaultPrevented) {
13540
13739
  return;
13541
13740
  }
13542
-
13543
- const requestSubmitCustomEvent = new CustomEvent("requestsubmit", {
13544
- cancelable: true,
13545
- detail: { cause: e },
13741
+ if (keydownEvent.key !== "Enter") {
13742
+ return;
13743
+ }
13744
+ if (element.hasAttribute("data-action")) {
13745
+ if (wouldKeydownSubmitForm(keydownEvent)) {
13746
+ keydownEvent.preventDefault();
13747
+ }
13748
+ dispatchActionRequestedCustomEvent(element, {
13749
+ event: keydownEvent,
13750
+ requester: element,
13751
+ });
13752
+ return;
13753
+ }
13754
+ const { form } = element;
13755
+ if (!form) {
13756
+ return;
13757
+ }
13758
+ keydownEvent.preventDefault();
13759
+ dispatchActionRequestedCustomEvent(form, {
13760
+ event: keydownEvent,
13761
+ requester: getFirstButtonSubmittingForm(form) || element,
13546
13762
  });
13547
- form.dispatchEvent(requestSubmitCustomEvent);
13548
- if (requestSubmitCustomEvent.defaultPrevented) {
13549
- e.preventDefault();
13763
+ };
13764
+ element.addEventListener("keydown", onkeydown);
13765
+ addTeardown(() => {
13766
+ element.removeEventListener("keydown", onkeydown);
13767
+ });
13768
+ }
13769
+
13770
+ {
13771
+ const onclick = (clickEvent) => {
13772
+ if (clickEvent.defaultPrevented) {
13773
+ return;
13774
+ }
13775
+ if (element.tagName !== "BUTTON") {
13776
+ return;
13777
+ }
13778
+ if (element.hasAttribute("data-action")) {
13779
+ if (wouldClickSubmitForm(clickEvent)) {
13780
+ clickEvent.preventDefault();
13781
+ }
13782
+ dispatchActionRequestedCustomEvent(element, {
13783
+ event: clickEvent,
13784
+ requester: element,
13785
+ });
13786
+ return;
13787
+ }
13788
+ const { form } = element;
13789
+ if (!form) {
13790
+ return;
13791
+ }
13792
+ if (wouldClickSubmitForm(clickEvent)) {
13793
+ clickEvent.preventDefault();
13550
13794
  }
13795
+ dispatchActionRequestedCustomEvent(form, {
13796
+ event: clickEvent,
13797
+ requester: element,
13798
+ });
13551
13799
  };
13552
- requestSubmitCallbackSet.add(onRequestSubmit);
13553
- cleanupCallbackSet.add(() => {
13554
- requestSubmitCallbackSet.delete(onRequestSubmit);
13800
+ element.addEventListener("click", onclick);
13801
+ addTeardown(() => {
13802
+ element.removeEventListener("click", onclick);
13803
+ });
13804
+ }
13805
+
13806
+ request_on_input_change: {
13807
+ const isInput =
13808
+ element.tagName === "INPUT" || element.tagName === "TEXTAREA";
13809
+ if (!isInput) {
13810
+ break request_on_input_change;
13811
+ }
13812
+ const stop = listenInputChange(element, (e) => {
13813
+ if (element.hasAttribute("data-action")) {
13814
+ dispatchActionRequestedCustomEvent(element, {
13815
+ event: e,
13816
+ requester: element,
13817
+ });
13818
+ return;
13819
+ }
13820
+ });
13821
+ addTeardown(() => {
13822
+ stop();
13555
13823
  });
13556
13824
  }
13557
13825
 
13558
13826
  execute_on_form_submit: {
13559
- const form = element.form || element.tagName === "FORM" ? element : null;
13560
- if (!form) {
13827
+ if (!isForm) {
13561
13828
  break execute_on_form_submit;
13562
13829
  }
13830
+ // We will dispatch "action" when "submit" occurs (code called from.submit() to bypass validation)
13831
+ const form = element;
13563
13832
  const removeListener = addEventListener(form, "submit", (e) => {
13564
13833
  e.preventDefault();
13565
13834
  const actionCustomEvent = new CustomEvent("action", {
@@ -13568,12 +13837,14 @@ const installCustomConstraintValidation = (
13568
13837
  event: e,
13569
13838
  method: "rerun",
13570
13839
  requester: form,
13571
- meta: {},
13840
+ meta: {
13841
+ isSubmit: true,
13842
+ },
13572
13843
  },
13573
13844
  });
13574
13845
  form.dispatchEvent(actionCustomEvent);
13575
13846
  });
13576
- cleanupCallbackSet.add(() => {
13847
+ addTeardown(() => {
13577
13848
  removeListener();
13578
13849
  });
13579
13850
  }
@@ -13587,7 +13858,7 @@ const installCustomConstraintValidation = (
13587
13858
  }
13588
13859
  };
13589
13860
  element.addEventListener("keydown", onkeydown);
13590
- cleanupCallbackSet.add(() => {
13861
+ addTeardown(() => {
13591
13862
  element.removeEventListener("keydown", onkeydown);
13592
13863
  });
13593
13864
  }
@@ -13595,7 +13866,11 @@ const installCustomConstraintValidation = (
13595
13866
  {
13596
13867
  const onblur = () => {
13597
13868
  if (element.value === "") {
13598
- dispatchCancelCustomEvent({ detail: { reason: "blur_empty" } });
13869
+ dispatchCancelCustomEvent({
13870
+ detail: {
13871
+ reason: "blur_empty",
13872
+ },
13873
+ });
13599
13874
  return;
13600
13875
  }
13601
13876
  // if we have failed constraint, we cancel too
@@ -13610,7 +13885,7 @@ const installCustomConstraintValidation = (
13610
13885
  }
13611
13886
  };
13612
13887
  element.addEventListener("blur", onblur);
13613
- cleanupCallbackSet.add(() => {
13888
+ addTeardown(() => {
13614
13889
  element.removeEventListener("blur", onblur);
13615
13890
  });
13616
13891
  }
@@ -13618,22 +13893,105 @@ const installCustomConstraintValidation = (
13618
13893
  return validationInterface;
13619
13894
  };
13620
13895
 
13621
- // https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation
13896
+ const wouldClickSubmitForm = (clickEvent) => {
13897
+ if (clickEvent.defaultPrevented) {
13898
+ return false;
13899
+ }
13900
+ const clickTarget = clickEvent.target;
13901
+ const { form } = clickTarget;
13902
+ if (!form) {
13903
+ return false;
13904
+ }
13905
+ const button = clickTarget.closest("button");
13906
+ if (!button) {
13907
+ return false;
13908
+ }
13909
+ const wouldSubmitFormByType =
13910
+ button.type === "submit" || button.type === "image";
13911
+ if (wouldSubmitFormByType) {
13912
+ return true;
13913
+ }
13914
+ if (button.type) {
13915
+ return false;
13916
+ }
13917
+ if (getFirstButtonSubmittingForm(form)) {
13918
+ // an other button is explicitly submitting the form, this one would not submit it
13919
+ return false;
13920
+ }
13921
+ // this is the only button inside the form without type attribute, so it defaults to type="submit"
13922
+ return true;
13923
+ };
13924
+ const getFirstButtonSubmittingForm = (form) => {
13925
+ return form.querySelector(
13926
+ `button[type="submit"], input[type="submit"], input[type="image"]`,
13927
+ );
13928
+ };
13929
+
13930
+ const wouldKeydownSubmitForm = (keydownEvent) => {
13931
+ if (keydownEvent.defaultPrevented) {
13932
+ return false;
13933
+ }
13934
+ const keydownTarget = keydownEvent.target;
13935
+ const { form } = keydownTarget;
13936
+ if (!form) {
13937
+ return false;
13938
+ }
13939
+ if (keydownEvent.key !== "Enter") {
13940
+ return false;
13941
+ }
13942
+ const isTextInput =
13943
+ keydownTarget.tagName === "INPUT" || keydownTarget.tagName === "TEXTAREA";
13944
+ if (!isTextInput) {
13945
+ return false;
13946
+ }
13947
+ return true;
13948
+ };
13622
13949
 
13623
- const requestSubmitCallbackSet = new Set();
13950
+ const dispatchActionRequestedCustomEvent = (
13951
+ fieldOrForm,
13952
+ { actionOrigin = "action_prop", event, requester },
13953
+ ) => {
13954
+ const actionRequestedCustomEvent = new CustomEvent("actionrequested", {
13955
+ cancelable: true,
13956
+ detail: {
13957
+ actionOrigin,
13958
+ event,
13959
+ requester,
13960
+ },
13961
+ });
13962
+ fieldOrForm.dispatchEvent(actionRequestedCustomEvent);
13963
+ };
13964
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation
13624
13965
  const requestSubmit = HTMLFormElement.prototype.requestSubmit;
13625
13966
  HTMLFormElement.prototype.requestSubmit = function (submitter) {
13626
- let prevented = false;
13627
- const preventDefault = () => {
13628
- prevented = true;
13629
- };
13630
- for (const requestSubmitCallback of requestSubmitCallbackSet) {
13631
- requestSubmitCallback(this, { submitter, preventDefault });
13632
- }
13633
- if (prevented) {
13967
+ const form = this;
13968
+ const isInstrumented = formInstrumentedWeakSet.has(form);
13969
+ if (!isInstrumented) {
13970
+ requestSubmit.call(form, submitter);
13634
13971
  return;
13635
13972
  }
13636
- requestSubmit.call(this, submitter);
13973
+ const programmaticEvent = new CustomEvent("programmatic_requestsubmit", {
13974
+ cancelable: true,
13975
+ detail: {
13976
+ submitter,
13977
+ },
13978
+ });
13979
+ dispatchActionRequestedCustomEvent(form, {
13980
+ event: programmaticEvent,
13981
+ requester: submitter,
13982
+ });
13983
+
13984
+ // When all fields are valid calling the native requestSubmit would let browser go through the
13985
+ // standard form validation steps leading to form submission.
13986
+ // We don't want that because we have our own action system to handle forms
13987
+ // If we did that the form submission would happen in parallel of our action system
13988
+ // and because we listen to "submit" event to dispatch "action" event
13989
+ // we would end up with two actions being executed.
13990
+ //
13991
+ // In case we have discrepencies in our implementation compared to the browser standard
13992
+ // this also prevent the native validation message to show up.
13993
+
13994
+ // requestSubmit.call(this, submitter);
13637
13995
  };
13638
13996
 
13639
13997
  // const submit = HTMLFormElement.prototype.submit;
@@ -14381,10 +14739,10 @@ const useKeyboardShortcuts = (
14381
14739
  }
14382
14740
  const { action } = shortcutCandidate;
14383
14741
  return requestAction(element, action, {
14742
+ actionOrigin: "keyboard_shortcut",
14384
14743
  event: keyboardEvent,
14385
14744
  requester: document.activeElement,
14386
14745
  confirmMessage: shortcutCandidate.confirmMessage,
14387
- actionOrigin: "keyboard_shortcut",
14388
14746
  meta: {
14389
14747
  shortcut: shortcutCandidate,
14390
14748
  },
@@ -18276,33 +18634,33 @@ const SummaryMarker = ({
18276
18634
 
18277
18635
  installImportMetaCss(import.meta);import.meta.css = /* css */`
18278
18636
  .navi_details {
18279
- display: flex;
18280
- flex-direction: column;
18281
18637
  position: relative;
18282
18638
  z-index: 1;
18639
+ display: flex;
18283
18640
  flex-shrink: 0;
18641
+ flex-direction: column;
18284
18642
  }
18285
18643
 
18286
18644
  .navi_details > summary {
18287
- flex-shrink: 0;
18288
- cursor: pointer;
18289
18645
  display: flex;
18646
+ flex-shrink: 0;
18290
18647
  flex-direction: column;
18648
+ cursor: pointer;
18291
18649
  user-select: none;
18292
18650
  }
18293
18651
  .summary_body {
18294
18652
  display: flex;
18653
+ width: 100%;
18295
18654
  flex-direction: row;
18296
18655
  align-items: center;
18297
- width: 100%;
18298
18656
  gap: 0.2em;
18299
18657
  }
18300
18658
  .summary_label {
18301
18659
  display: flex;
18660
+ padding-right: 10px;
18302
18661
  flex: 1;
18303
- gap: 0.2em;
18304
18662
  align-items: center;
18305
- padding-right: 10px;
18663
+ gap: 0.2em;
18306
18664
  }
18307
18665
 
18308
18666
  .navi_details > summary:focus {
@@ -18477,7 +18835,6 @@ const DetailsWithAction = forwardRef((props, ref) => {
18477
18835
  const isOpen = toggleEvent.newState === "open";
18478
18836
  if (isOpen) {
18479
18837
  requestAction(toggleEvent.target, effectiveAction, {
18480
- actionOrigin: "action_prop",
18481
18838
  event: toggleEvent,
18482
18839
  method: "run"
18483
18840
  });
@@ -20490,8 +20847,7 @@ const InputCheckboxWithAction = forwardRef((props, ref) => {
20490
20847
  loading: loading || actionLoading,
20491
20848
  onChange: e => {
20492
20849
  requestAction(e.target, actionBoundToUIState, {
20493
- event: e,
20494
- actionOrigin: "action_prop"
20850
+ event: e
20495
20851
  });
20496
20852
  onChange?.(e);
20497
20853
  }
@@ -21127,8 +21483,6 @@ const InputTextualWithAction = forwardRef((props, ref) => {
21127
21483
  cancelOnBlurInvalid,
21128
21484
  cancelOnEscape,
21129
21485
  actionErrorEffect,
21130
- onInput,
21131
- onKeyDown,
21132
21486
  ...rest
21133
21487
  } = props;
21134
21488
  const innerRef = useRef(null);
@@ -21140,17 +21494,6 @@ const InputTextualWithAction = forwardRef((props, ref) => {
21140
21494
  const executeAction = useExecuteAction(innerRef, {
21141
21495
  errorEffect: actionErrorEffect
21142
21496
  });
21143
- const valueAtInteractionRef = useRef(null);
21144
- useOnInputChange(innerRef, e => {
21145
- if (valueAtInteractionRef.current !== null && e.target.value === valueAtInteractionRef.current) {
21146
- valueAtInteractionRef.current = null;
21147
- return;
21148
- }
21149
- requestAction(e.target, boundAction, {
21150
- event: e,
21151
- actionOrigin: "action_prop"
21152
- });
21153
- });
21154
21497
  // here updating the input won't call the associated action
21155
21498
  // (user have to blur or press enter for this to happen)
21156
21499
  // so we can keep the ui state on cancel/abort/error and let user decide
@@ -21171,16 +21514,12 @@ const InputTextualWithAction = forwardRef((props, ref) => {
21171
21514
  if (!cancelOnEscape) {
21172
21515
  return;
21173
21516
  }
21174
- /**
21175
- * Browser trigger a "change" event right after the escape is pressed
21176
- * if the input value has changed.
21177
- * We need to prevent the next change event otherwise we would request action when
21178
- * we actually want to cancel
21179
- */
21180
- valueAtInteractionRef.current = e.target.value;
21181
21517
  }
21182
21518
  onCancel?.(e, reason);
21183
21519
  },
21520
+ onRequested: e => {
21521
+ forwardActionRequested(e, boundAction);
21522
+ },
21184
21523
  onPrevented: onActionPrevented,
21185
21524
  onAction: executeAction,
21186
21525
  onStart: onActionStart,
@@ -21191,33 +21530,11 @@ const InputTextualWithAction = forwardRef((props, ref) => {
21191
21530
  "data-action": boundAction.name,
21192
21531
  ...rest,
21193
21532
  ref: innerRef,
21194
- loading: loading || actionLoading,
21195
- onInput: e => {
21196
- valueAtInteractionRef.current = null;
21197
- onInput?.(e);
21198
- },
21199
- onKeyDown: e => {
21200
- if (e.key !== "Enter") {
21201
- return;
21202
- }
21203
- e.preventDefault();
21204
- /**
21205
- * Browser trigger a "change" event right after the enter is pressed
21206
- * if the input value has changed.
21207
- * We need to prevent the next change event otherwise we would request action twice
21208
- */
21209
- valueAtInteractionRef.current = e.target.value;
21210
- requestAction(e.target, boundAction, {
21211
- event: e,
21212
- actionOrigin: "action_prop"
21213
- });
21214
- onKeyDown?.(e);
21215
- }
21533
+ loading: loading || actionLoading
21216
21534
  });
21217
21535
  });
21218
21536
  const InputTextualInsideForm = forwardRef((props, ref) => {
21219
21537
  const {
21220
- onKeyDown,
21221
21538
  // We destructure formContext to avoid passing it to the underlying input element
21222
21539
  // eslint-disable-next-line no-unused-vars
21223
21540
  formContext,
@@ -21225,94 +21542,10 @@ const InputTextualInsideForm = forwardRef((props, ref) => {
21225
21542
  } = props;
21226
21543
  return jsx(InputTextualBasic, {
21227
21544
  ...rest,
21228
- ref: ref,
21229
- onKeyDown: e => {
21230
- if (e.key === "Enter") {
21231
- const inputElement = e.target;
21232
- const {
21233
- form
21234
- } = inputElement;
21235
- const formSubmitButton = form.querySelector("button[type='submit'], input[type='submit'], input[type='image']");
21236
- e.preventDefault();
21237
- form.dispatchEvent(new CustomEvent("actionrequested", {
21238
- detail: {
21239
- requester: formSubmitButton ? formSubmitButton : inputElement,
21240
- event: e,
21241
- meta: {
21242
- isSubmit: true
21243
- },
21244
- actionOrigin: "action_prop"
21245
- }
21246
- }));
21247
- }
21248
- onKeyDown?.(e);
21249
- }
21545
+ ref: ref
21250
21546
  });
21251
21547
  });
21252
- const useOnInputChange = (inputRef, callback) => {
21253
- // we must use a custom event listener because preact bind onChange to onInput for compat with react
21254
- useEffect(() => {
21255
- const input = inputRef.current;
21256
- input.addEventListener("change", callback);
21257
- return () => {
21258
- input.removeEventListener("change", callback);
21259
- };
21260
- }, [callback]);
21261
21548
 
21262
- // Handle programmatic value changes that don't trigger browser change events
21263
- //
21264
- // Problem: When input values are set programmatically (not by user typing),
21265
- // browsers don't fire the 'change' event. However, our application logic
21266
- // still needs to detect these changes.
21267
- //
21268
- // Example scenario:
21269
- // 1. User starts editing (letter key pressed, value set programmatically)
21270
- // 2. User doesn't type anything additional (this is the key part)
21271
- // 3. User clicks outside to finish editing
21272
- // 4. Without this code, no change event would fire despite the fact that the input value did change from its original state
21273
- //
21274
- // This distinction is crucial because:
21275
- //
21276
- // - If the user typed additional text after the initial programmatic value,
21277
- // the browser would fire change events normally
21278
- // - But when they don't type anything else, the browser considers it as "no user interaction"
21279
- // even though the programmatic initial value represents a meaningful change
21280
- const valueAtStartRef = useRef();
21281
- const interactedRef = useRef(false);
21282
- useLayoutEffect(() => {
21283
- const input = inputRef.current;
21284
- valueAtStartRef.current = input.value;
21285
- const onfocus = () => {
21286
- interactedRef.current = false;
21287
- valueAtStartRef.current = input.value;
21288
- };
21289
- const oninput = e => {
21290
- if (!e.isTrusted) {
21291
- // non trusted "input" events will be ignored by the browser when deciding to fire "change" event
21292
- // we ignore them too
21293
- return;
21294
- }
21295
- interactedRef.current = true;
21296
- };
21297
- const onblur = e => {
21298
- if (interactedRef.current) {
21299
- return;
21300
- }
21301
- if (valueAtStartRef.current === input.value) {
21302
- return;
21303
- }
21304
- callback(e);
21305
- };
21306
- input.addEventListener("focus", onfocus);
21307
- input.addEventListener("input", oninput);
21308
- input.addEventListener("blur", onblur);
21309
- return () => {
21310
- input.removeEventListener("focus", onfocus);
21311
- input.removeEventListener("input", oninput);
21312
- input.removeEventListener("blur", onblur);
21313
- };
21314
- }, []);
21315
- };
21316
21549
  // As explained in https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/datetime-local#setting_timezones
21317
21550
  // datetime-local does not support timezones
21318
21551
  const convertToLocalTimezone = dateTimeString => {
@@ -21536,6 +21769,7 @@ const useFormEvents = (
21536
21769
  elementRef,
21537
21770
  {
21538
21771
  onFormReset,
21772
+ onFormActionRequested,
21539
21773
  onFormActionPrevented,
21540
21774
  onFormActionStart,
21541
21775
  onFormActionAbort,
@@ -21544,6 +21778,7 @@ const useFormEvents = (
21544
21778
  },
21545
21779
  ) => {
21546
21780
  onFormReset = useStableCallback(onFormReset);
21781
+ onFormActionRequested = useStableCallback(onFormActionRequested);
21547
21782
  onFormActionPrevented = useStableCallback(onFormActionPrevented);
21548
21783
  onFormActionStart = useStableCallback(onFormActionStart);
21549
21784
  onFormActionAbort = useStableCallback(onFormActionAbort);
@@ -21567,6 +21802,7 @@ const useFormEvents = (
21567
21802
  }
21568
21803
  return addManyEventListeners(form, {
21569
21804
  reset: onFormReset,
21805
+ actionrequested: onFormActionRequested,
21570
21806
  actionprevented: onFormActionPrevented,
21571
21807
  actionstart: onFormActionStart,
21572
21808
  actionabort: onFormActionAbort,
@@ -21575,6 +21811,7 @@ const useFormEvents = (
21575
21811
  });
21576
21812
  }, [
21577
21813
  onFormReset,
21814
+ onFormActionRequested,
21578
21815
  onFormActionPrevented,
21579
21816
  onFormActionStart,
21580
21817
  onFormActionAbort,
@@ -21821,7 +22058,6 @@ const ButtonWithAction = forwardRef((props, ref) => {
21821
22058
  const {
21822
22059
  action,
21823
22060
  loading,
21824
- onClick,
21825
22061
  actionErrorEffect,
21826
22062
  onActionPrevented,
21827
22063
  onActionStart,
@@ -21839,22 +22075,15 @@ const ButtonWithAction = forwardRef((props, ref) => {
21839
22075
  const executeAction = useExecuteAction(innerRef, {
21840
22076
  errorEffect: actionErrorEffect
21841
22077
  });
22078
+ const innerLoading = loading || actionLoading;
21842
22079
  useActionEvents(innerRef, {
21843
22080
  onPrevented: onActionPrevented,
22081
+ onRequested: e => forwardActionRequested(e, boundAction),
21844
22082
  onAction: executeAction,
21845
22083
  onStart: onActionStart,
21846
22084
  onError: onActionError,
21847
22085
  onEnd: onActionEnd
21848
22086
  });
21849
- const handleClick = event => {
21850
- event.preventDefault();
21851
- const button = innerRef.current;
21852
- requestAction(button, boundAction, {
21853
- event,
21854
- actionOrigin: "action_prop"
21855
- });
21856
- };
21857
- const innerLoading = loading || actionLoading;
21858
22087
  return jsx(ButtonBasic
21859
22088
  // put data-action first to help find it in devtools
21860
22089
  , {
@@ -21862,10 +22091,6 @@ const ButtonWithAction = forwardRef((props, ref) => {
21862
22091
  ...rest,
21863
22092
  ref: innerRef,
21864
22093
  loading: innerLoading,
21865
- onClick: event => {
21866
- handleClick(event);
21867
- onClick?.(event);
21868
- },
21869
22094
  children: children
21870
22095
  });
21871
22096
  });
@@ -21874,7 +22099,6 @@ const ButtonInsideForm = forwardRef((props, ref) => {
21874
22099
  // eslint-disable-next-line no-unused-vars
21875
22100
  formContext,
21876
22101
  type,
21877
- onClick,
21878
22102
  children,
21879
22103
  loading,
21880
22104
  readOnly,
@@ -21882,50 +22106,14 @@ const ButtonInsideForm = forwardRef((props, ref) => {
21882
22106
  } = props;
21883
22107
  const innerRef = useRef();
21884
22108
  useImperativeHandle(ref, () => innerRef.current);
21885
- const wouldSubmitFormByType = type === "submit" || type === "image";
21886
22109
  const innerLoading = loading;
21887
22110
  const innerReadOnly = readOnly;
21888
- const handleClick = event => {
21889
- const buttonElement = innerRef.current;
21890
- const {
21891
- form
21892
- } = buttonElement;
21893
- let wouldSubmitForm = wouldSubmitFormByType;
21894
- if (!wouldSubmitForm && type === undefined) {
21895
- const formSubmitButton = form.querySelector("button[type='submit'], input[type='submit'], input[type='image']");
21896
- const wouldSubmitFormBecauseSingleButtonWithoutType = !formSubmitButton;
21897
- wouldSubmitForm = wouldSubmitFormBecauseSingleButtonWithoutType;
21898
- }
21899
- if (!wouldSubmitForm) {
21900
- if (buttonElement.hasAttribute("data-readonly")) {
21901
- event.preventDefault();
21902
- }
21903
- return;
21904
- }
21905
- // prevent default behavior that would submit the form
21906
- // we want to go through the action execution process (with validation and all)
21907
- event.preventDefault();
21908
- form.dispatchEvent(new CustomEvent("actionrequested", {
21909
- detail: {
21910
- requester: buttonElement,
21911
- event,
21912
- meta: {
21913
- isSubmit: true
21914
- },
21915
- actionOrigin: "action_prop"
21916
- }
21917
- }));
21918
- };
21919
22111
  return jsx(ButtonBasic, {
21920
22112
  ...rest,
21921
22113
  ref: innerRef,
21922
22114
  type: type,
21923
22115
  loading: innerLoading,
21924
22116
  readOnly: innerReadOnly,
21925
- onClick: event => {
21926
- handleClick(event);
21927
- onClick?.(event);
21928
- },
21929
22117
  children: children
21930
22118
  });
21931
22119
  });
@@ -21939,7 +22127,6 @@ const ButtonWithActionInsideForm = forwardRef((props, ref) => {
21939
22127
  action,
21940
22128
  loading,
21941
22129
  children,
21942
- onClick,
21943
22130
  onActionPrevented,
21944
22131
  onActionStart,
21945
22132
  onActionAbort,
@@ -21988,16 +22175,8 @@ const ButtonWithActionInsideForm = forwardRef((props, ref) => {
21988
22175
  ref: innerRef,
21989
22176
  type: type,
21990
22177
  loading: innerLoading,
21991
- onClick: event => {
21992
- const button = innerRef.current;
21993
- const form = button.form;
21994
- event.preventDefault();
21995
- requestAction(form, actionBoundToFormParams, {
21996
- event,
21997
- requester: button,
21998
- actionOrigin: "action_prop"
21999
- });
22000
- onClick?.(event);
22178
+ onactionrequested: e => {
22179
+ forwardActionRequested(e, actionBoundToFormParams, e.target.form);
22001
22180
  },
22002
22181
  children: children
22003
22182
  });
@@ -22148,8 +22327,7 @@ const CheckboxListWithAction = forwardRef((props, ref) => {
22148
22327
  const checkbox = event.target;
22149
22328
  requestAction(checkboxList, boundAction, {
22150
22329
  event,
22151
- requester: checkbox,
22152
- actionOrigin: "action_prop"
22330
+ requester: checkbox
22153
22331
  });
22154
22332
  },
22155
22333
  loading: loading || actionLoading,
@@ -22374,13 +22552,7 @@ const FormWithAction = forwardRef((props, ref) => {
22374
22552
  useActionEvents(innerRef, {
22375
22553
  onPrevented: onActionPrevented,
22376
22554
  onRequested: e => {
22377
- const form = innerRef.current;
22378
- requestAction(form, actionBoundToUIState, {
22379
- requester: e.detail?.requester,
22380
- event: e.detail?.event || e,
22381
- meta: e.detail?.meta,
22382
- actionOrigin: e.detail?.actionOrigin
22383
- });
22555
+ forwardActionRequested(e, actionBoundToUIState);
22384
22556
  },
22385
22557
  onAction: e => {
22386
22558
  const form = innerRef.current;
@@ -22416,15 +22588,6 @@ const FormWithAction = forwardRef((props, ref) => {
22416
22588
  ...rest,
22417
22589
  ref: innerRef,
22418
22590
  loading: innerLoading,
22419
- onrequestsubmit: e => {
22420
- // prevent "submit" event that would be dispatched by the browser after form.requestSubmit()
22421
- // (not super important because our <form> listen the "action" and do does preventDefault on "submit")
22422
- e.preventDefault();
22423
- requestAction(e.target, actionBoundToUIState, {
22424
- event: e,
22425
- actionOrigin: "action_prop"
22426
- });
22427
- },
22428
22591
  children: jsx(FormActionContext.Provider, {
22429
22592
  value: actionBoundToUIState,
22430
22593
  children: jsx(LoadingElementContext.Provider, {
@@ -22591,8 +22754,7 @@ const RadioListWithAction = forwardRef((props, ref) => {
22591
22754
  const radioListContainer = innerRef.current;
22592
22755
  requestAction(radioListContainer, boundAction, {
22593
22756
  event: e,
22594
- requester: radio,
22595
- actionOrigin: "action_prop"
22757
+ requester: radio
22596
22758
  });
22597
22759
  },
22598
22760
  loading: loading || actionLoading,
@@ -22800,8 +22962,7 @@ const SelectWithAction = forwardRef((props, ref) => {
22800
22962
  const optionSelected = select.querySelector(`option[value="${selectedValue}"]`);
22801
22963
  requestAction(radioListContainer, boundAction, {
22802
22964
  event,
22803
- requester: optionSelected,
22804
- actionOrigin: "action_prop"
22965
+ requester: optionSelected
22805
22966
  });
22806
22967
  },
22807
22968
  ...rest,
@@ -28522,4 +28683,4 @@ const useDependenciesDiff = (inputs) => {
28522
28683
  return diffRef.current;
28523
28684
  };
28524
28685
 
28525
- export { ActionRenderer, ActiveKeyboardShortcuts, Button, Checkbox, CheckboxList, Col, Colgroup, Details, Editable, ErrorBoundaryContext, FlexColumn, FlexItem, FlexRow, FontSizedSvg, Form, Icon, IconAndText, Input, Label, Link, LinkWithIcon, Overflow, Radio, RadioList, Route, RowNumberCol, RowNumberTableCell, SINGLE_SPACE_CONSTRAINT, SVGMaskOverlay, Select, SelectionContext, Spacing, SummaryMarker, Tab, TabList, Table, TableCell, Tbody, Text, TextAndCount, Thead, Tr, UITransition, actionIntegratedVia, addCustomMessage, createAction, createSelectionKeyboardShortcuts, createUniqueValueConstraint, defineRoutes, enableDebugActions, enableDebugOnDocumentLoading, goBack, goForward, goTo, isCellSelected, isColumnSelected, isRowSelected, openCallout, rawUrlPart, reload, removeCustomMessage, rerunActions, resource, setBaseUrl, stopLoad, stringifyTableSelectionValue, updateActions, useActionData, useActionStatus, useCellsAndColumns, useDependenciesDiff, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useRouteStatus, useRunOnMount, useSelectableElement, useSelectionController, useSignalSync, useStateArray, valueInLocalStorage };
28686
+ export { ActionRenderer, ActiveKeyboardShortcuts, Button, Checkbox, CheckboxList, Col, Colgroup, Details, Editable, ErrorBoundaryContext, FlexColumn, FlexItem, FlexRow, FontSizedSvg, Form, Icon, IconAndText, Input, Label, Link, LinkWithIcon, Overflow, Radio, RadioList, Route, RowNumberCol, RowNumberTableCell, SINGLE_SPACE_CONSTRAINT, SVGMaskOverlay, Select, SelectionContext, Spacing, SummaryMarker, Tab, TabList, Table, TableCell, Tbody, Text, TextAndCount, Thead, Tr, UITransition, actionIntegratedVia, addCustomMessage, createAction, createSelectionKeyboardShortcuts, createUniqueValueConstraint, defineRoutes, enableDebugActions, enableDebugOnDocumentLoading, forwardActionRequested, goBack, goForward, goTo, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, openCallout, rawUrlPart, reload, removeCustomMessage, rerunActions, resource, setBaseUrl, stopLoad, stringifyTableSelectionValue, updateActions, useActionData, useActionStatus, useCellsAndColumns, useDependenciesDiff, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useRouteStatus, useRunOnMount, useSelectableElement, useSelectionController, useSignalSync, useStateArray, valueInLocalStorage };