react-state-basis 0.4.2 → 0.5.1

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/README.md CHANGED
@@ -4,416 +4,168 @@
4
4
 
5
5
  <div align="center">
6
6
 
7
- # 📐 react-state-basis
8
- ### Runtime Architectural Auditor & State Profiler for React
7
+ # react-state-basis
8
+ ### Runtime Architectural Auditor for React
9
+
10
+ **Basis tracks when state updates (never what) to catch architectural debt that standard tools miss, while keeping your data private.**
9
11
 
10
12
  [![npm version](https://img.shields.io/npm/v/react-state-basis.svg?style=flat-square)](https://www.npmjs.com/package/react-state-basis)
11
13
  [![GitHub stars](https://img.shields.io/github/stars/liovic/react-state-basis.svg?style=flat-square)](https://github.com/liovic/react-state-basis/stargazers)
12
14
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
13
15
 
14
- **Basis tracks the rhythm of state updates, not the data. It identifies redundant patterns and sync-leaks that standard tools miss.**
15
-
16
- > Stop relying on architectural intuition. Start measuring architectural debt.
17
-
18
16
  </div>
19
17
 
20
18
  ---
21
19
 
22
- ## What Does It Do?
23
-
24
- **react-state-basis** watches your React app in development and flags common architectural issues:
25
-
26
- - **Redundant state** - Two states that always update together
27
- - **Update chains** - Effects that trigger more state updates (double renders)
28
- - **Infinite loops** - Circular dependencies that freeze your browser
29
- - **Tight coupling** - State variables that should be independent but aren't
30
-
31
- It works by tracking *when* state updates happen (temporal patterns), not *what* the values are.
32
-
33
- ---
34
-
35
- ## Quick Example
36
- ```tsx
37
- // ❌ Basis will flag this
38
- const [user, setUser] = useState(null);
39
- const [isLoggedIn, setIsLoggedIn] = useState(false);
40
-
41
- useEffect(() => {
42
- setIsLoggedIn(!!user); // Double render - flagged as sync leak
43
- }, [user]);
44
-
45
- // ✅ Better
46
- const [user, setUser] = useState(null);
47
- const isLoggedIn = !!user; // Computed, no second render
48
- ```
49
-
50
- ---
51
-
52
- ## See It Work
53
-
54
- The optional HUD shows your state basis matrix in real-time:
55
-
56
- <p align="center">
57
- <img src="./assets/react-state-basis-demo.gif" width="800" alt="React State Basis Demo" />
58
- </p>
59
-
60
- ---
61
-
62
- ## Real-World Audits
63
-
64
- Basis has been tested on major open-source projects to validate detection accuracy:
65
-
66
- ### Excalidraw (114k+ ⭐)
67
- **Detected:** Causal Sync Leak in theme state synchronization
68
- **Issue:** A `useEffect` was manually syncing theme state, causing an unnecessary double render on every theme toggle
69
- **Fix:** [PR #10637](https://github.com/excalidraw/excalidraw/pull/10637) - Replaced with a computed value
70
-
71
- <p align="center">
72
- <img src="./assets/excalidraw-audit.png" width="800" alt="Excalidraw Audit" />
73
- </p>
74
-
75
- ### shadcn-admin (10k+ ⭐)
76
- **Detected:** Redundant state pattern in mobile detection hooks
77
- **Issue:** Viewport resize events were being synchronized via effects rather than direct subscriptions
78
- **Fix:** [PR #274](https://github.com/satnaing/shadcn-admin/pull/274) - Optimized subscription pattern
79
-
80
- <p align="center">
81
- <img src="./assets/shadcn-admin.png" width="800" alt="shadcn Admin Audit" />
82
- </p>
83
-
84
- > **Note:** These are proposed architectural improvements. Basis points out patterns worth investigating - the final decision rests with the maintainer.
85
-
86
- ---
87
-
88
- ## Setup (Vite)
20
+ ## Quick Start
89
21
 
90
22
  ### 1. Install
91
23
  ```bash
92
24
  npm i react-state-basis
93
25
  ```
94
26
 
95
- ### 2. Add to `vite.config.ts`
96
- ```tsx
97
- import { defineConfig } from 'vite';
98
- import react from '@vitejs/plugin-react';
27
+ ### 2. Setup (Vite)
28
+ Add the plugin to your `vite.config.ts`. The Babel plugin auto-labels your hooks—you continue importing from `react` as normal.
29
+
30
+ ```ts
99
31
  import { basis } from 'react-state-basis/vite';
100
32
 
101
33
  export default defineConfig({
102
34
  plugins: [
103
- react({
104
- babel: { plugins: [['react-state-basis/plugin']] }
35
+ react({
36
+ babel: { plugins: [['react-state-basis/plugin']] }
105
37
  }),
106
38
  basis()
107
39
  ]
108
40
  });
109
41
  ```
110
42
 
111
- ### 3. Wrap your app
43
+ ### 3. Initialize
112
44
  ```tsx
113
45
  import { BasisProvider } from 'react-state-basis';
114
46
 
115
47
  root.render(
116
- <BasisProvider debug={true}>
48
+ <BasisProvider
49
+ debug={true}
50
+ showHUD={true} // Set to false for console-only forensics
51
+ >
117
52
  <App />
118
53
  </BasisProvider>
119
54
  );
120
55
  ```
121
56
 
122
- ### 4. Verify It's Working
57
+ ### 4. Verify the Signal
58
+ Drop this pattern into any component. Basis will identify the rhythm of the debt within ~100ms.
123
59
 
124
- Add this test pattern to any component:
125
60
  ```tsx
126
61
  const [a, setA] = useState(0);
127
62
  const [b, setB] = useState(0);
128
63
 
129
64
  useEffect(() => {
130
- setB(a); // Basis will flag this
65
+ setB(a); // BASIS: "Double Render Detected"
131
66
  }, [a]);
132
- ```
133
67
 
134
- Trigger an update (e.g., click a button that calls `setA(1)`). You should see a console alert within ~100ms.
135
-
136
- ---
137
-
138
- ## What You'll See
139
-
140
- ### Console Alerts
141
-
142
- **Redundant Pattern:**
143
- Detected when two variables move in perfect unison.
144
- ```
145
- 📐 BASIS | REDUNDANT PATTERN
146
- 📍 Location: TodoList.tsx
147
- Observation: "todos" and "count" move together.
148
- One is likely a direct mirror of the other. Confidence: 94%
149
- Action: Refactor "count" to useMemo.
68
+ return <button onClick={() => setA(a + 1)}>Pulse Basis</button>;
150
69
  ```
151
70
 
152
- **Sync Leak (Causal Chain):**
153
- Detected when one variable consistently triggers another with a temporal lag.
71
+ Click the button. You should see this in your console within ~100ms:
154
72
  ```
155
- 💡 BASIS | DETECTED SYNC LEAK
156
- 📍 Location: AuthProvider.tsx
157
- Flow: user Effect isLoggedIn
158
- Context: The engine detected a consistent 20ms lag between these updates.
159
- Result: This creates a Double Render Cycle.
73
+ BASIS | DOUBLE RENDER
74
+ 📍 Location: YourComponent.tsx
75
+ Issue: a triggers b in a separate frame.
76
+ Fix: Derive b during the first render.
160
77
  ```
161
78
 
162
- **Infinite Loop:**
163
- Detected when a variable updates too rapidly (circuit breaker).
164
- ```
165
- 🛑 BASIS CRITICAL | CIRCUIT BREAKER
166
- Infinite oscillation detected on: "counter"
167
- Execution halted to prevent browser thread lock.
168
- ```
169
-
170
- ### Health Report
171
-
172
- Check your entire app's state architecture:
173
- ```tsx
174
- window.printBasisReport();
175
- ```
176
-
177
- Shows:
178
- - **Health Score** - Percentage of independent vs. synchronized state
179
- - **Synchronized Clusters** - Groups of variables that move together
180
- - **Correlation Matrix** - Full pairwise similarity analysis (for <15 variables)
181
-
182
- ### Hardware Telemetry
183
-
184
- Verify engine efficiency and heap stability in real-time:
185
-
186
- ```tsx
187
- window.getBasisMetrics();
188
- ```
189
-
190
- Returns: Engine execution time, active hook count, and current memory allocation strategy.
191
-
192
79
  ---
193
80
 
194
- ## How It Works (v0.4.x)
81
+ ### 5. Control & Scope
82
+ * **Ghost Mode:** Disable the Matrix UI while keeping console-based forensics active by setting `showHUD={false}` on the provider.
83
+ * **Selective Auditing:** Add `// @basis-ignore` at the top of any file to disable instrumentation. Recommended for:
84
+ * High-frequency animation logic (>60fps)
85
+ * Third-party library wrappers
86
+ * Intentional synchronization (e.g., local mirrors of external caches)
195
87
 
196
- ### Temporal Cross-Correlation
197
-
198
- Basis tracks **when** state updates occur, creating a 50-tick timeline for each variable:
199
- ```
200
- useState("count"): [0,0,1,0,0,1,1,0,...] (updates at ticks 2, 5, 6)
201
- useState("total"): [0,0,1,0,0,1,1,0,...] (same pattern)
202
- ↑ Redundant: identical temporal signature
203
- ```
204
-
205
- For every pair of variables, Basis checks three temporal relationships:
206
-
207
- 1. **Synchronous (Redundancy):** Do they update in the same tick?
208
- ```
209
- A: [0,1,0,1,0,...]
210
- B: [0,1,0,1,0,...] → Flagged as redundant
211
- ```
212
-
213
- 2. **Lead-Lag (A → B):** Does B consistently follow A in the next tick?
214
- ```
215
- A: [0,1,0,1,0,...]
216
- B: [0,0,1,0,1,...] → B follows A (sync leak detected)
217
- ```
218
-
219
- 3. **Lead-Lag (B → A):** Does A consistently follow B?
220
- ```
221
- A: [0,0,1,0,1,...]
222
- B: [0,1,0,1,0,...] → A follows B (reverse causality)
223
- ```
224
-
225
- The engine uses **offset-based comparison** to check these patterns without allocating temporary arrays, ensuring minimal overhead even at high frame rates.
226
-
227
- ### Performance Optimizations
88
+ ---
228
89
 
229
- - **Idle Filtering:** Only analyzes variables with 2+ updates, reducing pairwise comparisons by ~90% in typical applications (measured on Excalidraw's 47-hook codebase)
230
- - **Batched Analysis:** Runs every 5 ticks (~100ms) to avoid impacting frame budget
231
- - **Console Throttling:** Same alert won't repeat within 5 seconds
232
- - **Zero Production Overhead:** Entire library is replaced with no-op shims in production builds
90
+ ## Visual Proof
233
91
 
234
- ### What Gets Flagged?
92
+ The optional HUD shows your **State Basis Matrix** in real-time. Purple pulses ($\Omega$) are Context anchors; Red pulses (!) are redundant shadows.
235
93
 
236
- **Redundant Pattern Example:**
237
- ```tsx
238
- // ❌ Before (Basis flags this)
239
- const [count, setCount] = useState(0);
240
- const [doubled, setDoubled] = useState(0);
94
+ <p align="center">
95
+ <img src="./assets/050Basis.gif" width="800" alt="Basis v0.5.0 Demo" />
96
+ </p>
241
97
 
242
- useEffect(() => {
243
- setDoubled(count * 2);
244
- }, [count]);
98
+ ---
245
99
 
246
- // After (Basis suggestion)
247
- const [count, setCount] = useState(0);
248
- const doubled = useMemo(() => count * 2, [count]);
249
- ```
100
+ ## What Basis Detects
250
101
 
251
- **Sync Leak Example:**
252
- ```tsx
253
- // ❌ Before (causes double render)
254
- const [user, setUser] = useState(null);
255
- const [isLoggedIn, setIsLoggedIn] = useState(false);
102
+ Basis treats every hook as a signal to catch these architectural violations:
256
103
 
257
- useEffect(() => {
258
- setIsLoggedIn(!!user);
259
- }, [user]);
104
+ - **Ω Context Mirroring** - Local state shadowing global context
105
+ - **♊ Duplicate State** - Independent variables that always update together
106
+ - **⚡ Sync Leaks** - 1-frame delays forcing double renders
107
+ - **🛑 Recursive Oscillation** - Infinite loops (with circuit breaker)
260
108
 
261
- // After (single render)
262
- const [user, setUser] = useState(null);
263
- const isLoggedIn = !!user; // Derived, no effect needed
264
- ```
109
+ [**See examples & fixes →**](https://github.com/liovic/react-state-basis/wiki/The-Forensic-Catalog)
265
110
 
266
111
  ---
267
112
 
268
- ## Production Safety
269
-
270
- In production builds, the entire tool is replaced with zero-op shims. **Zero runtime overhead. Zero bundle size increase.**
271
- ```json
272
- // package.json - automatic based on NODE_ENV
273
- "exports": {
274
- ".": {
275
- "development": "./dist/index.mjs",
276
- "production": "./dist/production.mjs", // No-op shims
277
- "default": "./dist/production.mjs"
278
- }
279
- }
280
- ```
113
+ ## Reports & Telemetry
281
114
 
282
- ---
283
-
284
- ## When to Skip Files
115
+ ### Architectural Health Report
116
+ Check your entire app's state architecture by running `window.printBasisReport()` in the console.
285
117
 
286
- Add `// @basis-ignore` at the top of a file to disable instrumentation:
287
- ```tsx
288
- // @basis-ignore
289
- // This file contains external protocols or hardware-bound synchronization outside the scope of architectural auditing.
290
- ```
118
+ * **Efficiency Score:** Ratio of independent signals to total hooks.
119
+ * **Entangled Clusters:** Groups of variables that move in sync (Boolean Explosion).
120
+ * **Correlation Matrix:** Raw pairwise similarity data for deep-dive forensics.
291
121
 
292
- **Good candidates for skipping:**
293
- - **High-frequency animations** (>60fps state updates)
294
- - **WebSocket message handlers** (rapid, intentional updates)
295
- - **Canvas/WebGL render loops** (performance-critical paths)
296
- - **Intentional synchronization** (e.g., React Query → local cache mirrors)
297
- - **Third-party library wrappers** (where you don't control the architecture)
122
+ ### Hardware Telemetry
123
+ Verify engine efficiency and heap stability in real-time via `window.getBasisMetrics()`.
298
124
 
299
125
  ---
300
126
 
301
- ## Comparison to Other Tools
127
+ ## Real-World Evidence
302
128
 
303
- | Tool | Focus | When to Use |
304
- |------|-------|-------------|
305
- | **React DevTools** | Component hierarchy & values | Debugging specific components |
306
- | **Why Did You Render** | Re-render optimization | Performance tuning renders |
307
- | **ESLint exhaustive-deps** | Static dependency analysis | Preventing missing deps |
308
- | **react-state-basis** | **Temporal state relationships** | **Finding redundant state & effect chains** |
129
+ Basis is verified against industry-standard codebases to ensure high-fidelity detection:
309
130
 
310
- These tools are complementary - use them together for best results.
131
+ * **Excalidraw (114k⭐)** - Caught a theme-sync leak forcing a double-render on every toggle. [**PR #10637**](https://github.com/excalidraw/excalidraw/pull/10637)
132
+ * **shadcn-admin (10k⭐)** - Detected redundant state pattern in viewport detection hooks. [**PR #274**](https://github.com/satnaing/shadcn-admin/pull/274)
311
133
 
312
134
  ---
313
135
 
314
- ## Performance Impact (Measured)
315
-
316
- **Development Mode**
317
-
318
- **Basis is designed to be statistically invisible to the main thread.**
136
+ ## Performance & Privacy
319
137
 
320
- The v0.4.2 **Flat Memory Architecture** utilizes `Uint8Array` Ring Buffers to eliminate Garbage Collection (GC) churn and provide constant-time $O(1)$ telemetry recording.
138
+ **Development:** <1ms overhead per update cycle, zero heap growth
139
+ **Production:** ~0.01ms per hook (monitoring disabled, ~2-3KB bundle)
140
+ **Privacy:** Only tracks update timing, never state values
321
141
 
322
- ### Audited Benchmarks
323
-
324
- These metrics were recorded during a **20-minute high-frequency endurance audit** (1.2M state pulses) using the built-in **Stress Lab**.
325
-
326
- * **Logic Execution Overhead:** < 1.0ms per 100-hook update cycle.
327
- * **Memory Profile:** **0 Delta heap growth.** (Static allocation via Ring Buffers).
328
- * **Interaction Latency (INP):** ~56ms during continuous 50-hook concurrency tests (Green Zone).
329
- * **Drawing Efficiency:** ~15ms drawing cost via Path2D GPU-batching.
330
-
331
- > 🔍 **Forensic Proof:** Detailed heap snapshots, modulo-tax analysis, and linearized math benchmarks are documented in the [**v0.4.2 Performance RFC (#33)**](https://github.com/liovic/react-state-basis/issues/33).
332
-
333
- <p align="center">
334
- <img src="./assets/perf.gif" width="800" alt="Basis Stress Lab" />
335
- </p>
336
-
337
-
338
-
339
- **Production Mode:**
340
- - Overhead: ~0.01ms per hook call (negligible wrapper overhead)
341
- - Bundle size: ~2-3 KB minified (no-op wrappers only, no analysis engine)
342
- - Monitoring logic: 100% removed
343
- - HUD component: 100% removed
142
+ [**See benchmarks →**](https://github.com/liovic/react-state-basis/wiki/Performance-Forensics)
344
143
 
345
144
  ---
346
145
 
347
- ## Limitations (v0.4.x)
146
+ ## Documentation & Theory
348
147
 
349
- **What works well:**
350
- - ✅ Detecting synchronous redundant state
351
- - ✅ Flagging effect-driven update chains (A → Effect → B)
352
- - ✅ Catching infinite loops before browser freeze
353
- - ✅ Distinguishing causality from redundancy
354
-
355
- **Known edge cases:**
356
- - ⚠️ **Async gaps:** Updates delayed by >40ms (e.g., slow API responses) may appear independent
357
- - ⚠️ **Intentional sync:** Sometimes synchronization is required for library compatibility
358
- - ⚠️ **Complex multi-way dependencies:** Three or more interconnected states might not show full relationship graph
359
- - ⚠️ **Requires judgment:** Tool points out patterns worth investigating - you decide if they're issues
360
-
361
- **Heuristic interpretation requires context. Always verify architectural intent before refactoring.**.
148
+ Basis is built on heuristics inspired by **Linear Algebra** and **Signal Processing**. To understand the underlying math, visit the [**Full Wiki**](https://github.com/liovic/react-state-basis/wiki).
362
149
 
363
150
  ---
364
151
 
365
152
  ## Roadmap
366
153
 
367
- ### v0.4.x
368
- - [x] **v0.4.0**: Temporal Cross-Correlation Engine (Lead-Lag Analysis)
369
- - [x] **v0.4.1:** Density Filtering (Eliminate false positives from animations/sliders)
370
- - [x] v0.4.2: Ring Buffer (Zero-jank memory management for 500+ hooks) [**v0.4.2 Performance RFC (#33)**](https://github.com/liovic/react-state-basis/issues/33)
154
+ Each era of Basis answers a different architectural question:
371
155
 
156
+ ✓ **v0.4.x** - The Correlation Era - *Are these states moving together?*
157
+ → **v0.5.x** - The Decomposition Era - *Is this local state just a copy of Context?*
158
+ **v0.6.x** - The Graph Era - *Which bug should I fix first for maximum impact?*
159
+ **v0.7.x** - The Information Era - *Does this state carry real information, or is it derivative?*
160
+ **v0.8.x** - The Manifold Era - *How many hooks does your component actually need?*
372
161
 
373
- ### v0.5.0 (Planned)
374
- - [ ] Zustand & Redux middleware integration
375
- - [ ] Visual dependency graph in HUD
376
- - [ ] Historical trend tracking across sessions
377
162
 
378
- ### Future Ideas
379
- - [ ] Domain isolation analysis (detect feature boundaries)
380
- - [ ] Export audit reports for team reviews
381
- - [ ] CI integration for architectural regressions
382
-
383
- ---
384
-
385
- ## FAQ
386
-
387
- **Q: Will this slow down my app?**
388
- A: Only in development (~0.3ms per update). Production builds have zero overhead.
389
-
390
- **Q: Do I have to change my code?**
391
- A: No. The Babel plugin instruments hooks automatically.
392
-
393
- **Q: What if it flags something that's not a problem?**
394
- A: Use your judgment. Basis is a diagnostic tool that points out patterns worth investigating - not all flagged patterns are bugs.
395
-
396
- **Q: How is this different from Redux DevTools?**
397
- A: Redux DevTools shows state values and action history. Basis shows temporal relationships between state variables, regardless of what state management library you use.
398
-
399
- **Q: Why "basis"?**
400
- A: In linear algebra, a "basis" is a minimal set of independent vectors. The name reflects the goal of finding your app's minimal independent state - removing redundancy.
401
-
402
- **Q: How is this different from Redux DevTools?**
403
- A: Redux DevTools is a **Journal** - it logs specific values and actions within a Redux store. Basis is an **Architectural Auditor** - it instruments React's core primitives (useState, useReducer, useEffect) to detect hidden relationships between entirely separate components and hooks, even when they don't share a store. Redux DevTools answers "what changed and why?" while Basis answers "is this state architecture clean?"
404
-
405
- ---
406
-
407
- ## Contributing
408
-
409
- Found a bug? Have an idea? Open an issue or PR.
410
-
411
- For technical details on how the detection works, see the [Wiki](https://github.com/liovic/react-state-basis/wiki).
163
+ [**More info**](https://github.com/liovic/react-state-basis/wiki/Roadmap)
412
164
 
413
165
  ---
414
166
 
415
167
  <div align="center">
416
168
 
417
- Built by [LP](https://github.com/liovic) • MIT License
169
+ Built by [LP](https://github.com/liovic) • [MIT License](https://opensource.org/licenses/MIT)
418
170
 
419
- </div>
171
+ </div>
package/dist/index.d.mts CHANGED
@@ -3,47 +3,55 @@ import React__default, { ReactNode } from 'react';
3
3
  export { basis } from './vite-plugin.mjs';
4
4
  import 'vite';
5
5
 
6
- declare const configureBasis: (c: any) => void;
7
6
  /**
8
- * DISPLAY: window.printBasisReport()
7
+ * Standard React Reducer type inference helpers.
9
8
  */
10
- declare const printBasisHealthReport: (threshold?: number) => void;
11
- declare const getBasisMetrics: () => {
12
- engine: string;
13
- hooks: number;
14
- load: number;
15
- analysis_ms: string;
16
- };
17
-
18
9
  type GetReducerState<R extends React.Reducer<any, any>> = R extends React.Reducer<infer S, any> ? S : never;
19
10
  type GetReducerAction<R extends React.Reducer<any, any>> = R extends React.Reducer<any, infer A> ? A : never;
20
11
  declare function useState<S>(initialState: S | (() => S), label?: string): [S, React.Dispatch<React.SetStateAction<S>>];
21
- declare function useRef<T>(initialValue: T): React.RefObject<T>;
22
- declare function useRef<T>(initialValue: T | null): React.RefObject<T>;
23
- declare function useRef<T = undefined>(): React.MutableRefObject<T | undefined>;
24
- declare function useReducer<R extends React.Reducer<any, any>, I>(reducer: R, initialArg: I, init?: any, label?: string): [GetReducerState<R>, React.Dispatch<GetReducerAction<R>>];
12
+ /**
13
+ * PUBLIC OVERLOAD: Lazy initialization
14
+ */
15
+ declare function useReducer<R extends React.Reducer<any, any>, I>(reducer: R, initializerArg: I, initializer: (arg: I) => GetReducerState<R>, label?: string): [GetReducerState<R>, React.Dispatch<GetReducerAction<R>>];
16
+ /**
17
+ * PUBLIC OVERLOAD: Direct initialization
18
+ */
19
+ declare function useReducer<R extends React.Reducer<any, any>>(reducer: R, initialState: GetReducerState<R>, initializer?: undefined, label?: string): [GetReducerState<R>, React.Dispatch<GetReducerAction<R>>];
20
+ declare function createContext<T>(defaultValue: T, label?: string): React.Context<T>;
21
+ declare function useContext<T>(context: React.Context<T>): T;
25
22
  declare function useMemo<T>(factory: () => T, deps: React.DependencyList | undefined, label?: string): T;
26
- declare function useCallback<T extends (...args: any[]) => any>(callback: T, deps: React.DependencyList, label?: string): T;
23
+ declare function useCallback<T extends (...args: unknown[]) => unknown>(callback: T, deps: React.DependencyList, label?: string): T;
27
24
  declare function useEffect(effect: React.EffectCallback, deps?: React.DependencyList, label?: string): void;
28
25
  declare function useLayoutEffect(effect: React.EffectCallback, deps?: React.DependencyList, label?: string): void;
29
- declare function useTransition(_label?: string): [boolean, (callback: () => void) => void];
30
- declare function useDeferredValue<T>(value: T, initialValueOrLabel?: T | string, label?: string): T;
31
- declare const useId: (label?: string) => string;
26
+ declare function useOptimistic<S, P>(passthrough: S, reducer?: (state: S, payload: P) => S, label?: string): [S, (payload: P) => void];
27
+ declare function useActionState<State, Payload>(action: (state: State, payload: Payload) => Promise<State> | State, initialState: State, permalink?: string, label?: string): [state: State, dispatch: (payload: Payload) => void, isPending: boolean];
28
+ declare const useRef: typeof React.useRef;
29
+ declare const useId: typeof React.useId;
32
30
  declare const useDebugValue: typeof React.useDebugValue;
33
31
  declare const useImperativeHandle: typeof React.useImperativeHandle;
34
32
  declare const useInsertionEffect: typeof React.useInsertionEffect;
35
- declare const useSyncExternalStore: any;
36
- declare function use<T>(usable: React.Usable<T>): T;
37
- declare function useOptimistic<S, P>(passthrough: S, reducer?: (state: S, payload: P) => S, label?: string): [S, (payload: P) => void];
38
- declare function useActionState<State, Payload>(action: (state: State, payload: Payload) => Promise<State> | State, initialState: State, permalink?: string, label?: string): [state: State, dispatch: (payload: Payload) => void, isPending: boolean];
33
+ declare const useSyncExternalStore: typeof React.useSyncExternalStore;
34
+ declare const useTransition: typeof React.useTransition;
35
+ declare const useDeferredValue: typeof React.useDeferredValue;
36
+ declare const use: <T>(usable: React.Usable<T>) => T;
39
37
 
40
38
  interface BasisProviderProps {
41
39
  children: ReactNode;
42
40
  debug?: boolean;
41
+ showHUD?: boolean;
43
42
  }
44
43
  declare const BasisProvider: React__default.FC<BasisProviderProps>;
45
44
  declare const useBasisConfig: () => {
46
45
  debug: boolean;
47
46
  };
48
47
 
49
- export { BasisProvider, configureBasis, getBasisMetrics, printBasisHealthReport, use, useActionState, useBasisConfig, useCallback, useDebugValue, useDeferredValue, useEffect, useId, useImperativeHandle, useInsertionEffect, useLayoutEffect, useMemo, useOptimistic, useReducer, useRef, useState, useSyncExternalStore, useTransition };
48
+ declare const configureBasis: (c: any) => void;
49
+ declare const printBasisHealthReport: (threshold?: number) => void;
50
+ declare const getBasisMetrics: () => {
51
+ engine: string;
52
+ hooks: number;
53
+ analysis_ms: string;
54
+ entropy: string;
55
+ };
56
+
57
+ export { BasisProvider, configureBasis, createContext, getBasisMetrics, printBasisHealthReport, use, useActionState, useBasisConfig, useCallback, useContext, useDebugValue, useDeferredValue, useEffect, useId, useImperativeHandle, useInsertionEffect, useLayoutEffect, useMemo, useOptimistic, useReducer, useRef, useState, useSyncExternalStore, useTransition };
package/dist/index.d.ts CHANGED
@@ -3,47 +3,55 @@ import React__default, { ReactNode } from 'react';
3
3
  export { basis } from './vite-plugin.js';
4
4
  import 'vite';
5
5
 
6
- declare const configureBasis: (c: any) => void;
7
6
  /**
8
- * DISPLAY: window.printBasisReport()
7
+ * Standard React Reducer type inference helpers.
9
8
  */
10
- declare const printBasisHealthReport: (threshold?: number) => void;
11
- declare const getBasisMetrics: () => {
12
- engine: string;
13
- hooks: number;
14
- load: number;
15
- analysis_ms: string;
16
- };
17
-
18
9
  type GetReducerState<R extends React.Reducer<any, any>> = R extends React.Reducer<infer S, any> ? S : never;
19
10
  type GetReducerAction<R extends React.Reducer<any, any>> = R extends React.Reducer<any, infer A> ? A : never;
20
11
  declare function useState<S>(initialState: S | (() => S), label?: string): [S, React.Dispatch<React.SetStateAction<S>>];
21
- declare function useRef<T>(initialValue: T): React.RefObject<T>;
22
- declare function useRef<T>(initialValue: T | null): React.RefObject<T>;
23
- declare function useRef<T = undefined>(): React.MutableRefObject<T | undefined>;
24
- declare function useReducer<R extends React.Reducer<any, any>, I>(reducer: R, initialArg: I, init?: any, label?: string): [GetReducerState<R>, React.Dispatch<GetReducerAction<R>>];
12
+ /**
13
+ * PUBLIC OVERLOAD: Lazy initialization
14
+ */
15
+ declare function useReducer<R extends React.Reducer<any, any>, I>(reducer: R, initializerArg: I, initializer: (arg: I) => GetReducerState<R>, label?: string): [GetReducerState<R>, React.Dispatch<GetReducerAction<R>>];
16
+ /**
17
+ * PUBLIC OVERLOAD: Direct initialization
18
+ */
19
+ declare function useReducer<R extends React.Reducer<any, any>>(reducer: R, initialState: GetReducerState<R>, initializer?: undefined, label?: string): [GetReducerState<R>, React.Dispatch<GetReducerAction<R>>];
20
+ declare function createContext<T>(defaultValue: T, label?: string): React.Context<T>;
21
+ declare function useContext<T>(context: React.Context<T>): T;
25
22
  declare function useMemo<T>(factory: () => T, deps: React.DependencyList | undefined, label?: string): T;
26
- declare function useCallback<T extends (...args: any[]) => any>(callback: T, deps: React.DependencyList, label?: string): T;
23
+ declare function useCallback<T extends (...args: unknown[]) => unknown>(callback: T, deps: React.DependencyList, label?: string): T;
27
24
  declare function useEffect(effect: React.EffectCallback, deps?: React.DependencyList, label?: string): void;
28
25
  declare function useLayoutEffect(effect: React.EffectCallback, deps?: React.DependencyList, label?: string): void;
29
- declare function useTransition(_label?: string): [boolean, (callback: () => void) => void];
30
- declare function useDeferredValue<T>(value: T, initialValueOrLabel?: T | string, label?: string): T;
31
- declare const useId: (label?: string) => string;
26
+ declare function useOptimistic<S, P>(passthrough: S, reducer?: (state: S, payload: P) => S, label?: string): [S, (payload: P) => void];
27
+ declare function useActionState<State, Payload>(action: (state: State, payload: Payload) => Promise<State> | State, initialState: State, permalink?: string, label?: string): [state: State, dispatch: (payload: Payload) => void, isPending: boolean];
28
+ declare const useRef: typeof React.useRef;
29
+ declare const useId: typeof React.useId;
32
30
  declare const useDebugValue: typeof React.useDebugValue;
33
31
  declare const useImperativeHandle: typeof React.useImperativeHandle;
34
32
  declare const useInsertionEffect: typeof React.useInsertionEffect;
35
- declare const useSyncExternalStore: any;
36
- declare function use<T>(usable: React.Usable<T>): T;
37
- declare function useOptimistic<S, P>(passthrough: S, reducer?: (state: S, payload: P) => S, label?: string): [S, (payload: P) => void];
38
- declare function useActionState<State, Payload>(action: (state: State, payload: Payload) => Promise<State> | State, initialState: State, permalink?: string, label?: string): [state: State, dispatch: (payload: Payload) => void, isPending: boolean];
33
+ declare const useSyncExternalStore: typeof React.useSyncExternalStore;
34
+ declare const useTransition: typeof React.useTransition;
35
+ declare const useDeferredValue: typeof React.useDeferredValue;
36
+ declare const use: <T>(usable: React.Usable<T>) => T;
39
37
 
40
38
  interface BasisProviderProps {
41
39
  children: ReactNode;
42
40
  debug?: boolean;
41
+ showHUD?: boolean;
43
42
  }
44
43
  declare const BasisProvider: React__default.FC<BasisProviderProps>;
45
44
  declare const useBasisConfig: () => {
46
45
  debug: boolean;
47
46
  };
48
47
 
49
- export { BasisProvider, configureBasis, getBasisMetrics, printBasisHealthReport, use, useActionState, useBasisConfig, useCallback, useDebugValue, useDeferredValue, useEffect, useId, useImperativeHandle, useInsertionEffect, useLayoutEffect, useMemo, useOptimistic, useReducer, useRef, useState, useSyncExternalStore, useTransition };
48
+ declare const configureBasis: (c: any) => void;
49
+ declare const printBasisHealthReport: (threshold?: number) => void;
50
+ declare const getBasisMetrics: () => {
51
+ engine: string;
52
+ hooks: number;
53
+ analysis_ms: string;
54
+ entropy: string;
55
+ };
56
+
57
+ export { BasisProvider, configureBasis, createContext, getBasisMetrics, printBasisHealthReport, use, useActionState, useBasisConfig, useCallback, useContext, useDebugValue, useDeferredValue, useEffect, useId, useImperativeHandle, useInsertionEffect, useLayoutEffect, useMemo, useOptimistic, useReducer, useRef, useState, useSyncExternalStore, useTransition };