solid-tiny-utils 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 g-mero
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 g-mero
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
- # solid-tiny-utils
2
-
3
- Tiny utilities for SolidJS applications.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pnpm add solid-tiny-utils
9
- ```
1
+ # solid-tiny-utils
2
+
3
+ Tiny utilities for SolidJS applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add solid-tiny-utils
9
+ ```
package/dist/index.d.mts CHANGED
@@ -6,6 +6,7 @@ import { dataIf } from "./dom/attrs.mjs";
6
6
  import { combineClass, combineStyle, mountStyle, stringStyleToObject } from "./dom/css.mjs";
7
7
  import { AnyFn, Fn } from "./types/fn.mjs";
8
8
  import { MaybeAccessor, MaybeArray, MaybeNullableAccessor, MaybePromise } from "./types/maybe.mjs";
9
+ import { SetterParam } from "./types/solidjs.mjs";
9
10
  import { createClickOutside } from "./solidjs/create-click-outside.mjs";
10
11
  import { createDebounce } from "./solidjs/create-debounce.mjs";
11
12
  import { createDebouncedWatch } from "./solidjs/create-debounce-watch.mjs";
@@ -14,11 +15,13 @@ import { createEventListener } from "./solidjs/create-event-listener.mjs";
14
15
  import { createIntersectionObserver } from "./solidjs/create-intersection-observer.mjs";
15
16
  import { createList } from "./solidjs/create-list.mjs";
16
17
  import { createLoopExec } from "./solidjs/create-loop-exec.mjs";
18
+ import { StaticStoreSetter, createStaticStore } from "./solidjs/create-static-store.mjs";
19
+ import { PersistedStorage, PersistedStoreOption, createPersistedStore } from "./solidjs/create-persisted-store.mjs";
17
20
  import { MakePresenceOptions, PresencePhase, createPresence } from "./solidjs/create-presence.mjs";
18
21
  import { createThrottle } from "./solidjs/create-throttle.mjs";
19
22
  import { CreateVisibilityObserverOption, EntryCallback, UseVisibilityObserverFn, createVisibilityObserver } from "./solidjs/create-visibility-observer.mjs";
20
23
  import { createWatch } from "./solidjs/create-watch.mjs";
21
- import { MaybeCallableChild, access, callMaybeCallableChild, runSolidEventHandler } from "./solidjs/utils.mjs";
24
+ import { MaybeCallableChild, access, accessWith, callMaybeCallableChild, runSolidEventHandler } from "./solidjs/utils.mjs";
22
25
  import { clearArray, iterate, list, range } from "./utils/array.mjs";
23
26
  import { runAtNextAnimationFrame, sleep } from "./utils/async.mjs";
24
27
  import { noop } from "./utils/constant.mjs";
