@jsenv/navi 0.9.3 → 0.10.0

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,119 @@ 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
+ const { form } = element;
13821
+ if (!form) {
13822
+ return;
13823
+ }
13824
+ dispatchActionRequestedCustomEvent(form, {
13825
+ event: e,
13826
+ requester: element,
13827
+ });
13828
+ });
13829
+ addTeardown(() => {
13830
+ stop();
13555
13831
  });
13556
13832
  }
13557
13833
 
13558
13834
  execute_on_form_submit: {
13559
- const form = element.form || element.tagName === "FORM" ? element : null;
13560
- if (!form) {
13835
+ if (!isForm) {
13561
13836
  break execute_on_form_submit;
13562
13837
  }
13838
+ // We will dispatch "action" when "submit" occurs (code called from.submit() to bypass validation)
13839
+ const form = element;
13563
13840
  const removeListener = addEventListener(form, "submit", (e) => {
13564
13841
  e.preventDefault();
13565
13842
  const actionCustomEvent = new CustomEvent("action", {
@@ -13568,12 +13845,14 @@ const installCustomConstraintValidation = (
13568
13845
  event: e,
13569
13846
  method: "rerun",
13570
13847
  requester: form,
13571
- meta: {},
13848
+ meta: {
13849
+ isSubmit: true,
13850
+ },
13572
13851
  },
13573
13852
  });
13574
13853
  form.dispatchEvent(actionCustomEvent);
13575
13854
  });
13576
- cleanupCallbackSet.add(() => {
13855
+ addTeardown(() => {
13577
13856
  removeListener();
13578
13857
  });
13579
13858
  }
@@ -13587,7 +13866,7 @@ const installCustomConstraintValidation = (
13587
13866
  }
13588
13867
  };
13589
13868
  element.addEventListener("keydown", onkeydown);
13590
- cleanupCallbackSet.add(() => {
13869
+ addTeardown(() => {
13591
13870
  element.removeEventListener("keydown", onkeydown);
13592
13871
  });
13593
13872
  }
@@ -13595,7 +13874,11 @@ const installCustomConstraintValidation = (
13595
13874
  {
13596
13875
  const onblur = () => {
13597
13876
  if (element.value === "") {
13598
- dispatchCancelCustomEvent({ detail: { reason: "blur_empty" } });
13877
+ dispatchCancelCustomEvent({
13878
+ detail: {
13879
+ reason: "blur_empty",
13880
+ },
13881
+ });
13599
13882
  return;
13600
13883
  }
13601
13884
  // if we have failed constraint, we cancel too
@@ -13610,7 +13893,7 @@ const installCustomConstraintValidation = (
13610
13893
  }
13611
13894
  };
13612
13895
  element.addEventListener("blur", onblur);
13613
- cleanupCallbackSet.add(() => {
13896
+ addTeardown(() => {
13614
13897
  element.removeEventListener("blur", onblur);
13615
13898
  });
13616
13899
  }
@@ -13618,22 +13901,105 @@ const installCustomConstraintValidation = (
13618
13901
  return validationInterface;
13619
13902
  };
13620
13903
 
13621
- // https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation
13904
+ const wouldClickSubmitForm = (clickEvent) => {
13905
+ if (clickEvent.defaultPrevented) {
13906
+ return false;
13907
+ }
13908
+ const clickTarget = clickEvent.target;
13909
+ const { form } = clickTarget;
13910
+ if (!form) {
13911
+ return false;
13912
+ }
13913
+ const button = clickTarget.closest("button");
13914
+ if (!button) {
13915
+ return false;
13916
+ }
13917
+ const wouldSubmitFormByType =
13918
+ button.type === "submit" || button.type === "image";
13919
+ if (wouldSubmitFormByType) {
13920
+ return true;
13921
+ }
13922
+ if (button.type) {
13923
+ return false;
13924
+ }
13925
+ if (getFirstButtonSubmittingForm(form)) {
13926
+ // an other button is explicitly submitting the form, this one would not submit it
13927
+ return false;
13928
+ }
13929
+ // this is the only button inside the form without type attribute, so it defaults to type="submit"
13930
+ return true;
13931
+ };
13932
+ const getFirstButtonSubmittingForm = (form) => {
13933
+ return form.querySelector(
13934
+ `button[type="submit"], input[type="submit"], input[type="image"]`,
13935
+ );
13936
+ };
13622
13937
 
13623
- const requestSubmitCallbackSet = new Set();
13938
+ const wouldKeydownSubmitForm = (keydownEvent) => {
13939
+ if (keydownEvent.defaultPrevented) {
13940
+ return false;
13941
+ }
13942
+ const keydownTarget = keydownEvent.target;
13943
+ const { form } = keydownTarget;
13944
+ if (!form) {
13945
+ return false;
13946
+ }
13947
+ if (keydownEvent.key !== "Enter") {
13948
+ return false;
13949
+ }
13950
+ const isTextInput =
13951
+ keydownTarget.tagName === "INPUT" || keydownTarget.tagName === "TEXTAREA";
13952
+ if (!isTextInput) {
13953
+ return false;
13954
+ }
13955
+ return true;
13956
+ };
13957
+
13958
+ const dispatchActionRequestedCustomEvent = (
13959
+ fieldOrForm,
13960
+ { actionOrigin = "action_prop", event, requester },
13961
+ ) => {
13962
+ const actionRequestedCustomEvent = new CustomEvent("actionrequested", {
13963
+ cancelable: true,
13964
+ detail: {
13965
+ actionOrigin,
13966
+ event,
13967
+ requester,
13968
+ },
13969
+ });
13970
+ fieldOrForm.dispatchEvent(actionRequestedCustomEvent);
13971
+ };
13972
+ // https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation
13624
13973
  const requestSubmit = HTMLFormElement.prototype.requestSubmit;
13625
13974
  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) {
13975
+ const form = this;
13976
+ const isInstrumented = formInstrumentedWeakSet.has(form);
13977
+ if (!isInstrumented) {
13978
+ requestSubmit.call(form, submitter);
13634
13979
  return;
13635
13980
  }
13636
- requestSubmit.call(this, submitter);
13981
+ const programmaticEvent = new CustomEvent("programmatic_requestsubmit", {
13982
+ cancelable: true,
13983
+ detail: {
13984
+ submitter,
13985
+ },
13986
+ });
13987
+ dispatchActionRequestedCustomEvent(form, {
13988
+ event: programmaticEvent,
13989
+ requester: submitter,
13990
+ });
13991
+
13992
+ // When all fields are valid calling the native requestSubmit would let browser go through the
13993
+ // standard form validation steps leading to form submission.
13994
+ // We don't want that because we have our own action system to handle forms
13995
+ // If we did that the form submission would happen in parallel of our action system
13996
+ // and because we listen to "submit" event to dispatch "action" event
13997
+ // we would end up with two actions being executed.
13998
+ //
13999
+ // In case we have discrepencies in our implementation compared to the browser standard
14000
+ // this also prevent the native validation message to show up.
14001
+
14002
+ // requestSubmit.call(this, submitter);
13637
14003
  };
13638
14004
 
13639
14005
  // const submit = HTMLFormElement.prototype.submit;
@@ -14381,10 +14747,10 @@ const useKeyboardShortcuts = (
14381
14747
  }
14382
14748
  const { action } = shortcutCandidate;
14383
14749
  return requestAction(element, action, {
14750
+ actionOrigin: "keyboard_shortcut",
14384
14751
  event: keyboardEvent,
14385
14752
  requester: document.activeElement,
14386
14753
  confirmMessage: shortcutCandidate.confirmMessage,
14387
- actionOrigin: "keyboard_shortcut",
14388
14754
  meta: {
14389
14755
  shortcut: shortcutCandidate,
14390
14756
  },
@@ -18276,33 +18642,33 @@ const SummaryMarker = ({
18276
18642
 
18277
18643
  installImportMetaCss(import.meta);import.meta.css = /* css */`
18278
18644
  .navi_details {
18279
- display: flex;
18280
- flex-direction: column;
18281
18645
  position: relative;
18282
18646
  z-index: 1;
18647
+ display: flex;
18283
18648
  flex-shrink: 0;
18649
+ flex-direction: column;
18284
18650
  }
18285
18651
 
18286
18652
  .navi_details > summary {
18287
- flex-shrink: 0;
18288
- cursor: pointer;
18289
18653
  display: flex;
18654
+ flex-shrink: 0;
18290
18655
  flex-direction: column;
18656
+ cursor: pointer;
18291
18657
  user-select: none;
18292
18658
  }
18293
18659
  .summary_body {
18294
18660
  display: flex;
18661
+ width: 100%;
18295
18662
  flex-direction: row;
18296
18663
  align-items: center;
18297
- width: 100%;
18298
18664
  gap: 0.2em;
18299
18665
  }
18300
18666
  .summary_label {
18301
18667
  display: flex;
18668
+ padding-right: 10px;
18302
18669
  flex: 1;
18303
- gap: 0.2em;
18304
18670
  align-items: center;
18305
- padding-right: 10px;
18671
+ gap: 0.2em;
18306
18672
  }
18307
18673
 
18308
18674
  .navi_details > summary:focus {
@@ -18477,7 +18843,6 @@ const DetailsWithAction = forwardRef((props, ref) => {
18477
18843
  const isOpen = toggleEvent.newState === "open";
18478
18844
  if (isOpen) {
18479
18845
  requestAction(toggleEvent.target, effectiveAction, {
18480
- actionOrigin: "action_prop",
18481
18846
  event: toggleEvent,
18482
18847
  method: "run"
18483
18848
  });
@@ -20490,8 +20855,7 @@ const InputCheckboxWithAction = forwardRef((props, ref) => {
20490
20855
  loading: loading || actionLoading,
20491
20856
  onChange: e => {
20492
20857
  requestAction(e.target, actionBoundToUIState, {
20493
- event: e,
20494
- actionOrigin: "action_prop"
20858
+ event: e
20495
20859
  });
20496
20860
  onChange?.(e);
20497
20861
  }
@@ -21127,8 +21491,6 @@ const InputTextualWithAction = forwardRef((props, ref) => {
21127
21491
  cancelOnBlurInvalid,
21128
21492
  cancelOnEscape,
21129
21493
  actionErrorEffect,
21130
- onInput,
21131
- onKeyDown,
21132
21494
  ...rest
21133
21495
  } = props;
21134
21496
  const innerRef = useRef(null);
@@ -21140,17 +21502,6 @@ const InputTextualWithAction = forwardRef((props, ref) => {
21140
21502
  const executeAction = useExecuteAction(innerRef, {
21141
21503
  errorEffect: actionErrorEffect
21142
21504
  });
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
21505
  // here updating the input won't call the associated action
21155
21506
  // (user have to blur or press enter for this to happen)
21156
21507
  // so we can keep the ui state on cancel/abort/error and let user decide
@@ -21171,16 +21522,12 @@ const InputTextualWithAction = forwardRef((props, ref) => {
21171
21522
  if (!cancelOnEscape) {
21172
21523
  return;
21173
21524
  }
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
21525
  }
21182
21526
  onCancel?.(e, reason);
21183
21527
  },
21528
+ onRequested: e => {
21529
+ forwardActionRequested(e, boundAction);
21530
+ },
21184
21531
  onPrevented: onActionPrevented,
21185
21532
  onAction: executeAction,
21186
21533
  onStart: onActionStart,
@@ -21191,33 +21538,11 @@ const InputTextualWithAction = forwardRef((props, ref) => {
21191
21538
  "data-action": boundAction.name,
21192
21539
  ...rest,
21193
21540
  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
- }
21541
+ loading: loading || actionLoading
21216
21542
  });
21217
21543
  });
21218
21544
  const InputTextualInsideForm = forwardRef((props, ref) => {
21219
21545
  const {
21220
- onKeyDown,
21221
21546
  // We destructure formContext to avoid passing it to the underlying input element
21222
21547
  // eslint-disable-next-line no-unused-vars
21223
21548
  formContext,
@@ -21225,94 +21550,10 @@ const InputTextualInsideForm = forwardRef((props, ref) => {
21225
21550
  } = props;
21226
21551
  return jsx(InputTextualBasic, {
21227
21552
  ...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
- }
21553
+ ref: ref
21250
21554
  });
21251
21555
  });
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
21556
 
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
21557
  // As explained in https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/datetime-local#setting_timezones
21317
21558
  // datetime-local does not support timezones
21318
21559
  const convertToLocalTimezone = dateTimeString => {
@@ -21536,6 +21777,7 @@ const useFormEvents = (
21536
21777
  elementRef,
21537
21778
  {
21538
21779
  onFormReset,
21780
+ onFormActionRequested,
21539
21781
  onFormActionPrevented,
21540
21782
  onFormActionStart,
21541
21783
  onFormActionAbort,
@@ -21544,6 +21786,7 @@ const useFormEvents = (
21544
21786
  },
21545
21787
  ) => {
21546
21788
  onFormReset = useStableCallback(onFormReset);
21789
+ onFormActionRequested = useStableCallback(onFormActionRequested);
21547
21790
  onFormActionPrevented = useStableCallback(onFormActionPrevented);
21548
21791
  onFormActionStart = useStableCallback(onFormActionStart);
21549
21792
  onFormActionAbort = useStableCallback(onFormActionAbort);
@@ -21567,6 +21810,7 @@ const useFormEvents = (
21567
21810
  }
21568
21811
  return addManyEventListeners(form, {
21569
21812
  reset: onFormReset,
21813
+ actionrequested: onFormActionRequested,
21570
21814
  actionprevented: onFormActionPrevented,
21571
21815
  actionstart: onFormActionStart,
21572
21816
  actionabort: onFormActionAbort,
@@ -21575,6 +21819,7 @@ const useFormEvents = (
21575
21819
  });
21576
21820
  }, [
21577
21821
  onFormReset,
21822
+ onFormActionRequested,
21578
21823
  onFormActionPrevented,
21579
21824
  onFormActionStart,
21580
21825
  onFormActionAbort,
@@ -21821,7 +22066,6 @@ const ButtonWithAction = forwardRef((props, ref) => {
21821
22066
  const {
21822
22067
  action,
21823
22068
  loading,
21824
- onClick,
21825
22069
  actionErrorEffect,
21826
22070
  onActionPrevented,
21827
22071
  onActionStart,
@@ -21839,22 +22083,15 @@ const ButtonWithAction = forwardRef((props, ref) => {
21839
22083
  const executeAction = useExecuteAction(innerRef, {
21840
22084
  errorEffect: actionErrorEffect
21841
22085
  });
22086
+ const innerLoading = loading || actionLoading;
21842
22087
  useActionEvents(innerRef, {
21843
22088
  onPrevented: onActionPrevented,
22089
+ onRequested: e => forwardActionRequested(e, boundAction),
21844
22090
  onAction: executeAction,
21845
22091
  onStart: onActionStart,
21846
22092
  onError: onActionError,
21847
22093
  onEnd: onActionEnd
21848
22094
  });
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
22095
  return jsx(ButtonBasic
21859
22096
  // put data-action first to help find it in devtools
21860
22097
  , {
@@ -21862,10 +22099,6 @@ const ButtonWithAction = forwardRef((props, ref) => {
21862
22099
  ...rest,
21863
22100
  ref: innerRef,
21864
22101
  loading: innerLoading,
21865
- onClick: event => {
21866
- handleClick(event);
21867
- onClick?.(event);
21868
- },
21869
22102
  children: children
21870
22103
  });
21871
22104
  });
@@ -21874,7 +22107,6 @@ const ButtonInsideForm = forwardRef((props, ref) => {
21874
22107
  // eslint-disable-next-line no-unused-vars
21875
22108
  formContext,
21876
22109
  type,
21877
- onClick,
21878
22110
  children,
21879
22111
  loading,
21880
22112
  readOnly,
@@ -21882,50 +22114,14 @@ const ButtonInsideForm = forwardRef((props, ref) => {
21882
22114
  } = props;
21883
22115
  const innerRef = useRef();
21884
22116
  useImperativeHandle(ref, () => innerRef.current);
21885
- const wouldSubmitFormByType = type === "submit" || type === "image";
21886
22117
  const innerLoading = loading;
21887
22118
  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
22119
  return jsx(ButtonBasic, {
21920
22120
  ...rest,
21921
22121
  ref: innerRef,
21922
22122
  type: type,
21923
22123
  loading: innerLoading,
21924
22124
  readOnly: innerReadOnly,
21925
- onClick: event => {
21926
- handleClick(event);
21927
- onClick?.(event);
21928
- },
21929
22125
  children: children
21930
22126
  });
21931
22127
  });
@@ -21939,7 +22135,6 @@ const ButtonWithActionInsideForm = forwardRef((props, ref) => {
21939
22135
  action,
21940
22136
  loading,
21941
22137
  children,
21942
- onClick,
21943
22138
  onActionPrevented,
21944
22139
  onActionStart,
21945
22140
  onActionAbort,
@@ -21988,16 +22183,8 @@ const ButtonWithActionInsideForm = forwardRef((props, ref) => {
21988
22183
  ref: innerRef,
21989
22184
  type: type,
21990
22185
  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);
22186
+ onactionrequested: e => {
22187
+ forwardActionRequested(e, actionBoundToFormParams, e.target.form);
22001
22188
  },
22002
22189
  children: children
22003
22190
  });
@@ -22148,8 +22335,7 @@ const CheckboxListWithAction = forwardRef((props, ref) => {
22148
22335
  const checkbox = event.target;
22149
22336
  requestAction(checkboxList, boundAction, {
22150
22337
  event,
22151
- requester: checkbox,
22152
- actionOrigin: "action_prop"
22338
+ requester: checkbox
22153
22339
  });
22154
22340
  },
22155
22341
  loading: loading || actionLoading,
@@ -22374,13 +22560,7 @@ const FormWithAction = forwardRef((props, ref) => {
22374
22560
  useActionEvents(innerRef, {
22375
22561
  onPrevented: onActionPrevented,
22376
22562
  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
- });
22563
+ forwardActionRequested(e, actionBoundToUIState);
22384
22564
  },
22385
22565
  onAction: e => {
22386
22566
  const form = innerRef.current;
@@ -22416,15 +22596,6 @@ const FormWithAction = forwardRef((props, ref) => {
22416
22596
  ...rest,
22417
22597
  ref: innerRef,
22418
22598
  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
22599
  children: jsx(FormActionContext.Provider, {
22429
22600
  value: actionBoundToUIState,
22430
22601
  children: jsx(LoadingElementContext.Provider, {
@@ -22591,8 +22762,7 @@ const RadioListWithAction = forwardRef((props, ref) => {
22591
22762
  const radioListContainer = innerRef.current;
22592
22763
  requestAction(radioListContainer, boundAction, {
22593
22764
  event: e,
22594
- requester: radio,
22595
- actionOrigin: "action_prop"
22765
+ requester: radio
22596
22766
  });
22597
22767
  },
22598
22768
  loading: loading || actionLoading,
@@ -22800,8 +22970,7 @@ const SelectWithAction = forwardRef((props, ref) => {
22800
22970
  const optionSelected = select.querySelector(`option[value="${selectedValue}"]`);
22801
22971
  requestAction(radioListContainer, boundAction, {
22802
22972
  event,
22803
- requester: optionSelected,
22804
- actionOrigin: "action_prop"
22973
+ requester: optionSelected
22805
22974
  });
22806
22975
  },
22807
22976
  ...rest,
@@ -28522,4 +28691,4 @@ const useDependenciesDiff = (inputs) => {
28522
28691
  return diffRef.current;
28523
28692
  };
28524
28693
 
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 };
28694
+ 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 };