react-router
Version:
Declarative routing for React
144 lines (138 loc) • 4.89 kB
JavaScript
/**
* react-router v8.0.0
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
import { warning } from "../router/history.js";
import { stripBasename } from "../router/utils.js";
const defaultEncType = "application/x-www-form-urlencoded";
function isHtmlElement(object) {
return typeof HTMLElement !== "undefined" && object instanceof HTMLElement;
}
function isButtonElement(object) {
return isHtmlElement(object) && object.tagName.toLowerCase() === "button";
}
function isFormElement(object) {
return isHtmlElement(object) && object.tagName.toLowerCase() === "form";
}
function isInputElement(object) {
return isHtmlElement(object) && object.tagName.toLowerCase() === "input";
}
function isModifiedEvent(event) {
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
}
function shouldProcessLinkClick(event, target) {
return event.button === 0 && (!target || target === "_self") && !isModifiedEvent(event);
}
/**
Creates a URLSearchParams object using the given initializer.
This is identical to `new URLSearchParams(init)` except it also
supports arrays as values in the object form of the initializer
instead of just strings. This is convenient when you need multiple
values for a given key, but don't want to use an array initializer.
For example, instead of:
```tsx
let searchParams = new URLSearchParams([
['sort', 'name'],
['sort', 'price']
]);
```
you can do:
```
let searchParams = createSearchParams({
sort: ['name', 'price']
});
```
@category Utils
*/
function createSearchParams(init = "") {
return new URLSearchParams(typeof init === "string" || Array.isArray(init) || init instanceof URLSearchParams ? init : Object.keys(init).reduce((memo, key) => {
let value = init[key];
return memo.concat(Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]);
}, []));
}
function getSearchParamsForLocation(locationSearch, defaultSearchParams) {
let searchParams = createSearchParams(locationSearch);
if (defaultSearchParams) defaultSearchParams.forEach((_, key) => {
if (!searchParams.has(key)) defaultSearchParams.getAll(key).forEach((value) => {
searchParams.append(key, value);
});
});
return searchParams;
}
let _formDataSupportsSubmitter = null;
function isFormDataSubmitterSupported() {
if (_formDataSupportsSubmitter === null) try {
new FormData(document.createElement("form"), 0);
_formDataSupportsSubmitter = false;
} catch (e) {
_formDataSupportsSubmitter = true;
}
return _formDataSupportsSubmitter;
}
const supportedFormEncTypes = new Set([
"application/x-www-form-urlencoded",
"multipart/form-data",
"text/plain"
]);
function getFormEncType(encType) {
if (encType != null && !supportedFormEncTypes.has(encType)) {
warning(false, `"${encType}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${defaultEncType}"`);
return null;
}
return encType;
}
function getFormSubmissionInfo(target, basename) {
let method;
let action;
let encType;
let formData;
let body;
if (isFormElement(target)) {
let attr = target.getAttribute("action");
action = attr ? stripBasename(attr, basename) : null;
method = target.getAttribute("method") || "get";
encType = getFormEncType(target.getAttribute("enctype")) || defaultEncType;
formData = new FormData(target);
} else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) {
let form = target.form;
if (form == null) throw new Error(`Cannot submit a <button> or <input type="submit"> without a <form>`);
let attr = target.getAttribute("formaction") || form.getAttribute("action");
action = attr ? stripBasename(attr, basename) : null;
method = target.getAttribute("formmethod") || form.getAttribute("method") || "get";
encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType;
formData = new FormData(form, target);
if (!isFormDataSubmitterSupported()) {
let { name, type, value } = target;
if (type === "image") {
let prefix = name ? `${name}.` : "";
formData.append(`${prefix}x`, "0");
formData.append(`${prefix}y`, "0");
} else if (name) formData.append(name, value);
}
} else if (isHtmlElement(target)) throw new Error("Cannot submit element that is not <form>, <button>, or <input type=\"submit|image\">");
else {
method = "get";
action = null;
encType = defaultEncType;
body = target;
}
if (formData && encType === "text/plain") {
body = formData;
formData = void 0;
}
return {
action,
method: method.toLowerCase(),
encType,
formData,
body
};
}
//#endregion
export { createSearchParams, getFormSubmissionInfo, getSearchParamsForLocation, shouldProcessLinkClick };