@khanglvm/react 1.2.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 +21 -0
- package/README.md +87 -0
- package/dist/helpers/createCacheStorage.d.ts +5 -0
- package/dist/helpers/createCacheStorage.js +35 -0
- package/dist/helpers/deepClone.d.ts +1 -0
- package/dist/helpers/deepClone.js +53 -0
- package/dist/helpers/deepEqual.d.ts +8 -0
- package/dist/helpers/deepEqual.js +63 -0
- package/dist/helpers/index.d.ts +8 -0
- package/dist/helpers/index.js +18 -0
- package/dist/helpers/react.d.ts +26 -0
- package/dist/helpers/react.js +44 -0
- package/dist/helpers/types.d.ts +19 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +12 -0
- package/dist/libs/createContextState.d.ts +89 -0
- package/dist/libs/createContextState.js +231 -0
- package/dist/libs/createEventMethod.d.ts +24 -0
- package/dist/libs/createEventMethod.js +51 -0
- package/dist/libs/createStateManager.d.ts +48 -0
- package/dist/libs/createStateManager.js +16 -0
- package/dist/libs/createTranslator.d.ts +120 -0
- package/dist/libs/createTranslator.js +78 -0
- package/docs/helpers.md +127 -0
- package/docs/state.md +169 -0
- package/docs/utilities.md +130 -0
- package/package.json +96 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as g, jsxs as B } from "react/jsx-runtime";
|
|
3
|
+
import { createContext as N, memo as J, useRef as l, useCallback as f, forwardRef as K, useEffect as b, useSyncExternalStore as R, useContext as Q } from "react";
|
|
4
|
+
import { deepClone as T } from "../helpers/deepClone.js";
|
|
5
|
+
import { createCacheStorage as Z } from "../helpers/createCacheStorage.js";
|
|
6
|
+
import { comparePropsForMemo as tt } from "../helpers/react.js";
|
|
7
|
+
import { enableMapSet as et, enablePatches as nt, produceWithPatches as st, produce as D, applyPatches as ot } from "immer";
|
|
8
|
+
et();
|
|
9
|
+
nt();
|
|
10
|
+
const rt = `
|
|
11
|
+
❌ Compute function validation failed: Non-pure function detected
|
|
12
|
+
|
|
13
|
+
🔍 ISSUE:
|
|
14
|
+
Your compute function returns different values on consecutive calls with the same input.
|
|
15
|
+
This will cause infinite re-renders and performance issues.
|
|
16
|
+
|
|
17
|
+
📝 WHAT IS A PURE FUNCTION?
|
|
18
|
+
A pure function always returns the same output for the same input and has no side effects.
|
|
19
|
+
|
|
20
|
+
✅ VALID EXAMPLES:
|
|
21
|
+
useContextState(state => state.user.name) // ✓ Simple property access
|
|
22
|
+
useContextState(state => state.todos.length) // ✓ Deterministic computation
|
|
23
|
+
useContextState(state => state.todos.filter(t => t.done)) // ✓ Array operations on state
|
|
24
|
+
useContextState(state => ({ // ✓ Object creation with static values
|
|
25
|
+
user: state.user,
|
|
26
|
+
isLoggedIn: !!state.user,
|
|
27
|
+
staticData: 'constant'
|
|
28
|
+
}))
|
|
29
|
+
|
|
30
|
+
❌ INVALID EXAMPLES:
|
|
31
|
+
useContextState(state => Math.random()) // ✗ Random values
|
|
32
|
+
useContextState(state => new Date()) // ✗ Current time
|
|
33
|
+
useContextState(state => ({ id: Math.random() })) // ✗ Non-deterministic object properties
|
|
34
|
+
useContextState(state => state.todos.map(t => ({ // ✗ Creating new objects with random IDs
|
|
35
|
+
...t,
|
|
36
|
+
tempId: Math.random()
|
|
37
|
+
})))
|
|
38
|
+
|
|
39
|
+
🛠️ HOW TO FIX:
|
|
40
|
+
1. Remove any calls to Math.random(), Date.now(), new Date(), etc.
|
|
41
|
+
2. Avoid creating objects with non-deterministic properties
|
|
42
|
+
3. Only use state data and constants in your compute function
|
|
43
|
+
4. Move side effects outside the compute function
|
|
44
|
+
|
|
45
|
+
💡 TIP: If you need random values or timestamps, generate them in event handlers or effects,
|
|
46
|
+
then store them in state and access them in your compute function.
|
|
47
|
+
`.trim(), j = (u) => u;
|
|
48
|
+
function X() {
|
|
49
|
+
var u, i;
|
|
50
|
+
return typeof globalThis == "object" && "process" in globalThis ? (i = (u = globalThis.process) == null ? void 0 : u.env) == null ? void 0 : i.NODE_ENV : void 0;
|
|
51
|
+
}
|
|
52
|
+
function ht(u) {
|
|
53
|
+
const { cache: i, clear: v, uid: h } = Z(), I = () => ({
|
|
54
|
+
stateInstance: h(),
|
|
55
|
+
getSnapshotFunction: h(),
|
|
56
|
+
snapshotInstance: h()
|
|
57
|
+
}), m = u || h();
|
|
58
|
+
let S, p;
|
|
59
|
+
typeof window > "u" ? (S = {}, p = N(null)) : (window.__CONTEXT_STATE__ || (window.__CONTEXT_STATE__ = /* @__PURE__ */ new Map()), window.__CONTEXT_STATE__.get(m) || window.__CONTEXT_STATE__.set(m, {
|
|
60
|
+
state: {},
|
|
61
|
+
instance: N(null)
|
|
62
|
+
}), S = window.__CONTEXT_STATE__.get(m).state, p = window.__CONTEXT_STATE__.get(m).instance);
|
|
63
|
+
const P = /* @__PURE__ */ new Set(), L = {
|
|
64
|
+
getStateValue: (e = !0) => e ? T(S) : S,
|
|
65
|
+
subscribe: () => () => {
|
|
66
|
+
},
|
|
67
|
+
setState: () => () => {
|
|
68
|
+
},
|
|
69
|
+
setStateFast: () => () => {
|
|
70
|
+
},
|
|
71
|
+
emitChanges: () => {
|
|
72
|
+
},
|
|
73
|
+
setPostFlush: () => {
|
|
74
|
+
}
|
|
75
|
+
}, d = () => {
|
|
76
|
+
const e = Q(p);
|
|
77
|
+
if (!e) {
|
|
78
|
+
if (X() === "development") {
|
|
79
|
+
const t = u || "unknown";
|
|
80
|
+
P.has(t) || (P.add(t), console.warn(`ContextState not found for ${t}. Returning dummy context.`));
|
|
81
|
+
}
|
|
82
|
+
return L;
|
|
83
|
+
}
|
|
84
|
+
return e;
|
|
85
|
+
};
|
|
86
|
+
function k(e, t, n, ...s) {
|
|
87
|
+
const r = i(t(e), n, ...s), a = i(t(e), n, ...s);
|
|
88
|
+
if (r !== a)
|
|
89
|
+
throw new Error(rt);
|
|
90
|
+
}
|
|
91
|
+
function H(e) {
|
|
92
|
+
const t = l(e ?? S), n = f(
|
|
93
|
+
(o = !0) => o ? T(t.current) : t.current,
|
|
94
|
+
[]
|
|
95
|
+
), s = l(/* @__PURE__ */ new Set()), r = l(null), a = l(!1), C = typeof queueMicrotask == "function" ? queueMicrotask : (o) => {
|
|
96
|
+
Promise.resolve().then(o);
|
|
97
|
+
};
|
|
98
|
+
function c() {
|
|
99
|
+
a.current || (a.current = !0, C(() => {
|
|
100
|
+
a.current = !1, r.current && (t.current = D(t.current, r.current));
|
|
101
|
+
for (const o of s.current)
|
|
102
|
+
o();
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
const x = f((o) => {
|
|
106
|
+
r.current = o;
|
|
107
|
+
}, []), z = f((o) => (s.current.add(o), () => s.current.delete(o)), []), U = f((o) => {
|
|
108
|
+
const _ = typeof o == "function" ? o : ($) => {
|
|
109
|
+
Object.keys(o).forEach((O) => {
|
|
110
|
+
$[O] = T(o[O]);
|
|
111
|
+
});
|
|
112
|
+
}, [E, , w] = st(t.current, _), Y = () => {
|
|
113
|
+
t.current = ot(t.current, w), c();
|
|
114
|
+
};
|
|
115
|
+
return t.current = E, c(), Y;
|
|
116
|
+
}, []), q = f((o) => {
|
|
117
|
+
const _ = typeof o == "function" ? o : (E) => {
|
|
118
|
+
Object.keys(o).forEach((w) => {
|
|
119
|
+
E[w] = T(o[w]);
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
return t.current = D(t.current, _), c(), () => {
|
|
123
|
+
};
|
|
124
|
+
}, []);
|
|
125
|
+
return {
|
|
126
|
+
getStateValue: n,
|
|
127
|
+
subscribe: z,
|
|
128
|
+
setState: U,
|
|
129
|
+
setStateFast: q,
|
|
130
|
+
emitChanges: c,
|
|
131
|
+
setPostFlush: x
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const F = J(
|
|
135
|
+
function({
|
|
136
|
+
initialState: t,
|
|
137
|
+
children: n
|
|
138
|
+
}) {
|
|
139
|
+
return /* @__PURE__ */ g(p.Provider, { value: H(t), children: n });
|
|
140
|
+
},
|
|
141
|
+
tt(["children", "initialState"])
|
|
142
|
+
);
|
|
143
|
+
function y(e) {
|
|
144
|
+
function t(n) {
|
|
145
|
+
const s = e.getStateValue(!1);
|
|
146
|
+
return n ? n(s) : s;
|
|
147
|
+
}
|
|
148
|
+
return t;
|
|
149
|
+
}
|
|
150
|
+
function G(e = j, t = !0) {
|
|
151
|
+
const n = d(), s = l(I()), r = (c, x) => i(c, x, s.current.stateInstance);
|
|
152
|
+
b(() => {
|
|
153
|
+
const c = s.current.stateInstance;
|
|
154
|
+
return () => v(c);
|
|
155
|
+
}, []);
|
|
156
|
+
const a = () => r(e(n.getStateValue(!1)), s.current.getSnapshotFunction);
|
|
157
|
+
return [R(
|
|
158
|
+
n.subscribe,
|
|
159
|
+
a,
|
|
160
|
+
() => r(e(n.getStateValue(!1)), s.current.snapshotInstance)
|
|
161
|
+
), t ? n.setState : n.setStateFast, y(n)];
|
|
162
|
+
}
|
|
163
|
+
function W(e = j) {
|
|
164
|
+
const t = d(), n = l(I()), s = f(
|
|
165
|
+
(a, C) => i(a, C, n.current.stateInstance),
|
|
166
|
+
[]
|
|
167
|
+
);
|
|
168
|
+
b(() => {
|
|
169
|
+
const a = n.current.stateInstance;
|
|
170
|
+
return () => v(a);
|
|
171
|
+
}, []), X() === "development" && k(t.getStateValue(!1), e, "computeFunction", n.current.stateInstance);
|
|
172
|
+
const r = () => s(e(t.getStateValue(!1)), "getSnapshotWithComputeFunction");
|
|
173
|
+
return R(
|
|
174
|
+
t.subscribe,
|
|
175
|
+
r,
|
|
176
|
+
() => s(e(t.getStateValue(!1)), "hasComputeFunctionSnapshot")
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
function V(e = !0) {
|
|
180
|
+
const t = d();
|
|
181
|
+
return e ? t.setState : t.setStateFast;
|
|
182
|
+
}
|
|
183
|
+
function A({
|
|
184
|
+
updateStateOnDataChanged: e,
|
|
185
|
+
data: t
|
|
186
|
+
}) {
|
|
187
|
+
const n = l(!1), s = V();
|
|
188
|
+
return b(() => {
|
|
189
|
+
if (!n.current) {
|
|
190
|
+
n.current = !0;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
!e || !t || s((r) => e(r, t));
|
|
194
|
+
}, [e, t]), null;
|
|
195
|
+
}
|
|
196
|
+
function M(e, t = {}) {
|
|
197
|
+
return K((n, s) => {
|
|
198
|
+
var r;
|
|
199
|
+
return /* @__PURE__ */ B(F, { initialState: (r = t.initialState) == null ? void 0 : r.call(t, n), children: [
|
|
200
|
+
/* @__PURE__ */ g(A, { updateStateOnDataChanged: t.bindPropToState, data: n }),
|
|
201
|
+
/* @__PURE__ */ g(e, { ...n, ref: s })
|
|
202
|
+
] });
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
/** React component to provide state context */
|
|
207
|
+
Provider: F,
|
|
208
|
+
/** Hook for full state access (read + write + computed values) */
|
|
209
|
+
useContextState: G,
|
|
210
|
+
/** Hook for read-only state access with computed values */
|
|
211
|
+
useContextStateValue: W,
|
|
212
|
+
/** Hook for write-only state access */
|
|
213
|
+
useSetContextState: V,
|
|
214
|
+
/** Hook for synchronous state snapshot access */
|
|
215
|
+
useStateSnapshotGetter: () => {
|
|
216
|
+
const e = d();
|
|
217
|
+
return y(e);
|
|
218
|
+
},
|
|
219
|
+
/** Hook to register a postFlush callback (runs once per batch before subscribers) */
|
|
220
|
+
useSetPostFlush: () => d().setPostFlush,
|
|
221
|
+
/** Component for syncing external props to state */
|
|
222
|
+
StateSynchronizer: A,
|
|
223
|
+
/** @deprecated - renamed to withContextProvider */
|
|
224
|
+
withStateProvider: M,
|
|
225
|
+
/** HOC to automatically wrap components with state provider */
|
|
226
|
+
withContextProvider: M
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
export {
|
|
230
|
+
ht as createContextState
|
|
231
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type TEventData = {
|
|
2
|
+
[field: string]: unknown;
|
|
3
|
+
};
|
|
4
|
+
type TEventFunction = (data?: {
|
|
5
|
+
[field: string]: unknown;
|
|
6
|
+
}) => any | Promise<any>;
|
|
7
|
+
type TEventHandler = (data: TEventData, signal?: AbortSignal) => any | Promise<any>;
|
|
8
|
+
declare global {
|
|
9
|
+
interface Window {
|
|
10
|
+
__LVMK_EVENT_LISTENER__: Map<symbol, {
|
|
11
|
+
event: string;
|
|
12
|
+
handle: TEventHandler;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
type IsFunction<T> = T extends (...args: any[]) => any ? true : false;
|
|
17
|
+
type ExtractReturnType<T> = T extends (...args: any[]) => infer R ? Awaited<R> : never;
|
|
18
|
+
type ExtractParamType<T> = T extends (arg: infer P) => any ? P : T extends () => any ? never : never;
|
|
19
|
+
type HasParameters<T> = T extends () => any ? false : T extends (arg: any) => any ? true : false;
|
|
20
|
+
export declare function createEventMethod<CustomEventDef extends Record<string, unknown | TEventFunction>>(): {
|
|
21
|
+
useEventListener: <EventKey extends keyof CustomEventDef & string>(event: EventKey, handle: IsFunction<CustomEventDef[EventKey]> extends true ? HasParameters<CustomEventDef[EventKey]> extends true ? (eventData: ExtractParamType<CustomEventDef[EventKey]>, signal?: AbortSignal) => ExtractReturnType<CustomEventDef[EventKey]> | Promise<ExtractReturnType<CustomEventDef[EventKey]>> : (signal?: AbortSignal) => ExtractReturnType<CustomEventDef[EventKey]> | Promise<ExtractReturnType<CustomEventDef[EventKey]>> : (eventData: CustomEventDef[EventKey], signal?: AbortSignal) => Promise<void> | void) => void;
|
|
22
|
+
emitEvent: <EventKey extends keyof CustomEventDef & string>(event: EventKey, ...args: IsFunction<CustomEventDef[EventKey]> extends true ? HasParameters<CustomEventDef[EventKey]> extends true ? [data: ExtractParamType<CustomEventDef[EventKey]>] : [] : CustomEventDef[EventKey] extends undefined ? [] : [data: CustomEventDef[EventKey]]) => Promise<IsFunction<CustomEventDef[EventKey]> extends true ? ExtractReturnType<CustomEventDef[EventKey]>[] : void>;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef as c, useCallback as u, useEffect as E } from "react";
|
|
3
|
+
function f() {
|
|
4
|
+
function i(o, s) {
|
|
5
|
+
const t = c(null), l = c(s);
|
|
6
|
+
l.current = s;
|
|
7
|
+
const n = u(async (e) => {
|
|
8
|
+
try {
|
|
9
|
+
return t.current = new AbortController(), await l.current(e, t.current.signal);
|
|
10
|
+
} catch (r) {
|
|
11
|
+
if (r instanceof Error && r.name === "AbortError")
|
|
12
|
+
return;
|
|
13
|
+
throw console.error("Event handler error:", r), r;
|
|
14
|
+
}
|
|
15
|
+
}, []);
|
|
16
|
+
E(() => {
|
|
17
|
+
if (typeof window > "u") return () => {
|
|
18
|
+
};
|
|
19
|
+
window.__LVMK_EVENT_LISTENER__ || (window.__LVMK_EVENT_LISTENER__ = /* @__PURE__ */ new Map());
|
|
20
|
+
const e = Symbol();
|
|
21
|
+
return window.__LVMK_EVENT_LISTENER__.set(e, {
|
|
22
|
+
event: o,
|
|
23
|
+
handle: n
|
|
24
|
+
}), () => {
|
|
25
|
+
t.current && t.current.abort(), window.__LVMK_EVENT_LISTENER__.delete(e);
|
|
26
|
+
};
|
|
27
|
+
}, [o, n]);
|
|
28
|
+
}
|
|
29
|
+
async function _(o, ...s) {
|
|
30
|
+
if (!window.__LVMK_EVENT_LISTENER__)
|
|
31
|
+
return [];
|
|
32
|
+
const t = [], l = s[0], n = [];
|
|
33
|
+
for (const [, e] of window.__LVMK_EVENT_LISTENER__.entries()) {
|
|
34
|
+
if (e.event !== o) continue;
|
|
35
|
+
const r = e.handle(l);
|
|
36
|
+
n.push(Promise.resolve(r));
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const e = await Promise.allSettled(n);
|
|
40
|
+
for (const r of e)
|
|
41
|
+
r.status === "fulfilled" ? t.push(r.value) : console.error("Event handler failed:", r.reason);
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.error("Unexpected error in emitEvent:", e);
|
|
44
|
+
}
|
|
45
|
+
return t;
|
|
46
|
+
}
|
|
47
|
+
return { useEventListener: i, emitEvent: _ };
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
f as createEventMethod
|
|
51
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backward-compatible wrapper around createContextState.
|
|
3
|
+
*
|
|
4
|
+
* @deprecated Prefer createContextState for new code.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createStateManager<State extends Record<string | number, unknown>>(instanceId?: string): {
|
|
7
|
+
useState: <ComputedValue = State>(compute?: (state: import('../helpers/types.js').TDeepReadonly<State>) => ComputedValue, enableRevert?: boolean) => [import('../helpers/types.js').TDeepMutable<ComputedValue>, <T extends Partial<State> | ((draft: import('immer').Draft<State>) => void)>(valueOrUpdater: T) => () => void, {
|
|
8
|
+
<ComputedSnapshotValue>(compute: (input: State) => ComputedSnapshotValue): ComputedSnapshotValue;
|
|
9
|
+
(compute?: undefined): State;
|
|
10
|
+
}];
|
|
11
|
+
useStateValue: <ComputedValue = State>(compute?: (state: import('../helpers/types.js').TDeepReadonly<State>) => ComputedValue) => import('../helpers/types.js').TDeepMutable<ComputedValue>;
|
|
12
|
+
useSetState: (enableRevert?: boolean) => <T extends Partial<State> | ((draft: import('immer').Draft<State>) => void)>(valueOrUpdater: T) => () => void;
|
|
13
|
+
useSnapshot: () => {
|
|
14
|
+
<ComputedSnapshotValue>(compute: (input: State) => ComputedSnapshotValue): ComputedSnapshotValue;
|
|
15
|
+
(compute?: undefined): State;
|
|
16
|
+
};
|
|
17
|
+
withProvider: <ComponentProps>(WrappedComponent: import('react').ComponentType<ComponentProps>, config?: {
|
|
18
|
+
initialState?: ((props: import('react').PropsWithoutRef<ComponentProps>) => Partial<State>) | undefined;
|
|
19
|
+
bindPropToState?: ((draft: import('immer').Draft<State>, data: import('react').PropsWithoutRef<ComponentProps>) => void) | undefined;
|
|
20
|
+
}) => import('react').ForwardRefExoticComponent<import('react').PropsWithoutRef<ComponentProps> & import('react').RefAttributes<unknown>>;
|
|
21
|
+
Provider: import('react').NamedExoticComponent<import('react').PropsWithChildren<{
|
|
22
|
+
initialState?: Partial<State> | undefined;
|
|
23
|
+
}>>;
|
|
24
|
+
useContextState: <ComputedValue = State>(compute?: (state: import('../helpers/types.js').TDeepReadonly<State>) => ComputedValue, enableRevert?: boolean) => [import('../helpers/types.js').TDeepMutable<ComputedValue>, <T extends Partial<State> | ((draft: import('immer').Draft<State>) => void)>(valueOrUpdater: T) => () => void, {
|
|
25
|
+
<ComputedSnapshotValue>(compute: (input: State) => ComputedSnapshotValue): ComputedSnapshotValue;
|
|
26
|
+
(compute?: undefined): State;
|
|
27
|
+
}];
|
|
28
|
+
useContextStateValue: <ComputedValue = State>(compute?: (state: import('../helpers/types.js').TDeepReadonly<State>) => ComputedValue) => import('../helpers/types.js').TDeepMutable<ComputedValue>;
|
|
29
|
+
useSetContextState: (enableRevert?: boolean) => <T extends Partial<State> | ((draft: import('immer').Draft<State>) => void)>(valueOrUpdater: T) => () => void;
|
|
30
|
+
useStateSnapshotGetter: () => {
|
|
31
|
+
<ComputedSnapshotValue>(compute: (input: State) => ComputedSnapshotValue): ComputedSnapshotValue;
|
|
32
|
+
(compute?: undefined): State;
|
|
33
|
+
};
|
|
34
|
+
useSetPostFlush: () => (callback: (draft: import('immer').Draft<State>) => void) => void;
|
|
35
|
+
StateSynchronizer: <ComponentProps>({ updateStateOnDataChanged, data }: {
|
|
36
|
+
data?: ComponentProps | undefined;
|
|
37
|
+
updateStateOnDataChanged?: ((draft: import('immer').Draft<State>, data: ComponentProps) => void) | undefined;
|
|
38
|
+
}) => null;
|
|
39
|
+
withStateProvider: <ComponentProps>(WrappedComponent: import('react').ComponentType<ComponentProps>, config?: {
|
|
40
|
+
initialState?: ((props: import('react').PropsWithoutRef<ComponentProps>) => Partial<State>) | undefined;
|
|
41
|
+
bindPropToState?: ((draft: import('immer').Draft<State>, data: import('react').PropsWithoutRef<ComponentProps>) => void) | undefined;
|
|
42
|
+
}) => import('react').ForwardRefExoticComponent<import('react').PropsWithoutRef<ComponentProps> & import('react').RefAttributes<unknown>>;
|
|
43
|
+
withContextProvider: <ComponentProps>(WrappedComponent: import('react').ComponentType<ComponentProps>, config?: {
|
|
44
|
+
initialState?: ((props: import('react').PropsWithoutRef<ComponentProps>) => Partial<State>) | undefined;
|
|
45
|
+
bindPropToState?: ((draft: import('immer').Draft<State>, data: import('react').PropsWithoutRef<ComponentProps>) => void) | undefined;
|
|
46
|
+
}) => import('react').ForwardRefExoticComponent<import('react').PropsWithoutRef<ComponentProps> & import('react').RefAttributes<unknown>>;
|
|
47
|
+
};
|
|
48
|
+
export type TStateManager = ReturnType<typeof createStateManager>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContextState as a } from "./createContextState.js";
|
|
3
|
+
function n(e) {
|
|
4
|
+
const t = a(e);
|
|
5
|
+
return {
|
|
6
|
+
...t,
|
|
7
|
+
useState: t.useContextState,
|
|
8
|
+
useStateValue: t.useContextStateValue,
|
|
9
|
+
useSetState: t.useSetContextState,
|
|
10
|
+
useSnapshot: t.useStateSnapshotGetter,
|
|
11
|
+
withProvider: t.withContextProvider
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
n as createStateManager
|
|
16
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { TDeepReadonly } from '../helpers/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generic translation item type that accepts any language enum/union
|
|
5
|
+
* @template Languages - Language type (enum or union of strings)
|
|
6
|
+
*/
|
|
7
|
+
export type LocalizedString<Languages extends string> = {
|
|
8
|
+
[Language in Languages]: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Generic translation definition type that supports nested namespaces
|
|
12
|
+
* @template Languages - Language type (enum or union of strings)
|
|
13
|
+
*/
|
|
14
|
+
export type TranslationNamespace<Languages extends string> = {
|
|
15
|
+
[key: string]: LocalizedString<Languages> | TranslationNamespace<Languages>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Creates a translation function for a specific language with interpolation support
|
|
19
|
+
*
|
|
20
|
+
* This function creates a translator that:
|
|
21
|
+
* - Selects text for the specified language
|
|
22
|
+
* - Handles placeholder replacement using {key} syntax
|
|
23
|
+
* - Supports string and number interpolation
|
|
24
|
+
* - Falls back to empty string if language not found
|
|
25
|
+
*
|
|
26
|
+
* @template Language - The language type (string literal or union)
|
|
27
|
+
* @param currentLanguage - The language to translate to
|
|
28
|
+
* @returns Translation function that processes LocalizedString objects
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // Basic usage
|
|
33
|
+
* const t = createTranslator('en')
|
|
34
|
+
* const greeting = t({ en: "Hello", vi: "Xin chào" })
|
|
35
|
+
* // Returns: "Hello"
|
|
36
|
+
*
|
|
37
|
+
* // With interpolation
|
|
38
|
+
* const personalGreeting = t(
|
|
39
|
+
* { en: "Hello {name}, you have {count} messages", vi: "Xin chào {name}, bạn có {count} tin nhắn" },
|
|
40
|
+
* { name: "John", count: 5 }
|
|
41
|
+
* )
|
|
42
|
+
* // Returns: "Hello John, you have 5 messages"
|
|
43
|
+
*
|
|
44
|
+
* // Fallback behavior
|
|
45
|
+
* const t2 = createTranslator('fr')
|
|
46
|
+
* const text = t2({ en: "Hello", vi: "Xin chào" })
|
|
47
|
+
* // Returns: "" (empty string fallback)
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare const createTranslator: <Language extends string>(currentLanguage: Language) => <Translation extends LocalizedString<Language>>(translation: Translation, replace?: Record<string, string | number>) => string;
|
|
51
|
+
/**
|
|
52
|
+
* Creates a locale-specific translation factory with type safety
|
|
53
|
+
*
|
|
54
|
+
* This function returns a set of utilities for working with translations in a specific
|
|
55
|
+
* set of languages. It provides type-safe translation definitions, hooks, and functions
|
|
56
|
+
* that are bound to your language configuration.
|
|
57
|
+
*
|
|
58
|
+
* @template Languages - Union type of supported language strings
|
|
59
|
+
* @returns Object containing translation utilities for the specified languages
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* // Define your supported languages
|
|
64
|
+
* type AppLanguages = 'en' | 'vi' | 'fr'
|
|
65
|
+
*
|
|
66
|
+
* // Create locale-specific utilities
|
|
67
|
+
* const { assertTranslation, createTranslatorHook, createTranslator } = defineLocale<AppLanguages>()
|
|
68
|
+
*
|
|
69
|
+
* // Use assertTranslation for type-safe translation definitions
|
|
70
|
+
* const translations = assertTranslation({
|
|
71
|
+
* welcome: { en: "Welcome", vi: "Chào mừng", fr: "Bienvenue" },
|
|
72
|
+
* goodbye: { en: "Goodbye", vi: "Tạm biệt", fr: "Au revoir" }
|
|
73
|
+
* })
|
|
74
|
+
*
|
|
75
|
+
* // Create a translator for a specific language
|
|
76
|
+
* const t = createTranslator('en')
|
|
77
|
+
* console.log(t(translations.welcome)) // "Welcome"
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare const defineLocale: <Languages extends string>() => {
|
|
81
|
+
assertTranslation: <T extends Record<string, LocalizedString<Languages> | TranslationNamespace<Languages>>>(translation: T) => TDeepReadonly<T>;
|
|
82
|
+
createTranslatorHook: <R extends Record<string, LocalizedString<Languages> | TranslationNamespace<Languages>>>({ translation, usePreferredLanguage }: {
|
|
83
|
+
translation: R;
|
|
84
|
+
usePreferredLanguage: () => Languages;
|
|
85
|
+
}) => {
|
|
86
|
+
useTranslator: {
|
|
87
|
+
(): {
|
|
88
|
+
t: ReturnType<typeof createTranslator>;
|
|
89
|
+
d: TDeepReadonly<R>;
|
|
90
|
+
language: Languages;
|
|
91
|
+
};
|
|
92
|
+
<S>(selector: (dict: TDeepReadonly<R>) => S): {
|
|
93
|
+
t: ReturnType<typeof createTranslator>;
|
|
94
|
+
d: TDeepReadonly<S>;
|
|
95
|
+
language: Languages;
|
|
96
|
+
};
|
|
97
|
+
<K extends keyof R>(key: K): {
|
|
98
|
+
t: ReturnType<typeof createTranslator>;
|
|
99
|
+
d: TDeepReadonly<R[K]>;
|
|
100
|
+
language: Languages;
|
|
101
|
+
};
|
|
102
|
+
<K extends keyof R>(selector: ReadonlyArray<K>): {
|
|
103
|
+
t: ReturnType<typeof createTranslator>;
|
|
104
|
+
d: { [P in K]: TDeepReadonly<R[P]>; };
|
|
105
|
+
language: Languages;
|
|
106
|
+
};
|
|
107
|
+
<K extends keyof R>(firstKey: K, ...restKeys: K[]): {
|
|
108
|
+
t: ReturnType<typeof createTranslator>;
|
|
109
|
+
d: { [P in K]: TDeepReadonly<R[P]>; };
|
|
110
|
+
language: Languages;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
createNamespacedTranslatorHook: <K extends keyof R>(namespace: K) => () => {
|
|
114
|
+
t: <Translation extends LocalizedString<Languages>>(translation: Translation, replace?: Record<string, string | number>) => string;
|
|
115
|
+
d: TDeepReadonly<R[K]>;
|
|
116
|
+
language: Languages;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
createTranslator: (currentLanguage: Languages) => <Translation extends LocalizedString<Languages>>(translation: Translation, replace?: Record<string, string | number>) => string;
|
|
120
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback as T } from "react";
|
|
3
|
+
const f = (i) => (g, a) => {
|
|
4
|
+
const r = g[i] || "";
|
|
5
|
+
if (!a)
|
|
6
|
+
return r;
|
|
7
|
+
const o = Object.keys(a);
|
|
8
|
+
if (o.length === 0)
|
|
9
|
+
return r;
|
|
10
|
+
const d = Object.fromEntries(
|
|
11
|
+
o.map((n) => [n.toLowerCase(), a[n]])
|
|
12
|
+
), t = new RegExp(o.join("|"), "gi");
|
|
13
|
+
return r.replace(t, (n) => {
|
|
14
|
+
const e = d[n.toLowerCase()];
|
|
15
|
+
return e !== void 0 ? e.toString() : n;
|
|
16
|
+
});
|
|
17
|
+
}, k = () => {
|
|
18
|
+
function i(a) {
|
|
19
|
+
return a;
|
|
20
|
+
}
|
|
21
|
+
function g({
|
|
22
|
+
translation: a,
|
|
23
|
+
usePreferredLanguage: r
|
|
24
|
+
}) {
|
|
25
|
+
function o(t, ...n) {
|
|
26
|
+
const e = r(), s = T(() => f(e), [e]), u = a;
|
|
27
|
+
if (t === void 0)
|
|
28
|
+
return {
|
|
29
|
+
t: s(),
|
|
30
|
+
d: u,
|
|
31
|
+
language: e
|
|
32
|
+
};
|
|
33
|
+
if (typeof t == "function") {
|
|
34
|
+
const c = t(u);
|
|
35
|
+
return {
|
|
36
|
+
t: s(),
|
|
37
|
+
d: c,
|
|
38
|
+
language: e
|
|
39
|
+
};
|
|
40
|
+
} else {
|
|
41
|
+
const c = Array.isArray(t) ? t : [t, ...n];
|
|
42
|
+
if (c.length === 1) {
|
|
43
|
+
const l = c[0];
|
|
44
|
+
return {
|
|
45
|
+
t: s(),
|
|
46
|
+
d: u[l],
|
|
47
|
+
language: e
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const p = {};
|
|
51
|
+
return c.forEach((l) => {
|
|
52
|
+
p[l] = u[l];
|
|
53
|
+
}), {
|
|
54
|
+
t: s(),
|
|
55
|
+
d: p,
|
|
56
|
+
language: e
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { useTranslator: o, createNamespacedTranslatorHook: (t) => () => {
|
|
61
|
+
const n = r();
|
|
62
|
+
return {
|
|
63
|
+
t: T(() => f(n), [n])(),
|
|
64
|
+
d: a[t],
|
|
65
|
+
language: n
|
|
66
|
+
};
|
|
67
|
+
} };
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
assertTranslation: i,
|
|
71
|
+
createTranslatorHook: g,
|
|
72
|
+
createTranslator: f
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
export {
|
|
76
|
+
f as createTranslator,
|
|
77
|
+
k as defineLocale
|
|
78
|
+
};
|