@@ -2461,36 +2461,36 @@ function lanesToEventPriority(lanes) {
24612461 return IdleEventPriority;
24622462}
24632463
2464- function noop$3 () {}
2464+ function noop$4 () {}
24652465
24662466var DefaultDispatcher = {
24672467 f
24682468 /* flushSyncWork */
2469- : noop$3 ,
2469+ : noop$4 ,
24702470 r
24712471 /* requestFormReset */
2472- : noop$3 ,
2472+ : noop$4 ,
24732473 D
24742474 /* prefetchDNS */
2475- : noop$3 ,
2475+ : noop$4 ,
24762476 C
24772477 /* preconnect */
2478- : noop$3 ,
2478+ : noop$4 ,
24792479 L
24802480 /* preload */
2481- : noop$3 ,
2481+ : noop$4 ,
24822482 m
24832483 /* preloadModule */
2484- : noop$3 ,
2484+ : noop$4 ,
24852485 X
24862486 /* preinitScript */
2487- : noop$3 ,
2487+ : noop$4 ,
24882488 S
24892489 /* preinitStyle */
2490- : noop$3 ,
2490+ : noop$4 ,
24912491 M
24922492 /* preinitModuleScript */
2493- : noop$3
2493+ : noop$4
24942494};
24952495var Internals = {
24962496 Events: null,
@@ -8568,6 +8568,9 @@ transition) {
85688568
85698569 return currentEventTransitionLane;
85708570}
8571+ function didCurrentEventScheduleTransition() {
8572+ return currentEventTransitionLane !== NoLane;
8573+ }
85718574
85728575// transition updates that occur while the async action is still in progress
85738576// are treated as part of the action.
@@ -9570,7 +9573,7 @@ function isThenableResolved(thenable) {
95709573 return status === 'fulfilled' || status === 'rejected';
95719574}
95729575
9573- function noop$2 () {}
9576+ function noop$3 () {}
95749577
95759578function trackUsedThenable(thenableState, thenable, index) {
95769579 if (ReactSharedInternals.actQueue !== null) {
@@ -9613,7 +9616,7 @@ function trackUsedThenable(thenableState, thenable, index) {
96139616 // intentionally ignore.
96149617
96159618
9616- thenable.then(noop$2 , noop$2 );
9619+ thenable.then(noop$3 , noop$3 );
96179620 thenable = previous;
96189621 }
96199622 } // We use an expando to track the status and result of a thenable so that we
@@ -9646,7 +9649,7 @@ function trackUsedThenable(thenableState, thenable, index) {
96469649 // some custom userspace implementation. We treat it as "pending".
96479650 // Attach a dummy listener, to ensure that any lazy initialization can
96489651 // happen. Flight lazily parses JSON when the value is actually awaited.
9649- thenable.then(noop$2 , noop$2 );
9652+ thenable.then(noop$3 , noop$3 );
96509653 } else {
96519654 // This is an uncached thenable that we haven't seen before.
96529655 // Detect infinite ping loops caused by uncached promises.
@@ -13481,20 +13484,25 @@ function startTransition(fiber, queue, pendingState, finishedState, callback, op
1348113484 }
1348213485}
1348313486
13484- function startHostTransition(formFiber, pendingState, callback, formData) {
13487+ var noop$2 = function () {};
13488+
13489+ function startHostTransition(formFiber, pendingState, action, formData) {
1348513490
1348613491 if (formFiber.tag !== HostComponent) {
1348713492 throw new Error('Expected the form instance to be a HostComponent. This ' + 'is a bug in React.');
1348813493 }
1348913494
1349013495 var stateHook = ensureFormComponentIsStateful(formFiber);
1349113496 var queue = stateHook.queue;
13492- startTransition(formFiber, queue, pendingState, NotPendingTransition, // TODO: We can avoid this extra wrapper, somehow. Figure out layering
13493- // once more of this function is implemented.
13494- function () {
13497+ startTransition(formFiber, queue, pendingState, NotPendingTransition, // TODO: `startTransition` both sets the pending state and dispatches
13498+ // the action, if one is provided. Consider refactoring these two
13499+ // concerns to avoid the extra lambda.
13500+ action === null ? // No action was provided, but we still call `startTransition` to
13501+ // set the pending form status.
13502+ noop$2 : function () {
1349513503 // Automatically reset the form when the action completes.
1349613504 requestFormReset$1(formFiber);
13497- return callback (formData);
13505+ return action (formData);
1349813506 });
1349913507}
1350013508
@@ -30838,7 +30846,7 @@ identifierPrefix, onUncaughtError, onCaughtError, onRecoverableError, transition
3083830846 return root;
3083930847}
3084030848
30841- var ReactVersion = '19.0.0-www-classic-f43a9c2f ';
30849+ var ReactVersion = '19.0.0-www-classic-54329650 ';
3084230850
3084330851function createPortal$1(children, containerInfo, // TODO: figure out the API for cross-renderer implementation.
3084430852implementation) {
@@ -33892,11 +33900,49 @@ function extractEvents$2(dispatchQueue, domEventName, targetInst, nativeEvent, n
3389233900 }
3389333901}
3389433902
33903+ function coerceFormActionProp(actionProp) {
33904+ // This should match the logic in ReactDOMComponent
33905+ if (actionProp == null || typeof actionProp === 'symbol' || typeof actionProp === 'boolean') {
33906+ return null;
33907+ } else if (typeof actionProp === 'function') {
33908+ return actionProp;
33909+ } else {
33910+ {
33911+ checkAttributeStringCoercion(actionProp, 'action');
33912+ }
33913+
33914+ return sanitizeURL(enableTrustedTypesIntegration ? actionProp : '' + actionProp);
33915+ }
33916+ }
33917+
33918+ function createFormDataWithSubmitter(form, submitter) {
33919+ // The submitter's value should be included in the FormData.
33920+ // It should be in the document order in the form.
33921+ // Since the FormData constructor invokes the formdata event it also
33922+ // needs to be available before that happens so after construction it's too
33923+ // late. We use a temporary fake node for the duration of this event.
33924+ // TODO: FormData takes a second argument that it's the submitter but this
33925+ // is fairly new so not all browsers support it yet. Switch to that technique
33926+ // when available.
33927+ var temp = submitter.ownerDocument.createElement('input');
33928+ temp.name = submitter.name;
33929+ temp.value = submitter.value;
33930+
33931+ if (form.id) {
33932+ temp.setAttribute('form', form.id);
33933+ }
33934+
33935+ submitter.parentNode.insertBefore(temp, submitter);
33936+ var formData = new FormData(form);
33937+ temp.parentNode.removeChild(temp);
33938+ return formData;
33939+ }
3389533940/**
3389633941 * This plugin invokes action functions on forms, inputs and buttons if
3389733942 * the form doesn't prevent default.
3389833943 */
3389933944
33945+
3390033946function extractEvents$1(dispatchQueue, domEventName, maybeTargetInst, nativeEvent, nativeEventTarget, eventSystemFlags, targetContainer) {
3390133947 if (domEventName !== 'submit') {
3390233948 return;
@@ -33910,15 +33956,16 @@ function extractEvents$1(dispatchQueue, domEventName, maybeTargetInst, nativeEve
3391033956
3391133957 var formInst = maybeTargetInst;
3391233958 var form = nativeEventTarget;
33913- var action = getFiberCurrentPropsFromNode(form).action;
33959+ var action = coerceFormActionProp( getFiberCurrentPropsFromNode(form).action) ;
3391433960 var submitter = nativeEvent.submitter;
3391533961 var submitterAction;
3391633962
3391733963 if (submitter) {
3391833964 var submitterProps = getFiberCurrentPropsFromNode(submitter);
33919- submitterAction = submitterProps ? submitterProps.formAction : submitter.getAttribute('formAction');
33965+ submitterAction = submitterProps ? coerceFormActionProp(submitterProps.formAction) : // The built-in Flow type is ?string, wider than the spec
33966+ submitter.getAttribute('formAction');
3392033967
33921- if (submitterAction != null) {
33968+ if (submitterAction !== null) {
3392233969 // The submitter overrides the form action.
3392333970 action = submitterAction; // If the action is a function, we don't want to pass its name
3392433971 // value to the FormData since it's controlled by the server.
@@ -33927,58 +33974,53 @@ function extractEvents$1(dispatchQueue, domEventName, maybeTargetInst, nativeEve
3392733974 }
3392833975 }
3392933976
33930- if (typeof action !== 'function') {
33931- return;
33932- }
33933-
3393433977 var event = new SyntheticEvent('action', 'action', null, nativeEvent, nativeEventTarget);
3393533978
3393633979 function submitForm() {
3393733980 if (nativeEvent.defaultPrevented) {
33938- // We let earlier events to prevent the action from submitting.
33939- return;
33940- } // Prevent native navigation.
33941-
33942-
33943- event.preventDefault();
33944- var formData;
33981+ // An earlier event prevented form submission. If a transition update was
33982+ // also scheduled, we should trigger a pending form status — even if
33983+ // no action function was provided.
33984+ if (didCurrentEventScheduleTransition()) {
33985+ // We're going to set the pending form status, but because the submission
33986+ // was prevented, we should not fire the action function.
33987+ var formData = submitter ? createFormDataWithSubmitter(form, submitter) : new FormData(form);
33988+ var pendingState = {
33989+ pending: true,
33990+ data: formData,
33991+ method: form.method,
33992+ action: action
33993+ };
3394533994
33946- if (submitter) {
33947- // The submitter's value should be included in the FormData.
33948- // It should be in the document order in the form.
33949- // Since the FormData constructor invokes the formdata event it also
33950- // needs to be available before that happens so after construction it's too
33951- // late. We use a temporary fake node for the duration of this event.
33952- // TODO: FormData takes a second argument that it's the submitter but this
33953- // is fairly new so not all browsers support it yet. Switch to that technique
33954- // when available.
33955- var temp = submitter.ownerDocument.createElement('input');
33956- temp.name = submitter.name;
33957- temp.value = submitter.value;
33995+ {
33996+ Object.freeze(pendingState);
33997+ }
3395833998
33959- if (form.id) {
33960- temp.setAttribute('form', form.id);
33999+ startHostTransition(formInst, pendingState, // Pass `null` as the action
34000+ // TODO: Consider splitting up startHostTransition into two separate
34001+ // functions, one that sets the form status and one that invokes
34002+ // the action.
34003+ null, formData);
3396134004 }
34005+ } else if (typeof action === 'function') {
34006+ // A form action was provided. Prevent native navigation.
34007+ event.preventDefault(); // Dispatch the action and set a pending form status.
3396234008
33963- submitter.parentNode.insertBefore(temp, submitter);
33964- formData = new FormData(form);
33965- temp.parentNode.removeChild(temp);
33966- } else {
33967- formData = new FormData(form);
33968- }
34009+ var _formData = submitter ? createFormDataWithSubmitter(form, submitter) : new FormData(form);
3396934010
33970- var pendingState = {
33971- pending: true,
33972- data: formData ,
33973- method: form.method,
33974- action: action
33975- };
34011+ var _pendingState = {
34012+ pending: true,
34013+ data: _formData ,
34014+ method: form.method,
34015+ action: action
34016+ };
3397634017
33977- {
33978- Object.freeze(pendingState );
33979- }
34018+ {
34019+ Object.freeze(_pendingState );
34020+ }
3398034021
33981- startHostTransition(formInst, pendingState, action, formData);
34022+ startHostTransition(formInst, _pendingState, action, _formData);
34023+ } else ;
3398234024 }
3398334025
3398434026 dispatchQueue.push({
0 commit comments