@@ -26,4 +29,4 @@ import { isArray, isClient, isDate, isDefined, isEmpty, isFloat, isFn, isInt, is
26
29
  import { clamp, inRange, max, min, toHex } from "./utils/number.mjs";
27
30
  import { draw, random, shuffle, uid } from "./utils/random.mjs";
28
31
  import { camel, capitalize, dash, pascal, snake, template, title, trim } from "./utils/str.mjs";
29
- export { AnyFn, CreateVisibilityObserverOption, DocumentEventName, EntryCallback, Fn, GeneralEventListener, MakePresenceOptions, MaybeAccessor, MaybeArray, MaybeCallableChild, MaybeNullableAccessor, MaybePromise, OKLCH, PresencePhase, RGB, UseVisibilityObserverFn, WindowEventName, access, callMaybeCallableChild, camel, capitalize, clamp, clearArray, combineClass, combineStyle, createClickOutside, createDebounce, createDebouncedWatch, createEventListener, createIntersectionObserver, createList, createLoopExec, createPresence, createThrottle, createVisibilityObserver, createWatch, dash, dataIf, draw, hasAnimation, hexToRgb, inRange, isArray, isClient, isDate, isDefined, isEmpty, isFloat, isFn, isInt, isNumber, isObject, isPrimitive, isPromise, isString, isSymbol, isUndefined, isValidHex, isValidOKLCH, isValidRGB, iterate, list, makeEventListener, max, min, mountStyle, noop, oklchToRgb, pascal, random, range, rgbToHex, rgbToOklch, runAtNextAnimationFrame, runSolidEventHandler, shuffle, sleep, snake, stringStyleToObject, template, title, toHex, trim, uid };
32
+ export { AnyFn, CreateVisibilityObserverOption, DocumentEventName, EntryCallback, Fn, GeneralEventListener, MakePresenceOptions, MaybeAccessor, MaybeArray, MaybeCallableChild, MaybeNullableAccessor, MaybePromise, OKLCH, PersistedStorage, PersistedStoreOption, PresencePhase, RGB, SetterParam, StaticStoreSetter, UseVisibilityObserverFn, WindowEventName, access, accessWith, callMaybeCallableChild, camel, capitalize, clamp, clearArray, combineClass, combineStyle, createClickOutside, createDebounce, createDebouncedWatch, createEventListener, createIntersectionObserver, createList, createLoopExec, createPersistedStore, createPresence, createStaticStore, createThrottle, createVisibilityObserver, createWatch, dash, dataIf, draw, hasAnimation, hexToRgb, inRange, isArray, isClient, isDate, isDefined, isEmpty, isFloat, isFn, isInt, isNumber, isObject, isPrimitive, isPromise, isString, isSymbol, isUndefined, isValidHex, isValidOKLCH, isValidRGB, iterate, list, makeEventListener, max, min, mountStyle, noop, oklchToRgb, pascal, random, range, rgbToHex, rgbToOklch, runAtNextAnimationFrame, runSolidEventHandler, shuffle, sleep, snake, stringStyleToObject, template, title, toHex, trim, uid };
package/dist/index.mjs CHANGED
@@ -11,7 +11,7 @@ import { isValidHex, isValidOKLCH, isValidRGB } from "./color/validation.mjs";
11
11
  import { hasAnimation } from "./dom/animation.mjs";
12
12
  import { dataIf } from "./dom/attrs.mjs";
13
13
  import { makeEventListener } from "./solidjs/make-event-listener.mjs";
14
- import { access, callMaybeCallableChild, runSolidEventHandler } from "./solidjs/utils.mjs";
14
+ import { access, accessWith, callMaybeCallableChild, runSolidEventHandler } from "./solidjs/utils.mjs";
15
15
  import { createClickOutside } from "./solidjs/create-click-outside.mjs";
16
16
  import { createDebounce } from "./solidjs/create-debounce.mjs";
17
17
  import { createWatch } from "./solidjs/create-watch.mjs";
@@ -20,8 +20,10 @@ import { createEventListener } from "./solidjs/create-event-listener.mjs";
20
20
  import { createIntersectionObserver } from "./solidjs/create-intersection-observer.mjs";
21
21
  import { createList } from "./solidjs/create-list.mjs";
22
22
  import { createLoopExec } from "./solidjs/create-loop-exec.mjs";
23
+ import { createStaticStore } from "./solidjs/create-static-store.mjs";
24
+ import { createPersistedStore } from "./solidjs/create-persisted-store.mjs";
23
25
  import { createPresence } from "./solidjs/create-presence.mjs";
24
26
  import { createThrottle } from "./solidjs/create-throttle.mjs";
25
27
  import { createVisibilityObserver } from "./solidjs/create-visibility-observer.mjs";
26
28
  import { combineClass, combineStyle, mountStyle, stringStyleToObject } from "./dom/css.mjs";
27
- export { access, callMaybeCallableChild, camel, capitalize, clamp, clearArray, combineClass, combineStyle, createClickOutside, createDebounce, createDebouncedWatch, createEventListener, createIntersectionObserver, createList, createLoopExec, createPresence, createThrottle, createVisibilityObserver, createWatch, dash, dataIf, draw, hasAnimation, hexToRgb, inRange, isArray, isClient, isDate, isDefined, isEmpty, isFloat, isFn, isInt, isNumber, isObject, isPrimitive, isPromise, isString, isSymbol, isUndefined, isValidHex, isValidOKLCH, isValidRGB, iterate, list, makeEventListener, max, min, mountStyle, noop, oklchToRgb, pascal, random, range, rgbToHex, rgbToOklch, runAtNextAnimationFrame, runSolidEventHandler, shuffle, sleep, snake, stringStyleToObject, template, title, toHex, trim, uid };
29
+ export { access, accessWith, callMaybeCallableChild, camel, capitalize, clamp, clearArray, combineClass, combineStyle, createClickOutside, createDebounce, createDebouncedWatch, createEventListener, createIntersectionObserver, createList, createLoopExec, createPersistedStore, createPresence, createStaticStore, createThrottle, createVisibilityObserver, createWatch, dash, dataIf, draw, hasAnimation, hexToRgb, inRange, isArray, isClient, isDate, isDefined, isEmpty, isFloat, isFn, isInt, isNumber, isObject, isPrimitive, isPromise, isString, isSymbol, isUndefined, isValidHex, isValidOKLCH, isValidRGB, iterate, list, makeEventListener, max, min, mountStyle, noop, oklchToRgb, pascal, random, range, rgbToHex, rgbToOklch, runAtNextAnimationFrame, runSolidEventHandler, shuffle, sleep, snake, stringStyleToObject, template, title, toHex, trim, uid };
@@ -0,0 +1,42 @@
1
+ import { StaticStoreSetter } from "./create-static-store.mjs";
2
+
3
+ //#region src/solidjs/create-persisted-store.d.ts
4
+ interface PersistedStorage {
5
+ getItem(key: string): string | null;
6
+ removeItem(key: string): void;
7
+ setItem(key: string, value: string): void;
8
+ }
9
+ interface PersistedStoreOption {
10
+ /**
11
+ * Storage key used to read and write the store.
12
+ */
13
+ name?: string;
14
+ /**
15
+ * Storage adapter. Defaults to `localStorage` in the browser.
16
+ */
17
+ storage?: PersistedStorage;
18
+ }
19
+ /**
20
+ * Creates a static store persisted as JSON.
21
+ *
22
+ * Only keys from `init` are restored. Invalid JSON and storage errors are
23
+ * ignored.
24
+ *
25
+ * @param init Initial store value.
26
+ * @param opts Persistence options.
27
+ * @returns The store object and setter.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const [settings, setSettings] = createPersistedStore(
32
+ * { theme: "system", sidebarOpen: true },
33
+ * { name: "app-settings" }
34
+ * );
35
+ *
36
+ * setSettings("theme", "dark");
37
+ * setSettings({ sidebarOpen: false });
38
+ * ```
39
+ */
40
+ declare function createPersistedStore<T extends Record<string, unknown>>(init: T, opts?: PersistedStoreOption): readonly [T, StaticStoreSetter<T>];
41
+ //#endregion
42
+ export { PersistedStorage, PersistedStoreOption, createPersistedStore };
@@ -0,0 +1,64 @@
1
+ import { isObject } from "../utils/is.mjs";
2
+ import { createWatch } from "./create-watch.mjs";
3
+ import { createStaticStore } from "./create-static-store.mjs";
4
+ import { createUniqueId } from "solid-js";
5
+ //#region src/solidjs/create-persisted-store.ts
6
+ const noopStorage = {
7
+ getItem: () => null,
8
+ removeItem: () => void 0,
9
+ setItem: () => void 0
10
+ };
11
+ function getDefaultStorage() {
12
+ return typeof localStorage === "undefined" ? noopStorage : localStorage;
13
+ }
14
+ function getStore(storage, name) {
15
+ try {
16
+ const val = storage.getItem(name);
17
+ if (!val) return {};
18
+ return JSON.parse(val);
19
+ } catch {
20
+ return {};
21
+ }
22
+ }
23
+ function strictAssignStore(init, obj) {
24
+ const store = { ...init };
25
+ if (!isObject(obj)) return store;
26
+ for (const key in store) if (Object.hasOwn(obj, key) && Object.hasOwn(store, key)) store[key] = obj[key];
27
+ return store;
28
+ }
29
+ /**
30
+ * Creates a static store persisted as JSON.
31
+ *
32
+ * Only keys from `init` are restored. Invalid JSON and storage errors are
33
+ * ignored.
34
+ *
35
+ * @param init Initial store value.
36
+ * @param opts Persistence options.
37
+ * @returns The store object and setter.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const [settings, setSettings] = createPersistedStore(
42
+ * { theme: "system", sidebarOpen: true },
43
+ * { name: "app-settings" }
44
+ * );
45
+ *
46
+ * setSettings("theme", "dark");
47
+ * setSettings({ sidebarOpen: false });
48
+ * ```
49
+ */
50
+ function createPersistedStore(init, opts) {
51
+ const name = opts?.name ?? `persisted-${createUniqueId()}`;
52
+ const storage = opts?.storage ?? getDefaultStorage();
53
+ const [store, setStore] = createStaticStore(strictAssignStore(init, getStore(storage, name)));
54
+ createWatch(() => JSON.stringify(store), (jsonData) => {
55
+ try {
56
+ storage.setItem(name, jsonData);
57
+ } catch {
58
+ return;
59
+ }
60
+ }, { defer: true });
61
+ return [store, setStore];
62
+ }
63
+ //#endregion
64
+ export { createPersistedStore };
@@ -7,14 +7,16 @@ interface MakePresenceOptions {
7
7
  exitDuration: MaybeAccessor<number>;
8
8
  initialEnter?: boolean;
9
9
  }
10
- type PresencePhase = "idle" | "pre-enter" | "entering" | "entered" | "exiting" | "exited";
10
+ type PresencePhase = "idle" | "entering" | "entered" | "exiting";
11
+ /**
12
+ * Keeps an item mounted while its enter and exit animations run.
13
+ */
11
14
  declare function createPresence<TItem>(item: Accessor<TItem | undefined>, options: MakePresenceOptions): {
12
15
  isMounted: () => boolean;
13
- mountedItem: Accessor<TItem | undefined>;
14
- isVisible: Accessor<boolean>;
15
16
  isAnimating: Accessor<boolean>;
16
17
  isEntering: Accessor<boolean>;
17
18
  isExiting: Accessor<boolean>;
19
+ mountedItem: Accessor<TItem | undefined>;
18
20
  phase: Accessor<PresencePhase>;
19
21
  };
20
22
  //#endregion
@@ -1,86 +1,66 @@
1
1
  import { isDefined } from "../utils/is.mjs";
2
- import { runAtNextAnimationFrame } from "../utils/async.mjs";
3
2
  import { noop } from "../utils/constant.mjs";
4
3
  import { access } from "./utils.mjs";
5
4
  import { createWatch } from "./create-watch.mjs";
6
5
  import { createEffect, createMemo, createSignal, onCleanup, untrack } from "solid-js";
7
6
  //#region src/solidjs/create-presence.ts
8
7
  function makeTimeout(ms, fn) {
9
- if (ms() <= 0) {
8
+ if (ms <= 0) {
10
9
  fn();
11
10
  return noop;
12
11
  }
13
12
  const timeoutId = setTimeout(() => {
14
13
  fn();
15
- }, ms());
14
+ }, ms);
16
15
  return () => clearTimeout(timeoutId);
17
16
  }
