next
Version:
The React Framework
158 lines (156 loc) • 7.37 kB
JavaScript
'use client';
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return Form;
}
});
const _jsxruntime = require("react/jsx-runtime");
const _react = require("react");
const _addbasepath = require("../add-base-path");
const _usemergedref = require("../use-merged-ref");
const _approutercontextsharedruntime = require("../../shared/lib/app-router-context.shared-runtime");
const _routerreducertypes = require("../components/router-reducer/router-reducer-types");
const _formshared = require("../form-shared");
const _links = require("../components/links");
function Form(param) {
let { replace, scroll, prefetch: prefetchProp, ref: externalRef, ...props } = param;
const router = (0, _react.useContext)(_approutercontextsharedruntime.AppRouterContext);
const actionProp = props.action;
const isNavigatingForm = typeof actionProp === 'string';
// Validate `action`
if (process.env.NODE_ENV === 'development') {
if (isNavigatingForm) {
(0, _formshared.checkFormActionUrl)(actionProp, 'action');
}
}
// Validate `prefetch`
if (process.env.NODE_ENV === 'development') {
if (!(prefetchProp === undefined || prefetchProp === false || prefetchProp === null)) {
console.error('The `prefetch` prop of <Form> must be `false` or `null`');
}
if (prefetchProp !== undefined && !isNavigatingForm) {
console.error('Passing `prefetch` to a <Form> whose `action` is a function has no effect.');
}
}
const prefetch = prefetchProp === false || prefetchProp === null ? prefetchProp : null;
// Validate `scroll` and `replace`
if (process.env.NODE_ENV === 'development') {
if (!isNavigatingForm && (replace !== undefined || scroll !== undefined)) {
console.error('Passing `replace` or `scroll` to a <Form> whose `action` is a function has no effect.\n' + 'See the relevant docs to learn how to control this behavior for navigations triggered from actions:\n' + ' `redirect()` - https://nextjs.org/docs/app/api-reference/functions/redirect#parameters\n' + ' `router.replace()` - https://nextjs.org/docs/app/api-reference/functions/use-router#userouter\n');
}
}
// Clean up any unsupported form props (and warn if present)
for (const key of _formshared.DISALLOWED_FORM_PROPS){
if (key in props) {
if (process.env.NODE_ENV === 'development') {
console.error("<Form> does not support changing `" + key + "`. " + (isNavigatingForm ? "If you'd like to use it to perform a mutation, consider making `action` a function instead.\n" + "Learn more: https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations" : ''));
}
delete props[key];
}
}
const isPrefetchEnabled = // if we don't have an action path, we can't prefetch anything.
!!router && isNavigatingForm && prefetch === null;
const observeFormVisibilityOnMount = (0, _react.useCallback)((element)=>{
if (isPrefetchEnabled && router !== null) {
(0, _links.mountFormInstance)(element, actionProp, router, _routerreducertypes.PrefetchKind.AUTO);
}
return ()=>{
(0, _links.unmountPrefetchableInstance)(element);
};
}, [
isPrefetchEnabled,
actionProp,
router
]);
const mergedRef = (0, _usemergedref.useMergedRef)(observeFormVisibilityOnMount, externalRef != null ? externalRef : null);
if (!isNavigatingForm) {
return /*#__PURE__*/ (0, _jsxruntime.jsx)("form", {
...props,
ref: mergedRef
});
}
const actionHref = (0, _addbasepath.addBasePath)(actionProp);
return /*#__PURE__*/ (0, _jsxruntime.jsx)("form", {
...props,
ref: mergedRef,
action: actionHref,
onSubmit: (event)=>onFormSubmit(event, {
router,
actionHref,
replace,
scroll,
onSubmit: props.onSubmit
})
});
}
function onFormSubmit(event, param) {
let { actionHref, onSubmit, replace, scroll, router } = param;
if (typeof onSubmit === 'function') {
onSubmit(event);
// if the user called event.preventDefault(), do nothing.
// (this matches what Link does for `onClick`)
if (event.defaultPrevented) {
return;
}
}
if (!router) {
// Form was somehow used outside of the router (but not in pages, the implementation is forked!).
// We can't perform a soft navigation, so let the native submit handling do its thing.
return;
}
const formElement = event.currentTarget;
const submitter = event.nativeEvent.submitter;
let action = actionHref;
if (submitter) {
if (process.env.NODE_ENV === 'development') {
// the way server actions are encoded (e.g. `formMethod="post")
// causes some unnecessary dev-mode warnings from `hasUnsupportedSubmitterAttributes`.
// we'd bail out anyway, but we just do it silently.
if (hasReactServerActionAttributes(submitter)) {
return;
}
}
if ((0, _formshared.hasUnsupportedSubmitterAttributes)(submitter)) {
return;
}
// client actions have `formAction="javascript:..."`. We obviously can't prefetch/navigate to that.
if ((0, _formshared.hasReactClientActionAttributes)(submitter)) {
return;
}
// If the submitter specified an alternate formAction,
// use that URL instead -- this is what a native form would do.
// NOTE: `submitter.formAction` is unreliable, because it will give us `location.href` if it *wasn't* set
// NOTE: this should not have `basePath` added, because we can't add it before hydration
const submitterFormAction = submitter.getAttribute('formAction');
if (submitterFormAction !== null) {
if (process.env.NODE_ENV === 'development') {
(0, _formshared.checkFormActionUrl)(submitterFormAction, 'formAction');
}
action = submitterFormAction;
}
}
const targetUrl = (0, _formshared.createFormSubmitDestinationUrl)(action, formElement);
// Finally, no more reasons for bailing out.
event.preventDefault();
const method = replace ? 'replace' : 'push';
const targetHref = targetUrl.href;
router[method](targetHref, {
scroll
});
}
function hasReactServerActionAttributes(submitter) {
// https://github.com/facebook/react/blob/942eb80381b96f8410eab1bef1c539bed1ab0eb1/packages/react-client/src/ReactFlightReplyClient.js#L931-L934
const name = submitter.getAttribute('name');
return name && (name.startsWith('$ACTION_ID_') || name.startsWith('$ACTION_REF_'));
}
if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') {
Object.defineProperty(exports.default, '__esModule', { value: true });
Object.assign(exports.default, exports);
module.exports = exports.default;
}
//# sourceMappingURL=form.js.map