@solid-primitives/static-store
Advanced tools
+64
-60
@@ -1,65 +0,69 @@ | ||
| import { type SetterParam } from "@solid-primitives/utils"; | ||
| import { createMemo, type ComputeFunction, type NoInfer } from "solid-js"; | ||
| /* @ts-self-types="./index.d.ts" */ | ||
| import { SetterParam } from "@solid-primitives/utils"; | ||
| import { ComputeFunction, NoInfer, createMemo } from "solid-js"; | ||
| //#region src/index.d.ts | ||
| type Defined<T> = T extends undefined ? never : T; | ||
| export type MemoOptions<T> = Defined<Parameters<typeof createMemo<T>>[1]>; | ||
| export type StaticStoreSetter<T extends object> = { | ||
| (setter: (prev: T) => Partial<T>): T; | ||
| (state: Partial<T>): T; | ||
| <K extends keyof T>(key: K, state: SetterParam<T[K]>): T; | ||
| type MemoOptions<T> = Defined<Parameters<typeof createMemo<T>>[1]>; | ||
| type StaticStoreSetter<T extends object> = { | ||
| (setter: (prev: T) => Partial<T>): T; | ||
| (state: Partial<T>): T; | ||
| <K extends keyof T>(key: K, state: SetterParam<T[K]>): T; | ||
| }; | ||
| /** | ||
| * A shallowly wrapped reactive store object. It behaves similarly to the createStore, but with limited features to keep it simple. Designed to be used for reactive objects with static keys, but dynamic values, like reactive Event State, location, etc. | ||
| * @param init initial value of the store | ||
| * @returns tuple with the store object and a setter function | ||
| * ```ts | ||
| * [access: T, write: StaticStoreSetter<T>] | ||
| * ``` | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createStaticStore | ||
| * @example | ||
| * ```ts | ||
| * const [size, setSize] = createStaticStore({ width: 0, height: 0 }); | ||
| * | ||
| * el.addEventListener("resize", () => { | ||
| * setSize({ width: el.offsetWidth, height: el.offsetHeight }); | ||
| * }); | ||
| * | ||
| * createEffect(() => { | ||
| * console.log(size.width, size.height); | ||
| * }) | ||
| * ``` | ||
| */ | ||
| export declare function createStaticStore<T extends Record<string, Exclude<unknown, Function>>>(init: T): [access: T, write: StaticStoreSetter<T>]; | ||
| * A shallowly wrapped reactive store object. It behaves similarly to the createStore, but with limited features to keep it simple. Designed to be used for reactive objects with static keys, but dynamic values, like reactive Event State, location, etc. | ||
| * @param init initial value of the store | ||
| * @returns tuple with the store object and a setter function | ||
| * ```ts | ||
| * [access: T, write: StaticStoreSetter<T>] | ||
| * ``` | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createStaticStore | ||
| * @example | ||
| * ```ts | ||
| * const [size, setSize] = createStaticStore({ width: 0, height: 0 }); | ||
| * | ||
| * el.addEventListener("resize", () => { | ||
| * setSize({ width: el.offsetWidth, height: el.offsetHeight }); | ||
| * }); | ||
| * | ||
| * createEffect(() => { | ||
| * console.log(size.width, size.height); | ||
| * }) | ||
| * ``` | ||
| */ | ||
| declare function createStaticStore<T extends Record<string, Exclude<unknown, Function>>>(init: T): [access: T, write: StaticStoreSetter<T>]; | ||
| /** | ||
| * A hydratable version of the {@link createStaticStore}. It will use the {@link serverValue} on the server and the {@link update} function on the client. If initialized during hydration it will use {@link serverValue} as the initial value and update it once hydration is complete. | ||
| * | ||
| * @param serverValue initial value of the state on the server | ||
| * @param update called once on the client or on hydration to initialize the value | ||
| * @returns tuple with the store object and a setter function | ||
| * ```ts | ||
| * [access: T, write: StaticStoreSetter<T>] | ||
| * ``` | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createHydratableStaticStore | ||
| */ | ||
| export declare function createHydratableStaticStore<T extends Record<string, Exclude<unknown, Function>>>(serverValue: T, update: () => T): ReturnType<typeof createStaticStore<T>>; | ||
| * A hydratable version of the {@link createStaticStore}. It will use the {@link serverValue} on the server and the {@link update} function on the client. If initialized during hydration it will use {@link serverValue} as the initial value and update it once hydration is complete. | ||
| * | ||
| * @param serverValue initial value of the state on the server | ||
| * @param update called once on the client or on hydration to initialize the value | ||
| * @returns tuple with the store object and a setter function | ||
| * ```ts | ||
| * [access: T, write: StaticStoreSetter<T>] | ||
| * ``` | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createHydratableStaticStore | ||
| */ | ||
| declare function createHydratableStaticStore<T extends Record<string, Exclude<unknown, Function>>>(serverValue: T, update: () => T): ReturnType<typeof createStaticStore<T>>; | ||
| /** | ||
| * A derived version of the {@link createStaticStore}. It will use the update function to derive the value of the store. It will only update when the dependencies of the update function change. | ||
| * @param fn a reactive function to derive the value of the store | ||
| * @returns a shallow, reactive, static store object | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createDerivedStaticStore | ||
| * @example | ||
| * ```ts | ||
| * const [size, setSize] = createSignal({ width: 0, height: 0 }); | ||
| * | ||
| * el.addEventListener("resize", () => { | ||
| * setSize({ width: el.offsetWidth, height: el.offsetHeight }); | ||
| * }); | ||
| * | ||
| * const store = createDerivedStaticStore(size); | ||
| * | ||
| * createEffect(() => { | ||
| * console.log(store.width, store.height); | ||
| * }) | ||
| * ``` | ||
| */ | ||
| export declare function createDerivedStaticStore<Next extends Prev & object, Prev = Next>(fn: ComputeFunction<undefined | NoInfer<Prev>, Next>): Next; | ||
| export {}; | ||
| * A derived version of the {@link createStaticStore}. It will use the update function to derive the value of the store. It will only update when the dependencies of the update function change. | ||
| * @param fn a reactive function to derive the value of the store | ||
| * @returns a shallow, reactive, static store object | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createDerivedStaticStore | ||
| * @example | ||
| * ```ts | ||
| * const [size, setSize] = createSignal({ width: 0, height: 0 }); | ||
| * | ||
| * el.addEventListener("resize", () => { | ||
| * setSize({ width: el.offsetWidth, height: el.offsetHeight }); | ||
| * }); | ||
| * | ||
| * const store = createDerivedStaticStore(size); | ||
| * | ||
| * createEffect(() => { | ||
| * console.log(store.width, store.height); | ||
| * }) | ||
| * ``` | ||
| */ | ||
| declare function createDerivedStaticStore<Next extends Prev & object, Prev = Next>(fn: ComputeFunction<undefined | NoInfer<Prev>, Next>): Next; | ||
| //#endregion | ||
| export { MemoOptions, StaticStoreSetter, createDerivedStaticStore, createHydratableStaticStore, createStaticStore }; |
+102
-110
@@ -0,118 +1,110 @@ | ||
| /* @ts-self-types="./index.d.ts" */ | ||
| import { accessWith, isObject } from "@solid-primitives/utils"; | ||
| import { createMemo, createSignal, getObserver, onSettled, sharedConfig, untrack, } from "solid-js"; | ||
| import { createMemo, createSignal, getObserver, onSettled, sharedConfig, untrack } from "solid-js"; | ||
| import { isServer } from "@solidjs/web"; | ||
| //#region src/index.ts | ||
| /** | ||
| * A shallowly wrapped reactive store object. It behaves similarly to the createStore, but with limited features to keep it simple. Designed to be used for reactive objects with static keys, but dynamic values, like reactive Event State, location, etc. | ||
| * @param init initial value of the store | ||
| * @returns tuple with the store object and a setter function | ||
| * ```ts | ||
| * [access: T, write: StaticStoreSetter<T>] | ||
| * ``` | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createStaticStore | ||
| * @example | ||
| * ```ts | ||
| * const [size, setSize] = createStaticStore({ width: 0, height: 0 }); | ||
| * | ||
| * el.addEventListener("resize", () => { | ||
| * setSize({ width: el.offsetWidth, height: el.offsetHeight }); | ||
| * }); | ||
| * | ||
| * createEffect(() => { | ||
| * console.log(size.width, size.height); | ||
| * }) | ||
| * ``` | ||
| */ | ||
| export function createStaticStore(init) { | ||
| const copy = { ...init }, store = { ...init }, cache = {}; | ||
| const getValue = (key) => { | ||
| let signal = cache[key]; | ||
| if (!signal) { | ||
| if (!getObserver()) | ||
| return copy[key]; | ||
| cache[key] = signal = createSignal(copy[key], { ownedWrite: true }); | ||
| delete copy[key]; | ||
| } | ||
| return signal[0](); | ||
| }; | ||
| for (const key in init) { | ||
| Object.defineProperty(store, key, { get: () => getValue(key), enumerable: true }); | ||
| } | ||
| const setValue = (key, value) => { | ||
| const signal = cache[key]; | ||
| if (signal) | ||
| return signal[1](value); | ||
| if (key in copy) | ||
| copy[key] = accessWith(value, copy[key]); | ||
| }; | ||
| return [ | ||
| store, | ||
| (a, b) => { | ||
| if (isObject(a)) { | ||
| const entries = untrack(() => Object.entries(accessWith(a, store))); | ||
| for (const [key, value] of entries) | ||
| setValue(key, () => value); | ||
| } | ||
| else | ||
| setValue(a, b); | ||
| return store; | ||
| }, | ||
| ]; | ||
| * A shallowly wrapped reactive store object. It behaves similarly to the createStore, but with limited features to keep it simple. Designed to be used for reactive objects with static keys, but dynamic values, like reactive Event State, location, etc. | ||
| * @param init initial value of the store | ||
| * @returns tuple with the store object and a setter function | ||
| * ```ts | ||
| * [access: T, write: StaticStoreSetter<T>] | ||
| * ``` | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createStaticStore | ||
| * @example | ||
| * ```ts | ||
| * const [size, setSize] = createStaticStore({ width: 0, height: 0 }); | ||
| * | ||
| * el.addEventListener("resize", () => { | ||
| * setSize({ width: el.offsetWidth, height: el.offsetHeight }); | ||
| * }); | ||
| * | ||
| * createEffect(() => { | ||
| * console.log(size.width, size.height); | ||
| * }) | ||
| * ``` | ||
| */ | ||
| function createStaticStore(init) { | ||
| const copy = { ...init }, store = { ...init }, cache = {}; | ||
| const getValue = (key) => { | ||
| let signal = cache[key]; | ||
| if (!signal) { | ||
| if (!getObserver()) return copy[key]; | ||
| cache[key] = signal = createSignal(copy[key], { ownedWrite: true }); | ||
| delete copy[key]; | ||
| } | ||
| return signal[0](); | ||
| }; | ||
| for (const key in init) Object.defineProperty(store, key, { | ||
| get: () => getValue(key), | ||
| enumerable: true | ||
| }); | ||
| const setValue = (key, value) => { | ||
| const signal = cache[key]; | ||
| if (signal) return signal[1](value); | ||
| if (key in copy) copy[key] = accessWith(value, copy[key]); | ||
| }; | ||
| return [store, (a, b) => { | ||
| if (isObject(a)) { | ||
| const entries = untrack(() => Object.entries(accessWith(a, store))); | ||
| for (const [key, value] of entries) setValue(key, () => value); | ||
| } else setValue(a, b); | ||
| return store; | ||
| }]; | ||
| } | ||
| /** | ||
| * A hydratable version of the {@link createStaticStore}. It will use the {@link serverValue} on the server and the {@link update} function on the client. If initialized during hydration it will use {@link serverValue} as the initial value and update it once hydration is complete. | ||
| * | ||
| * @param serverValue initial value of the state on the server | ||
| * @param update called once on the client or on hydration to initialize the value | ||
| * @returns tuple with the store object and a setter function | ||
| * ```ts | ||
| * [access: T, write: StaticStoreSetter<T>] | ||
| * ``` | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createHydratableStaticStore | ||
| */ | ||
| export function createHydratableStaticStore(serverValue, update) { | ||
| if (isServer) | ||
| return createStaticStore(serverValue); | ||
| if (sharedConfig.hydrating) { | ||
| const [state, setState] = createStaticStore(serverValue); | ||
| onSettled(() => { setState(update()); }); | ||
| return [state, setState]; | ||
| } | ||
| return createStaticStore(update()); | ||
| * A hydratable version of the {@link createStaticStore}. It will use the {@link serverValue} on the server and the {@link update} function on the client. If initialized during hydration it will use {@link serverValue} as the initial value and update it once hydration is complete. | ||
| * | ||
| * @param serverValue initial value of the state on the server | ||
| * @param update called once on the client or on hydration to initialize the value | ||
| * @returns tuple with the store object and a setter function | ||
| * ```ts | ||
| * [access: T, write: StaticStoreSetter<T>] | ||
| * ``` | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createHydratableStaticStore | ||
| */ | ||
| function createHydratableStaticStore(serverValue, update) { | ||
| if (isServer) return createStaticStore(serverValue); | ||
| if (sharedConfig.hydrating) { | ||
| const [state, setState] = createStaticStore(serverValue); | ||
| onSettled(() => { | ||
| setState(update()); | ||
| }); | ||
| return [state, setState]; | ||
| } | ||
| return createStaticStore(update()); | ||
| } | ||
| /** | ||
| * A derived version of the {@link createStaticStore}. It will use the update function to derive the value of the store. It will only update when the dependencies of the update function change. | ||
| * @param fn a reactive function to derive the value of the store | ||
| * @returns a shallow, reactive, static store object | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createDerivedStaticStore | ||
| * @example | ||
| * ```ts | ||
| * const [size, setSize] = createSignal({ width: 0, height: 0 }); | ||
| * | ||
| * el.addEventListener("resize", () => { | ||
| * setSize({ width: el.offsetWidth, height: el.offsetHeight }); | ||
| * }); | ||
| * | ||
| * const store = createDerivedStaticStore(size); | ||
| * | ||
| * createEffect(() => { | ||
| * console.log(store.width, store.height); | ||
| * }) | ||
| * ``` | ||
| */ | ||
| export function createDerivedStaticStore(fn) { | ||
| const fnMemo = createMemo(fn), store = { ...untrack(fnMemo) }; | ||
| // Eagerly create per-key memos so their child IDs are allocated at initialization | ||
| // time on both server and client. The previous lazy approach created memos on first | ||
| // reactive access — which happened inside _$className render-effect computes on the | ||
| // client but not on the server (SSR doesn't run render-effect computes with a live | ||
| // observer), shifting every subsequent hydration key by +1 per lazily-created memo. | ||
| for (const key in store) { | ||
| const k = key; | ||
| const keyMemo = createMemo(() => fnMemo()[k]); | ||
| Object.defineProperty(store, k, { | ||
| get: () => keyMemo(), | ||
| enumerable: true, | ||
| }); | ||
| } | ||
| return store; | ||
| * A derived version of the {@link createStaticStore}. It will use the update function to derive the value of the store. It will only update when the dependencies of the update function change. | ||
| * @param fn a reactive function to derive the value of the store | ||
| * @returns a shallow, reactive, static store object | ||
| * @see https://github.com/solidjs-community/solid-primitives/tree/main/packages/static-store#createDerivedStaticStore | ||
| * @example | ||
| * ```ts | ||
| * const [size, setSize] = createSignal({ width: 0, height: 0 }); | ||
| * | ||
| * el.addEventListener("resize", () => { | ||
| * setSize({ width: el.offsetWidth, height: el.offsetHeight }); | ||
| * }); | ||
| * | ||
| * const store = createDerivedStaticStore(size); | ||
| * | ||
| * createEffect(() => { | ||
| * console.log(store.width, store.height); | ||
| * }) | ||
| * ``` | ||
| */ | ||
| function createDerivedStaticStore(fn) { | ||
| const fnMemo = createMemo(fn), store = { ...untrack(fnMemo) }; | ||
| for (const key in store) { | ||
| const k = key; | ||
| const keyMemo = createMemo(() => fnMemo()[k]); | ||
| Object.defineProperty(store, k, { | ||
| get: () => keyMemo(), | ||
| enumerable: true | ||
| }); | ||
| } | ||
| return store; | ||
| } | ||
| //#endregion | ||
| export { createDerivedStaticStore, createHydratableStaticStore, createStaticStore }; |
+12
-8
| { | ||
| "name": "@solid-primitives/static-store", | ||
| "version": "1.0.0-next.0", | ||
| "version": "1.0.0-next.1", | ||
| "description": "Primitives for creating small reactive objects that doesn't change their shape over time - don't need a proxy wrapper.", | ||
@@ -24,3 +24,3 @@ "author": "Damian Tarnawski <gthetarnav@gmail.com>", | ||
| "category": "Reactivity", | ||
| "gzip": 589 | ||
| "gzip": 587 | ||
| }, | ||
@@ -48,16 +48,20 @@ "keywords": [ | ||
| "typesVersions": {}, | ||
| "tsdown": { | ||
| "entry": "src/**/*.{ts,tsx}", | ||
| "outDir": "dist" | ||
| }, | ||
| "peerDependencies": { | ||
| "@solidjs/web": "^2.0.0-beta.15", | ||
| "solid-js": "^2.0.0-beta.15" | ||
| "@solidjs/web": "^2.0.0-beta.20", | ||
| "solid-js": "^2.0.0-beta.20" | ||
| }, | ||
| "dependencies": { | ||
| "@solid-primitives/utils": "^7.0.0-next.0" | ||
| "@solid-primitives/utils": "^7.0.0-next.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@solidjs/web": "2.0.0-beta.15", | ||
| "solid-js": "2.0.0-beta.15" | ||
| "@solidjs/web": "2.0.0-beta.20", | ||
| "solid-js": "2.0.0-beta.20" | ||
| }, | ||
| "scripts": { | ||
| "dev": "node --import=@nothing-but/node-resolve-ts --experimental-transform-types ../../scripts/dev.ts", | ||
| "build": "node --import=@nothing-but/node-resolve-ts --experimental-transform-types ../../scripts/build.ts", | ||
| "build": "pnpm -w build", | ||
| "vitest": "vitest -c ../../configs/vitest.config.ts", | ||
@@ -64,0 +68,0 @@ "test": "pnpm run vitest", |
+1
-1
@@ -7,3 +7,3 @@ <p> | ||
| [](https://bundlephobia.com/package/@solid-primitives/static-store) | ||
| [](https://bundlephobia.com/package/@solid-primitives/static-store) | ||
| [](https://www.npmjs.com/package/@solid-primitives/static-store) | ||
@@ -10,0 +10,0 @@ [](https://github.com/solidjs-community/solid-primitives#contribution-process) |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
0
-100%14764
-4.25%177
-3.28%