17
+ const itemShouldBeMounted = (item) => item !== false && item != null;
18
+ function getInitialPhase(item, initialEnter) {
19
+ if (!itemShouldBeMounted(item)) return "idle";
20
+ if (initialEnter) return "entering";
21
+ return "entered";
22
+ }
18
23
  /**
19
- * Animates the appearance of its children.
20
- *
21
- * @internal - to be combined with `createPresence` in the future
24
+ * Keeps an item mounted while its enter and exit animations run.
22
25
  */
23
- function createPresenceBase(source, options) {
24
- const enterDuration = () => access(options.enterDuration);
25
- const exitDuration = () => access(options.exitDuration);
26
- const initialSource = untrack(source);
27
- let initialPhase = "idle";
28
- if (initialSource) initialPhase = options.initialEnter ? "pre-enter" : "entered";
29
- const [phase, setPhase] = createSignal(initialPhase);
26
+ function createPresence(item, options) {
27
+ const initial = untrack(item);
28
+ const [mountedItem, setMountedItem] = createSignal(initial);
29
+ const [phase, setPhase] = createSignal(getInitialPhase(initial, options.initialEnter));
30
+ const isMounted = createMemo(() => phase() !== "idle");
31
+ const isEntering = createMemo(() => phase() === "entering");
32
+ const isExiting = createMemo(() => phase() === "exiting");
33
+ const isAnimating = createMemo(() => isEntering() || isExiting());
30
34
  let clear = noop;
31
35
  onCleanup(clear);
32
- createWatch(source, (visible) => {
33
- setPhase((prev) => {
34
- if (visible) {
35
- if (prev === "idle" || prev === "exited") return "pre-enter";
36
- return prev;
37
- }
38
- if (prev === "entered" || prev === "entering") return "exiting";
39
- return prev;
40
- });
41
- });
42
36
  createWatch(phase, (currentPhase) => {
43
37
  clear();
44
- if (currentPhase === "pre-enter") runAtNextAnimationFrame(() => {
45
- setPhase("entering");
46
- });
47
- if (currentPhase === "entering") clear = makeTimeout(enterDuration, () => setPhase("entered"));
48
- if (currentPhase === "exiting") clear = makeTimeout(exitDuration, () => setPhase("exited"));
49
- if (currentPhase === "exited") setPhase("idle");
38
+ if (currentPhase === "entering") clear = makeTimeout(access(options.enterDuration), () => setPhase("entered"));
39
+ if (currentPhase === "exiting") clear = makeTimeout(access(options.exitDuration), () => setPhase("idle"));
50
40
  });
51
- const isVisible = createMemo(() => ["entering", "entered"].includes(phase()));
52
- const isMounted = createMemo(() => phase() !== "idle");
53
- const isExiting = createMemo(() => phase() === "exiting");
54
- const isEntering = createMemo(() => phase() === "entering");
55
- return {
56
- isMounted,
57
- isVisible,
58
- isAnimating: createMemo(() => isEntering() || isExiting()),
59
- isEntering,
60
- isExiting,
61
- phase
62
- };
63
- }
64
- const itemShouldBeMounted = (item) => item !== false && item != null;
65
- function createPresence(item, options) {
66
- const initial = untrack(item);
67
- const [mountedItem, setMountedItem] = createSignal(initial);
68
- const [shouldBeMounted, setShouldBeMounted] = createSignal(itemShouldBeMounted(initial));
69
- const { isMounted, ...rest } = createPresenceBase(shouldBeMounted, options);
70
41
  createEffect(() => {
71
- if (mountedItem() !== item()) {
72
- if (isMounted()) setShouldBeMounted(false);
73
- else if (itemShouldBeMounted(item())) {
74
- setMountedItem(() => item());
75
- setShouldBeMounted(true);
42
+ const currentItem = item();
43
+ if (mountedItem() !== currentItem) {
44
+ if (isMounted()) setPhase("exiting");
45
+ else if (itemShouldBeMounted(currentItem)) {
46
+ setMountedItem(() => currentItem);
47
+ setPhase("entering");
76
48
  }
77
- } else if (!itemShouldBeMounted(item())) setShouldBeMounted(false);
78
- else if (itemShouldBeMounted(item())) setShouldBeMounted(true);
49
+ return;
50
+ }
51
+ if (itemShouldBeMounted(currentItem)) {
52
+ if (!isMounted()) setPhase("entering");
53
+ return;
54
+ }
55
+ if (isMounted()) setPhase("exiting");
79
56
  });
80
57
  return {
81
- ...rest,
82
58
  isMounted: () => isMounted() && isDefined(mountedItem()),
83
- mountedItem
59
+ isAnimating,
60
+ isEntering,
61
+ isExiting,
62
+ mountedItem,
63
+ phase
84
64
  };
85
65
  }
86
66
  //#endregion
@@ -0,0 +1,27 @@
1
+ import { SetterParam } from "../types/solidjs.mjs";
2
+ //#region src/solidjs/create-static-store.d.ts
3
+ interface StaticStoreSetter<T extends object> {
4
+ (setter: (prev: T) => Partial<T>): T;
5
+ (state: Partial<T>): T;
6
+ <K extends keyof T>(key: K, state: SetterParam<T[K]>): T;
7
+ }
8
+ /**
9
+ * Creates a shallow reactive object with a fixed set of keys.
10
+ *
11
+ * Only top-level properties are tracked. Keys are defined by `init` and are not
12
+ * added or removed later.
13
+ *
14
+ * @param init Initial store value.
15
+ * @returns The store object and setter.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const [state, setState] = createStaticStore({ count: 0 });
20
+ *
21
+ * setState("count", (count) => count + 1);
22
+ * setState({ count: 10 });
23
+ * ```
24
+ */
25
+ declare function createStaticStore<T extends object>(init: T): [access: T, write: StaticStoreSetter<T>];
26
+ //#endregion
27
+ export { StaticStoreSetter, createStaticStore };
@@ -0,0 +1,54 @@
1
+ import { isFn, isObject } from "../utils/is.mjs";
2
+ import { accessWith } from "./utils.mjs";
3
+ import { batch, createSignal, getListener, untrack } from "solid-js";
4
+ //#region src/solidjs/create-static-store.ts
5
+ /** biome-ignore-all lint/suspicious/noExplicitAny: any */
6
+ /**
7
+ * Creates a shallow reactive object with a fixed set of keys.
8
+ *
9
+ * Only top-level properties are tracked. Keys are defined by `init` and are not
10
+ * added or removed later.
11
+ *
12
+ * @param init Initial store value.
13
+ * @returns The store object and setter.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const [state, setState] = createStaticStore({ count: 0 });
18
+ *
19
+ * setState("count", (count) => count + 1);
20
+ * setState({ count: 10 });
21
+ * ```
22
+ */
23
+ function createStaticStore(init) {
24
+ const copy = { ...init }, store = { ...init }, cache = {};
25
+ const getValue = (key) => {
26
+ let signal = cache[key];
27
+ if (!signal) {
28
+ if (!getListener()) return copy[key];
29
+ cache[key] = signal = createSignal(copy[key], { internal: true });
30
+ delete copy[key];
31
+ }
32
+ return signal[0]();
33
+ };
34
+ for (const key in init) if (Object.hasOwn(init, key)) Object.defineProperty(store, key, {
35
+ get: () => getValue(key),
36
+ enumerable: true
37
+ });
38
+ const setValue = (key, value) => {
39
+ const signal = cache[key];
40
+ if (signal) signal[1](value);
41
+ if (key in copy) copy[key] = accessWith(value, copy[key]);
42
+ };
43
+ return [store, (a, b) => {
44
+ if (isObject(a) || isFn(a)) {
45
+ const entries = untrack(() => Object.entries(accessWith(a, store)));
46
+ batch(() => {
47
+ for (const [key, value] of entries) setValue(key, () => value);
48
+ });
49
+ } else setValue(a, b);
50
+ return store;
51
+ }];
52
+ }
53
+ //#endregion
54
+ export { createStaticStore };
@@ -6,8 +6,10 @@ import { createEventListener } from "./create-event-listener.mjs";
6
6
  import { createIntersectionObserver } from "./create-intersection-observer.mjs";
7
7
  import { createList } from "./create-list.mjs";
8
8
  import { createLoopExec } from "./create-loop-exec.mjs";
9
+ import { StaticStoreSetter, createStaticStore } from "./create-static-store.mjs";
10
+ import { PersistedStorage, PersistedStoreOption, createPersistedStore } from "./create-persisted-store.mjs";
9
11
  import { MakePresenceOptions, PresencePhase, createPresence } from "./create-presence.mjs";
10
12
  import { createThrottle } from "./create-throttle.mjs";
11
13
  import { CreateVisibilityObserverOption, EntryCallback, UseVisibilityObserverFn, createVisibilityObserver } from "./create-visibility-observer.mjs";
12
14
  import { createWatch } from "./create-watch.mjs";
13
- import { MaybeCallableChild, access, callMaybeCallableChild, runSolidEventHandler } from "./utils.mjs";
15
+ import { MaybeCallableChild, access, accessWith, callMaybeCallableChild, runSolidEventHandler } from "./utils.mjs";
@@ -1,10 +1,13 @@
1
+ import { AnyFn } from "../types/fn.mjs";
1
2
  import { MaybeAccessor } from "../types/maybe.mjs";
2
3
  import { JSX } from "solid-js";
3
4
 
4
5
  //#region src/solidjs/utils.d.ts
5
6
  declare function access<T>(value: MaybeAccessor<T>): T;
7
+ /** If value is a function – call it with a given arguments – otherwise get the value as is */
8
+ declare function accessWith<T>(valueOrFn: T, ...args: T extends AnyFn ? Parameters<T> : never): T extends AnyFn ? ReturnType<T> : T;
6
9
  declare function runSolidEventHandler<T, E extends Event, EHandler extends JSX.EventHandler<T, any> = JSX.EventHandler<T, E>>(event: E, handler?: EHandler | JSX.BoundEventHandler<T, E, EHandler>): void;
7
10
  type MaybeCallableChild<T extends unknown[] = []> = JSX.Element | ((...args: T) => JSX.Element);
8
11
  declare function callMaybeCallableChild<T extends unknown[] = []>(children: MaybeCallableChild<T>, ...args: T): JSX.Element;
9
12
  //#endregion
10
- export { MaybeCallableChild, access, callMaybeCallableChild, runSolidEventHandler };
13
+ export { MaybeCallableChild, access, accessWith, callMaybeCallableChild, runSolidEventHandler };
@@ -3,6 +3,10 @@ import { isArray, isFn } from "../utils/is.mjs";
3
3
  function access(value) {
4
4
  return isFn(value) ? value() : value;
5
5
  }
6
+ /** If value is a function – call it with a given arguments – otherwise get the value as is */
7
+ function accessWith(valueOrFn, ...args) {
8
+ return isFn(valueOrFn) ? valueOrFn(...args) : valueOrFn;
9
+ }
6
10
  function runSolidEventHandler(event, handler) {
7
11
  if (isFn(handler)) {
8
12
  handler(event);
@@ -18,4 +22,4 @@ function callMaybeCallableChild(children, ...args) {
18
22
  return isFn(children) ? children(...args) : children;
19
23
  }
20
24
  //#endregion
21
- export { access, callMaybeCallableChild, runSolidEventHandler };
25
+ export { access, accessWith, callMaybeCallableChild, runSolidEventHandler };
@@ -1,2 +1,3 @@
1
1
  import { AnyFn, Fn } from "./fn.mjs";
2
- import { MaybeAccessor, MaybeArray, MaybeNullableAccessor, MaybePromise } from "./maybe.mjs";
2
+ import { MaybeAccessor, MaybeArray, MaybeNullableAccessor, MaybePromise } from "./maybe.mjs";
3
+ import { SetterParam } from "./solidjs.mjs";
@@ -0,0 +1,6 @@
1
+ import { Setter } from "solid-js";
2
+
3
+ //#region src/types/solidjs.d.ts
4
+ type SetterParam<T> = Parameters<Setter<T>>[0];
5
+ //#endregion
6
+ export { SetterParam };
package/package.json CHANGED
@@ -8,13 +8,12 @@
8
8
  "@testing-library/user-event": "^14.6.1",
9
9
  "@types/culori": "^4.0.0",
10
10
  "@types/node": "^25.0.3",
11
- "@typescript/native-preview": "7.0.0-dev.20260421.2",
11
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
12
12
  "@vitest/ui": "^4.0.16",
13
13
  "bumpp": "^11.1.0",
14
14
  "culori": "^4.0.2",
15
15
  "jsdom": "^29.1.1",
16
- "solid-tiny-context": "0.3.1",
17
- "tsdown": "^0.22.0",
16
+ "tsdown": "^0.22.1",
18
17
  "ultracite": "7.7.0",
19
18
  "unocss": "^66.7.0",
20
19
  "vite": "^8.0.14",
@@ -27,7 +26,7 @@
27
26
  "solid-js": "^1.9.7"
28
27
  },
29
28
  "type": "module",
30
- "version": "0.12.1",
29
+ "version": "0.13.0",
31
30
  "description": "A collection of tiny utilities for SolidJS applications",
32
31
  "author": "solid tiny",
33
32
  "license": "MIT",