UNPKG

react-unprop

Version:

A lightweight React signal system for sharing reactive state across components — no prop drilling, no context, no global state libraries. Just pure reactivity with persistent storage.

105 lines (103 loc) 3.96 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { createSignal: () => createSignal, useSignal: () => useSignal }); module.exports = __toCommonJS(index_exports); var import_react = require("react"); var import_crypto_js = __toESM(require("crypto-js")); var subscribers = /* @__PURE__ */ new Map(); var DEFAULT_SECRET = "__signal_package_secret__"; var isBrowser = typeof window !== "undefined"; var encrypt = (data, secret) => import_crypto_js.default.AES.encrypt(JSON.stringify(data), secret).toString(); var decrypt = (cipher, secret) => JSON.parse(import_crypto_js.default.AES.decrypt(cipher, secret).toString(import_crypto_js.default.enc.Utf8)); function createSignal(initialValue, options = {}) { let value = initialValue; const key = Symbol("signal"); subscribers.set(key, /* @__PURE__ */ new Set()); const { persistKey, encrypted = false, secret = DEFAULT_SECRET } = options; const load = (raw) => { if (!raw) return; try { value = encrypted ? decrypt(raw, secret) : JSON.parse(raw); } catch (e) { console.warn("[createSignal] Failed to parse persisted value:", e); } }; if (isBrowser && persistKey) { try { load(localStorage.getItem(persistKey)); window.addEventListener("storage", (e) => { if (e.key === persistKey && e.newValue !== e.oldValue) { load(e.newValue); subscribers.get(key)?.forEach((cb) => cb()); } }); } catch (e) { console.warn("[createSignal] Browser storage unavailable:", e); } } const get = () => value; const set = (next) => { const newValue = typeof next === "function" ? next(value) : next; if (newValue !== value) { value = newValue; if (isBrowser && persistKey) { try { const toStore = encrypted ? encrypt(value, secret) : JSON.stringify(value); localStorage.setItem(persistKey, toStore); } catch (e) { console.warn("[createSignal] Persist failed:", e); } } subscribers.get(key)?.forEach((cb) => cb()); } }; const subscribe = (cb) => { subscribers.get(key)?.add(cb); return () => subscribers.get(key)?.delete(cb); }; return { get, set, subscribe }; } function useSignal(signal) { return (0, import_react.useSyncExternalStore)( signal.subscribe, signal.get, // Server snapshot - same as client snapshot for consistent hydration signal.get ); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createSignal, useSignal });