@westacks/vortex
Version:
Server-based routing for SPAs
209 lines (208 loc) • 6.72 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { b as signal, e as effect, i as isEqual } from "./page-ILOxo6kg.js";
import { a as axios } from "./router-CgFdQeyO.js";
class Form {
constructor(initial, handler) {
__publicField(this, "_defaults");
__publicField(this, "_transform");
__publicField(this, "_recentlySuccessfulTimeout", null);
__publicField(this, "_handler");
__publicField(this, "wasSuccessful", false);
__publicField(this, "recentlySuccessful", false);
__publicField(this, "processing", false);
__publicField(this, "errors", {});
this._defaults = initial;
this._handler = handler;
Object.defineProperty(this, "_defaults", { enumerable: false });
Object.defineProperty(this, "_transform", { enumerable: false });
Object.defineProperty(this, "_recentlySuccessfulTimeout", { enumerable: false });
Object.defineProperty(this, "_handler", { enumerable: false, writable: false, configurable: false });
this.reset();
}
get hasErrors() {
return Object.keys(this.errors).length > 0;
}
get isDirty() {
return !isEqual(this.data(), this._defaults);
}
data() {
const keys = Object.keys(this._defaults);
return keys.reduce((acc, key) => {
acc[key] = unwrap(this[key]);
return acc;
}, {});
}
transform(fn) {
this._transform = fn(this.data());
return this;
}
reset(...fields) {
const data = fields.length > 0 ? Object.keys(this._defaults).filter((key) => fields.includes(key)).reduce((obj, key) => {
obj[key] = this._defaults[key];
return obj;
}, {}) : this._defaults;
Object.assign(this, wrap(data, this._handler));
return this;
}
fill(data) {
Object.assign(this, wrap(data, this._handler));
return this;
}
defaults(field, value) {
if (typeof field === "string") {
field = { [field]: value };
}
if (!field) {
field = unwrap(Object.keys(this._defaults).reduce((obj, key) => {
obj[key] = this[key];
return obj;
}, {}));
}
this._defaults = { ...this._defaults, ...field };
return this;
}
clearErrors(...fields) {
if (fields.length === 0) {
this.errors = {};
} else for (const field of fields) {
delete this.errors[field];
}
return this;
}
setError(field, message) {
if (typeof field === "string") {
field = { [field]: message };
}
this.errors = { ...this.errors, ...field };
return this;
}
request(options) {
if (this._recentlySuccessfulTimeout) {
clearTimeout(this._recentlySuccessfulTimeout);
}
this.wasSuccessful = false;
this.processing = true;
let data = this._transform || this.data();
if (containsFile(data)) {
data = objectToFormData(data);
}
return axios.request({ ...options, data }).catch((error) => {
return Promise.reject(error);
}).then((response) => {
var _a, _b;
this.errors = ((_b = (_a = response == null ? void 0 : response.data) == null ? void 0 : _a.props) == null ? void 0 : _b.errors) ?? {};
if (Object.keys(this.errors).length === 0) {
this.wasSuccessful = true;
this.recentlySuccessful = true;
this._recentlySuccessfulTimeout = setTimeout(() => {
this.recentlySuccessful = false;
}, 2e3);
}
return response;
}).finally(() => {
this._transform = void 0;
this.processing = false;
});
}
get(url, options) {
return this.request({ ...options, url, method: "get" });
}
post(url, options) {
return this.request({ ...options, url, method: "post" });
}
put(url, options) {
return this.request({ ...options, url, method: "put" });
}
patch(url, options) {
return this.request({ ...options, url, method: "patch" });
}
delete(url, options) {
return this.request({ ...options, url, method: "delete" });
}
}
function useForm(data, rememberKey) {
data = typeof data === "function" ? data() : data;
const [get, set] = signal(void 0, isEqual);
const subscribe = (fn) => effect(() => fn(get()));
set(createProxy(data, set));
return { get, set, subscribe };
}
function createProxy(data, set) {
const handler = {
set(target, key, value, receiver) {
const changed = target[key] !== value;
const result = Reflect.set(target, key, value, receiver);
if (result && !key.startsWith("_")) {
set(proxy, changed);
}
return result;
}
};
const form = new Form(data, handler);
const proxy = new Proxy(form, handler);
return proxy;
}
function wrap(data, handler) {
if (typeof data !== "object" || data === null || data instanceof File || data instanceof Blob) {
return data;
}
if (Array.isArray(data)) {
return data.map((item) => wrap(item, handler));
}
return Object.entries(data).reduce(
(acc, [key, value]) => {
acc[key] = typeof value !== "object" || value === null ? value : new Proxy(wrap(value, handler), handler);
return acc;
},
{}
);
}
function unwrap(data) {
if (typeof data !== "object" || data === null || data instanceof File || data instanceof Blob) {
return data;
}
if (Array.isArray(data)) {
return data.map(unwrap);
}
return Object.keys(data).reduce((acc, key) => {
acc[key] = unwrap(data[key]);
return acc;
}, {});
}
function containsFile(obj) {
if (typeof obj !== "object" || obj === null) {
return false;
}
return Object.values(obj).some(
(item) => item instanceof File || item instanceof Blob ? true : containsFile(item)
);
}
function objectToFormData(obj, form = new FormData(), namespace = "") {
for (const key in obj) {
if (!Object.hasOwn(obj, key)) continue;
const value = obj[key];
const formKey = namespace ? `${namespace}[${key}]` : key;
if (value instanceof File || value instanceof Blob) {
form.append(formKey, value);
} else if (Array.isArray(value)) {
value.forEach((item, index) => {
const arrayKey = `${formKey}[${index}]`;
if (typeof item === "object" && item !== null) {
objectToFormData(item, form, arrayKey);
} else {
form.append(arrayKey, item);
}
});
} else if (typeof value === "object" && value !== null) {
objectToFormData(value, form, formKey);
} else if (value !== void 0 && value !== null) {
form.append(formKey, value);
}
}
return form;
}
export {
useForm as u
};