UNPKG

use-query-guard

Version:

A router-agnostic query-string management hook for React with Zod validation

129 lines (127 loc) 4.11 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { useQueryGuard: () => useQueryGuard }); module.exports = __toCommonJS(index_exports); // src/useQueryGuard.ts var import_react = require("react"); var import_zod = require("zod"); var browserAdapter = { getSearch: () => typeof window === "undefined" ? "" : window.location.search, setSearch: (next) => { if (typeof window === "undefined") return; const url = window.location.pathname + (next.startsWith("?") || next === "" ? next : `?${next}`) + window.location.hash; window.history.pushState(null, "", url); window.dispatchEvent(new Event("popstate")); }, subscribe: (cb) => { if (typeof window === "undefined") return () => { }; window.addEventListener("popstate", cb); return () => window.removeEventListener("popstate", cb); } }; function useQueryGuard(options) { const { resolver, preprocess, adapter = browserAdapter, mode = "pick" } = options ?? {}; const search = (0, import_react.useSyncExternalStore)( adapter.subscribe, adapter.getSearch, () => "" ); const [isReady, setReadyTrue] = (0, import_react.useReducer)(() => true, false); const { data, isError } = (0, import_react.useMemo)(() => { const usp = new URLSearchParams(search); const raw = {}; usp.forEach((value, key) => { raw[key] = preprocess ? preprocess(key, value) : value; }); setReadyTrue(); if (!resolver) { return { data: raw, isError: false }; } const converted = {}; for (const key of Object.keys(resolver.shape)) { const schema = resolver.shape[key]; const v = raw[key]; if (v === void 0) continue; converted[key] = schema instanceof import_zod.ZodNumber ? Number(v) : v; } const base = Object.fromEntries( Object.keys(resolver.shape).map((k) => [k, void 0]) ); if (mode === "pick") { let anyError = false; const picked = {}; for (const [key, schema] of Object.entries(resolver.shape)) { const val = converted[key]; if (val === void 0) continue; const r = schema.safeParse(val); if (r.success) picked[key] = r.data; else anyError = true; } return { data: { ...base, ...picked }, isError: anyError }; } else { const parsed = resolver.safeParse(converted); return { data: parsed.success ? { ...base, ...parsed.data } : base, isError: !parsed.success }; } }, [search, resolver, preprocess, mode]); const updateParams = (0, import_react.useCallback)( (params) => { const usp = new URLSearchParams(adapter.getSearch()); Object.entries(params).forEach(([k, v]) => { if (v === null || v === "") { usp.delete(k); } else if (v !== void 0) { usp.set(k, String(v)); } }); usp.sort(); const next = usp.toString(); const current = adapter.getSearch().replace(/^\?/, ""); if (next === current) return; adapter.setSearch(next); }, [adapter] ); return { data, isReady, isError, updateParams }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { useQueryGuard }); //# sourceMappingURL=index.cjs.map