mirror of
https://github.com/withastro/astro.git
synced 2025-01-13 22:11:20 -05:00
Respect forms with enctype set for view transitions
This commit is contained in:
parent
429be8cc3e
commit
6d3e04a959
4 changed files with 22 additions and 11 deletions
packages/astro
|
@ -117,7 +117,18 @@ const { fallback = 'animate' } = Astro.props;
|
||||||
url.search = params.toString();
|
url.search = params.toString();
|
||||||
action = url.toString();
|
action = url.toString();
|
||||||
} else {
|
} else {
|
||||||
options.formData = formData;
|
// Form elements without enctype explicitly set default to application/x-www-form-urlencoded.
|
||||||
|
// In order to maintain compatibility with Astro 4.x, we need to check the value of enctype
|
||||||
|
// on the attributes property rather than accessing .enctype directly. Astro 5.x may
|
||||||
|
// introduce defaulting to application/x-www-form-urlencoded as a breaking change, and then
|
||||||
|
// we can access .enctype directly.
|
||||||
|
//
|
||||||
|
// Note: getNamedItem can return null in real life, even if TypeScript doesn't think so.
|
||||||
|
const enctype = form.attributes.getNamedItem('enctype')?.value;
|
||||||
|
options.body =
|
||||||
|
enctype === 'application/x-www-form-urlencoded'
|
||||||
|
? new URLSearchParams(formData as any)
|
||||||
|
: formData;
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
|
|
@ -66,7 +66,7 @@ export const isTransitionBeforePreparationEvent = (
|
||||||
value: any
|
value: any
|
||||||
): value is TransitionBeforePreparationEvent => value.type === TRANSITION_BEFORE_PREPARATION;
|
): value is TransitionBeforePreparationEvent => value.type === TRANSITION_BEFORE_PREPARATION;
|
||||||
export class TransitionBeforePreparationEvent extends BeforeEvent {
|
export class TransitionBeforePreparationEvent extends BeforeEvent {
|
||||||
formData: FormData | undefined;
|
body: FormData | URLSearchParams | undefined;
|
||||||
loader: () => Promise<void>;
|
loader: () => Promise<void>;
|
||||||
constructor(
|
constructor(
|
||||||
from: URL,
|
from: URL,
|
||||||
|
@ -76,7 +76,7 @@ export class TransitionBeforePreparationEvent extends BeforeEvent {
|
||||||
sourceElement: Element | undefined,
|
sourceElement: Element | undefined,
|
||||||
info: any,
|
info: any,
|
||||||
newDocument: Document,
|
newDocument: Document,
|
||||||
formData: FormData | undefined,
|
body: FormData | URLSearchParams | undefined,
|
||||||
loader: (event: TransitionBeforePreparationEvent) => Promise<void>
|
loader: (event: TransitionBeforePreparationEvent) => Promise<void>
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
|
@ -90,7 +90,7 @@ export class TransitionBeforePreparationEvent extends BeforeEvent {
|
||||||
info,
|
info,
|
||||||
newDocument
|
newDocument
|
||||||
);
|
);
|
||||||
this.formData = formData;
|
this.body = body;
|
||||||
this.loader = loader.bind(this, this);
|
this.loader = loader.bind(this, this);
|
||||||
Object.defineProperties(this, {
|
Object.defineProperties(this, {
|
||||||
formData: { enumerable: true },
|
formData: { enumerable: true },
|
||||||
|
@ -145,7 +145,7 @@ export async function doPreparation(
|
||||||
navigationType: NavigationTypeString,
|
navigationType: NavigationTypeString,
|
||||||
sourceElement: Element | undefined,
|
sourceElement: Element | undefined,
|
||||||
info: any,
|
info: any,
|
||||||
formData: FormData | undefined,
|
body: FormData | URLSearchParams | undefined,
|
||||||
defaultLoader: (event: TransitionBeforePreparationEvent) => Promise<void>
|
defaultLoader: (event: TransitionBeforePreparationEvent) => Promise<void>
|
||||||
) {
|
) {
|
||||||
const event = new TransitionBeforePreparationEvent(
|
const event = new TransitionBeforePreparationEvent(
|
||||||
|
@ -156,7 +156,7 @@ export async function doPreparation(
|
||||||
sourceElement,
|
sourceElement,
|
||||||
info,
|
info,
|
||||||
window.document,
|
window.document,
|
||||||
formData,
|
body,
|
||||||
defaultLoader
|
defaultLoader
|
||||||
);
|
);
|
||||||
if (document.dispatchEvent(event)) {
|
if (document.dispatchEvent(event)) {
|
||||||
|
|
|
@ -449,7 +449,7 @@ async function transition(
|
||||||
navigationType,
|
navigationType,
|
||||||
options.sourceElement,
|
options.sourceElement,
|
||||||
options.info,
|
options.info,
|
||||||
options.formData,
|
options.body,
|
||||||
defaultLoader
|
defaultLoader
|
||||||
);
|
);
|
||||||
if (prepEvent.defaultPrevented) {
|
if (prepEvent.defaultPrevented) {
|
||||||
|
@ -460,9 +460,9 @@ async function transition(
|
||||||
async function defaultLoader(preparationEvent: TransitionBeforePreparationEvent) {
|
async function defaultLoader(preparationEvent: TransitionBeforePreparationEvent) {
|
||||||
const href = preparationEvent.to.href;
|
const href = preparationEvent.to.href;
|
||||||
const init: RequestInit = {};
|
const init: RequestInit = {};
|
||||||
if (preparationEvent.formData) {
|
if (preparationEvent.body) {
|
||||||
init.method = 'POST';
|
init.method = 'POST';
|
||||||
init.body = preparationEvent.formData;
|
init.body = preparationEvent.body;
|
||||||
}
|
}
|
||||||
const response = await fetchHTML(href, init);
|
const response = await fetchHTML(href, init);
|
||||||
// If there is a problem fetching the new page, just do an MPA navigation to it.
|
// If there is a problem fetching the new page, just do an MPA navigation to it.
|
||||||
|
@ -488,7 +488,7 @@ async function transition(
|
||||||
// Unless this was a form submission, in which case we do not want to trigger another mutation.
|
// Unless this was a form submission, in which case we do not want to trigger another mutation.
|
||||||
if (
|
if (
|
||||||
!preparationEvent.newDocument.querySelector('[name="astro-view-transitions-enabled"]') &&
|
!preparationEvent.newDocument.querySelector('[name="astro-view-transitions-enabled"]') &&
|
||||||
!preparationEvent.formData
|
!preparationEvent.body
|
||||||
) {
|
) {
|
||||||
preparationEvent.preventDefault();
|
preparationEvent.preventDefault();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -5,6 +5,6 @@ export type Options = {
|
||||||
history?: 'auto' | 'push' | 'replace';
|
history?: 'auto' | 'push' | 'replace';
|
||||||
info?: any;
|
info?: any;
|
||||||
state?: any;
|
state?: any;
|
||||||
formData?: FormData;
|
body?: FormData | URLSearchParams;
|
||||||
sourceElement?: Element; // more than HTMLElement, e.g. SVGAElement
|
sourceElement?: Element; // more than HTMLElement, e.g. SVGAElement
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue