@hookform/lenses
Version:
Type-safe lenses for React Hook Form that enable precise control over nested form state. Build reusable form components with composable operations, array handling, and full TypeScript support.
202 lines (200 loc) • 6.1 kB
JavaScript
// src/LensCore.ts
import { get, set } from "react-hook-form";
var LensCore = class _LensCore {
constructor(control, path, cache) {
this.control = control;
this.path = path;
this.cache = cache;
}
static create(control, cache) {
return new _LensCore(control, "", cache);
}
focus(prop) {
var _a, _b, _c, _d, _e, _f;
const propString = prop.toString();
const nestedPath = this.path ? `${this.path}.${propString}` : propString;
const fromCache = (_a = this.cache) == null ? void 0 : _a.get(nestedPath);
if (fromCache) {
return fromCache;
}
if (Array.isArray(this.override)) {
const [template] = this.override;
const result2 = new _LensCore(this.control, nestedPath, this.cache);
result2.isArrayItemReflection = true;
result2.override = template;
(_b = this.cache) == null ? void 0 : _b.set(result2, nestedPath);
return result2;
} else if (this.override) {
const overriddenLens = get(this.override, propString);
if (!overriddenLens) {
const result2 = new _LensCore(this.control, nestedPath, this.cache);
(_c = this.cache) == null ? void 0 : _c.set(result2, nestedPath);
return result2;
}
if (this.isArrayItemReflection) {
const arrayItemNestedPath = `${this.path}.${overriddenLens.path}`;
const result2 = new _LensCore(this.control, arrayItemNestedPath, this.cache);
(_d = this.cache) == null ? void 0 : _d.set(result2, arrayItemNestedPath);
return result2;
} else {
(_e = this.cache) == null ? void 0 : _e.set(overriddenLens, nestedPath);
return overriddenLens;
}
}
const result = new _LensCore(this.control, nestedPath, this.cache);
(_f = this.cache) == null ? void 0 : _f.set(result, nestedPath);
return result;
}
reflect(getter) {
var _a, _b, _c;
const fromCache = (_a = this.cache) == null ? void 0 : _a.get(this.path, getter);
if (fromCache) {
return fromCache;
}
const template = new _LensCore(this.control, this.path, this.cache);
const dictionary = new Proxy(
{},
{
get: (target, prop) => {
if (typeof prop === "string") {
return template.focus(prop);
}
return target;
}
}
);
const override = getter(dictionary, template);
if (Array.isArray(override)) {
const result = new _LensCore(this.control, this.path, this.cache);
template.path = "";
result.override = getter(dictionary, template);
(_b = this.cache) == null ? void 0 : _b.set(result, this.path, getter);
return result;
} else {
template.override = override;
template.path = this.path;
(_c = this.cache) == null ? void 0 : _c.set(template, this.path, getter);
return template;
}
}
map(fields, mapper) {
return fields.map((value, index, array) => {
const item = this.focus(index.toString());
const res = mapper(value, item, index, array, this);
return res;
});
}
interop(cb) {
var _a;
if (cb) {
return cb(this.control, this.path);
}
(_a = this.interopCache) != null ? _a : this.interopCache = {
control: this.control,
name: this.path,
...this.override ? { getTransformer: this.getTransformer.bind(this), setTransformer: this.setTransformer.bind(this) } : {}
};
return this.interopCache;
}
getTransformer(value) {
const [template] = Array.isArray(this.override) ? this.override : [this.override];
if (!value || !template) {
return value;
}
const newValue = {};
Object.entries(template).forEach(([key, valueTemplate]) => {
const restructuredLens = valueTemplate;
if (!restructuredLens) {
return;
}
const v = get(value, restructuredLens.path);
set(newValue, key, v);
});
return newValue;
}
setTransformer(value) {
const [template] = Array.isArray(this.override) ? this.override : [this.override];
if (!value || !template) {
return value;
}
const newValue = {};
Object.entries(value).forEach(([key, value2]) => {
const restructuredLens = template[key];
if (!restructuredLens) {
return;
}
set(newValue, restructuredLens.path, value2);
});
return newValue;
}
};
// src/LensesStorage.ts
var LensesStorage = class {
constructor(control) {
var _a, _b, _c;
this.cache = /* @__PURE__ */ new Map();
(_c = (_b = (_a = control == null ? void 0 : control._subjects) == null ? void 0 : _a.values) == null ? void 0 : _b.subscribe) == null ? void 0 : _c.call(_b, {
next: () => {
control._names.unMount.forEach((name) => {
this.delete(name);
});
}
});
}
get(path, complexKey) {
const cached = this.cache.get(path);
if (cached) {
if (complexKey) {
return cached.complex.get(complexKey);
}
return cached.plain;
}
return void 0;
}
set(lens, path, complexKey) {
let cached = this.cache.get(path);
if (!cached) {
cached = {
complex: /* @__PURE__ */ new WeakMap()
};
this.cache.set(path, cached);
}
if (complexKey) {
cached.complex.set(complexKey, lens);
} else {
cached.plain = lens;
}
}
has(path, complexKey) {
var _a, _b;
if (complexKey) {
return (_b = (_a = this.cache.get(path)) == null ? void 0 : _a.complex.has(complexKey)) != null ? _b : false;
}
return this.cache.has(path);
}
delete(path) {
for (const key of this.cache.keys()) {
if (key.startsWith(path)) {
this.cache.delete(key);
}
}
}
clear() {
this.cache.clear();
}
};
// src/useLens.ts
import { useMemo } from "react";
function useLens(props, deps = []) {
return useMemo(() => {
const cache = new LensesStorage(props.control);
const lens = LensCore.create(props.control, cache);
return lens;
}, [props.control, ...deps]);
}
export {
LensCore,
LensesStorage,
useLens
};
//# sourceMappingURL=index.js.map