@dvirus-js/react 0.0.13

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/CHANGELOG.md ADDED
@@ -0,0 +1,37 @@
1
+ ## 0.0.12 (2026-05-31)
2
+
3
+ This was a version bump only for react to align it with other projects, there were no code changes.
4
+
5
+ ## 0.0.11 (2026-05-31)
6
+
7
+ This was a version bump only for react to align it with other projects, there were no code changes.
8
+
9
+ ## 0.0.10 (2026-05-31)
10
+
11
+ This was a version bump only for react to align it with other projects, there were no code changes.
12
+
13
+ ## 0.0.9 (2026-05-31)
14
+
15
+ This was a version bump only for react to align it with other projects, there were no code changes.
16
+
17
+ ## 0.0.8 (2026-05-31)
18
+
19
+ ### 🩹 Fixes
20
+
21
+ - prepare first 0.0.701 release flow ([29a6e68](https://github.com/Dvirus97/dvirus-js/commit/29a6e68))
22
+ - add react package with jsDocs and ReadMe ([6cf3517](https://github.com/Dvirus97/dvirus-js/commit/6cf3517))
23
+
24
+ ### ❤️ Thank You
25
+
26
+ - Dvir Cohen
27
+
28
+ ## 0.0.701 (2026-05-31)
29
+
30
+ ### 🩹 Fixes
31
+
32
+ - prepare first 0.0.701 release flow ([0661450](https://github.com/Dvirus97/dvirus-js/commit/0661450))
33
+ - add react package with jsDocs and ReadMe ([6154549](https://github.com/Dvirus97/dvirus-js/commit/6154549))
34
+
35
+ ### ❤️ Thank You
36
+
37
+ - Dvir Cohen
package/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # React Utils Library
2
+
3
+ Small, framework-focused helpers for React apps.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @dvirus-js/react
9
+ ```
10
+
11
+ ## Exports
12
+
13
+ - `cx`: join class names from strings and conditional maps.
14
+ - `toDataAttributes`: map values into `data-*` attributes.
15
+
16
+ ## Example
17
+
18
+ ```ts
19
+ import { cx, toDataAttributes } from '@dvirus-js/react';
20
+
21
+ const className = cx('btn', { 'btn-primary': true, disabled: false });
22
+ const dataAttrs = toDataAttributes({ state: 'active', index: 2 });
23
+ ```
package/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './lib/cx';
2
+ export * from './lib/to-data-attributes';
3
+ export * from './lib/signals';
package/index.js ADDED
@@ -0,0 +1,118 @@
1
+ import * as o from "react";
2
+ function y(...e) {
3
+ const n = [];
4
+ for (const t of e)
5
+ if (t) {
6
+ if (typeof t == "string") {
7
+ n.push(t);
8
+ continue;
9
+ }
10
+ for (const [r, a] of Object.entries(t))
11
+ a && n.push(r);
12
+ }
13
+ return n.join(" ");
14
+ }
15
+ function h(e) {
16
+ const n = {};
17
+ for (const [t, r] of Object.entries(e))
18
+ r != null && (n[`data-${t}`] = String(r));
19
+ return n;
20
+ }
21
+ const f = /* @__PURE__ */ Symbol("SIGNAL");
22
+ function O(e) {
23
+ return typeof e == "function" && f in e;
24
+ }
25
+ function d() {
26
+ let e, n = null, t = !1, r = null;
27
+ const a = () => e, i = (s) => {
28
+ (!t || !Object.is(e, s)) && (e = s, t = !0, r?.());
29
+ };
30
+ return {
31
+ get: Object.assign(() => e, {
32
+ [f]: !0,
33
+ set: (s) => {
34
+ i(s);
35
+ },
36
+ update: (s) => {
37
+ i(s(e));
38
+ },
39
+ asReadOnly: () => a
40
+ }),
41
+ // readOnlyGet,
42
+ // set: (newValue: T): void => {
43
+ // setValue(newValue);
44
+ // },
45
+ // update: (updater: (prevValue: T) => T): void => {
46
+ // setValue(updater(latestValue));
47
+ // },
48
+ bindNotifyChange: (s) => {
49
+ r = s;
50
+ },
51
+ computeIfNeeded: (s, u) => {
52
+ (!t || g(n, u)) && (e = s(), n = [...u], t = !0);
53
+ }
54
+ };
55
+ }
56
+ function p(e, n) {
57
+ const [, t] = o.useState(0), [r] = o.useState(
58
+ () => d()
59
+ );
60
+ return r.bindNotifyChange(() => t((a) => a > 1e3 ? 1 : a + 1)), r.computeIfNeeded(e, n), r;
61
+ }
62
+ function g(e, n) {
63
+ if (e === null || e.length !== n.length) return !0;
64
+ for (let t = 0; t < n.length; t += 1)
65
+ if (!Object.is(e[t], n[t])) return !0;
66
+ return !1;
67
+ }
68
+ function m(e, n) {
69
+ return S(e, n).asReadOnly();
70
+ }
71
+ function S(e, n) {
72
+ return p(e, n).get;
73
+ }
74
+ function b(e) {
75
+ let n;
76
+ return {
77
+ state: Object.assign(() => n, {
78
+ [f]: !0,
79
+ set: (t) => e(t),
80
+ update: (t) => e(t),
81
+ asReadOnly: () => () => n
82
+ }),
83
+ setLatest: (t) => {
84
+ n = t;
85
+ }
86
+ };
87
+ }
88
+ function l(e) {
89
+ const [n, t] = o.useState(e), [r] = o.useState(
90
+ () => b(t)
91
+ );
92
+ return r.setLatest(n), r.state;
93
+ }
94
+ function C(e) {
95
+ const n = l(e.defaultValue), t = l(!1), r = l(void 0), [a, i] = o.useState(0), s = o.useCallback(() => i((u) => u + 1), []);
96
+ return o.useEffect(() => {
97
+ let u = !1;
98
+ return t.set(!0), r.set(void 0), e.loader().then((c) => {
99
+ u || n.set(c);
100
+ }).catch((c) => {
101
+ u || r.set(c);
102
+ }).finally(() => {
103
+ u || t.set(!1);
104
+ }), () => {
105
+ u = !0;
106
+ };
107
+ }, [a, ...e.deps || []]), { value: n, isLoading: t, error: r, reload: s };
108
+ }
109
+ export {
110
+ f as USE_SIGNAL,
111
+ y as cx,
112
+ O as isSignalState,
113
+ h as toDataAttributes,
114
+ m as useComputed,
115
+ C as useResource,
116
+ l as useSignalState,
117
+ S as useWritableComputed
118
+ };
package/lib/cx.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export type ClassValue = string | null | undefined | false | Record<string, boolean | null | undefined>;
2
+ export declare function cx(...values: ClassValue[]): string;
@@ -0,0 +1,4 @@
1
+ export * from './signals.type';
2
+ export * from './useComputed';
3
+ export * from './useSignal';
4
+ export * from './useResource';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Marker symbol used to identify writable signal wrappers.
3
+ */
4
+ export declare const USE_SIGNAL: unique symbol;
5
+ /**
6
+ * Runtime type guard that checks whether a value is a signal.
7
+ */
8
+ export declare function isSignalState<T>(val: unknown): val is Signal<T>;
9
+ /**
10
+ * Read-only function-style signal.
11
+ * Call the function to read the current value.
12
+ */
13
+ export interface Signal<S> {
14
+ (): S;
15
+ }
16
+ /**
17
+ * Writable signal with mutation helpers.
18
+ */
19
+ export interface WritableSignal<S> extends Signal<S> {
20
+ /** Replace the current value. */
21
+ set: (newState: S) => void;
22
+ /** Update the current value from its previous value. */
23
+ update: (updater: (prevState: S) => S) => void;
24
+ /** Get a read-only view of this signal. */
25
+ asReadOnly: () => Signal<S>;
26
+ }
27
+ /**
28
+ * Options for the asynchronous resource hook.
29
+ */
30
+ export interface UseResourceOptions<T> {
31
+ /** Dependency list used to re-run the loader. */
32
+ deps?: React.DependencyList;
33
+ /** Async loader that resolves the resource value. */
34
+ loader: () => Promise<T>;
35
+ /** Optional initial value before the first load resolves. */
36
+ defaultValue?: T;
37
+ }
38
+ /**
39
+ * Reactive references returned by the resource hook.
40
+ */
41
+ export interface ResourceRef<T, E = Error> {
42
+ /** Current resource value. */
43
+ value: WritableSignal<T | undefined>;
44
+ /** Tracks whether a request is in-flight. */
45
+ isLoading: WritableSignal<boolean>;
46
+ /** Last request error when present. */
47
+ error: WritableSignal<E | undefined>;
48
+ /** Triggers a manual reload. */
49
+ reload: () => void;
50
+ }
@@ -0,0 +1,33 @@
1
+ import { Signal, WritableSignal } from './signals.type';
2
+ import * as React from 'react';
3
+ /**
4
+ * Creates a read-only computed signal.
5
+ *
6
+ * The value is lazily recomputed when dependencies change (using `Object.is`
7
+ * comparison semantics), otherwise the previously computed value is reused.
8
+ *
9
+ * This is the safe default when consumers should not be able to mutate the
10
+ * computed value directly.
11
+ *
12
+ * @template T Computed value type.
13
+ * @param compute Pure compute function used to derive the current value.
14
+ * @param deps Dependency list that controls recomputation.
15
+ * @returns A read-only signal function that returns the latest computed value.
16
+ */
17
+ export declare function useComputed<T>(compute: () => T, deps: React.DependencyList): Signal<T>;
18
+ /**
19
+ * Creates a writable computed signal.
20
+ *
21
+ * The signal starts from `compute()` and recomputes when `deps` change. In
22
+ * addition, callers can manually override the value via `set` or `update`.
23
+ * A later dependency change may replace that manual value with a newly
24
+ * computed result.
25
+ *
26
+ * ### Prefer `useComputed` unless you explicitly need imperative overrides.
27
+ *
28
+ * @template T Computed value type.
29
+ * @param compute Pure compute function used to derive the current value.
30
+ * @param deps Dependency list that controls recomputation.
31
+ * @returns A writable signal with `set`, `update`, and `asReadOnly` methods.
32
+ */
33
+ export declare function useWritableComputed<T>(compute: () => T, deps: React.DependencyList): WritableSignal<T>;
File without changes
@@ -0,0 +1,34 @@
1
+ import { ResourceRef, UseResourceOptions } from './signals.type';
2
+ /**
3
+ * Loads asynchronous data and exposes request state as writable signals.
4
+ *
5
+ * The loader runs on mount, when any `options.deps` value changes, and when
6
+ * `reload()` is called. While running, `isLoading` is set to `true` and `error`
7
+ * is cleared. On success, `value` is updated. On failure, `error` is updated.
8
+ *
9
+ * Stale async resolutions are ignored after cleanup, preventing state writes
10
+ * from outdated requests.
11
+ *
12
+ * @template T Loaded value type.
13
+ * @template E Error type captured in the `error` signal.
14
+ * @param options Resource options:
15
+ * - `loader`: async function that resolves the next value.
16
+ * - `deps`: optional dependency list that triggers reloads.
17
+ * - `defaultValue`: optional initial value before first successful load.
18
+ * @returns Signal-backed resource reference with:
19
+ * - `value`: latest loaded value.
20
+ * - `isLoading`: request in-flight flag.
21
+ * - `error`: latest error value.
22
+ * - `reload`: function to manually trigger a new load.
23
+ *
24
+ * @example
25
+ * const users = useResource({
26
+ * loader: () => fetch('/api/users').then((r) => r.json() as Promise<User[]>),
27
+ * deps: [teamId],
28
+ * defaultValue: [],
29
+ * });
30
+ *
31
+ * if (users.isLoading()) return;
32
+ * const list = users.value() ?? [];
33
+ */
34
+ export declare function useResource<T, E = Error>(options: UseResourceOptions<T>): ResourceRef<T, E>;
@@ -0,0 +1,23 @@
1
+ import { WritableSignal } from './signals.type';
2
+ /**
3
+ * React state hook exposed as a writable signal API.
4
+ *
5
+ * Returns a function-style signal with stable identity:
6
+ * - call `signal()` to read the latest value,
7
+ * - call `signal.set(next)` to replace it,
8
+ * - call `signal.update((prev) => next)` to derive the next value,
9
+ * - call `signal.asReadOnly()` to hide mutation methods.
10
+ *
11
+ * This is useful when you want React state ergonomics plus signal-style
12
+ * composability.
13
+ *
14
+ * @template S State value type.
15
+ * @param initVal Initial state value or lazy initializer.
16
+ * @returns Writable signal backed by `React.useState`.
17
+ *
18
+ * @example
19
+ * const count = useSignalState(0);
20
+ * count.update((v) => v + 1);
21
+ * console.log(count()); // 1
22
+ */
23
+ export declare function useSignalState<S>(initVal: S | (() => S)): WritableSignal<S>;
@@ -0,0 +1,4 @@
1
+ type Primitive = string | number | boolean | null | undefined;
2
+ export type DataSource = Record<string, Primitive>;
3
+ export declare function toDataAttributes(source: DataSource): Record<string, string>;
4
+ export {};
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@dvirus-js/react",
3
+ "version": "0.0.13",
4
+ "type": "module",
5
+ "main": "./index.js",
6
+ "types": "./index.d.ts",
7
+ "dependencies": {
8
+ "@types/react": "^19.2.15"
9
+ },
10
+ "peerDependencies": {
11
+ "react": ">=18"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ }
16
+ }