zustic 1.0.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/README.md ADDED
@@ -0,0 +1,439 @@
1
+ # Zustic
2
+
3
+ A lightweight, minimal state management library for React using `useSyncExternalStore`. Perfect for managing global state in React, React Native, and Next.js applications.
4
+
5
+ [![npm](https://img.shields.io/npm/v/zustic)](https://www.npmjs.com/package/zustic)
6
+ [![license](https://img.shields.io/npm/l/zustic)](LICENSE)
7
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/zustic)](https://bundlephobia.com/package/zustic)
8
+
9
+ ## Features
10
+
11
+ ✨ **Lightweight** - Minimal footprint with zero dependencies (except React)
12
+ ⚡ **Simple API** - Intuitive and easy to learn state management
13
+ 🎣 **React Hooks** - Use hooks to access state in your components
14
+ 📱 **Multi-Platform** - Works with React, React Native, and Next.js
15
+ 🔄 **Reactive Updates** - Automatic re-renders on state changes
16
+ 💾 **TypeScript Support** - Full TypeScript support with type safety
17
+ 🚀 **Production Ready** - Optimized for performance and reliability
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install zustic
23
+ ```
24
+
25
+ or with yarn:
26
+
27
+ ```bash
28
+ yarn add zustic
29
+ ```
30
+
31
+ or with pnpm:
32
+
33
+ ```bash
34
+ pnpm add zustic
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ### Basic Usage
40
+
41
+ ```typescript
42
+ import { create } from 'zustic';
43
+
44
+ type CounterStore = {
45
+ count: number;
46
+ inc: () => void;
47
+ dec: () => void;
48
+ reset: () => void;
49
+ };
50
+
51
+ export const useCounter = create<CounterStore>((set) => ({
52
+ count: 0,
53
+ inc: () => set((state) => ({ count: state.count + 1 })),
54
+ dec: () => set((state) => ({ count: state.count - 1 })),
55
+ reset: () => set({ count: 0 }),
56
+ }));
57
+ ```
58
+
59
+ ### Using in React Components
60
+
61
+ ```typescript
62
+ import { useCounter } from './store';
63
+
64
+ function Counter() {
65
+ const { count, inc, dec, reset } = useCounter();
66
+
67
+ return (
68
+ <div>
69
+ <p>Count: {count}</p>
70
+ <button onClick={inc}>Increment</button>
71
+ <button onClick={dec}>Decrement</button>
72
+ <button onClick={reset}>Reset</button>
73
+ </div>
74
+ );
75
+ }
76
+
77
+ export default Counter;
78
+ ```
79
+
80
+ ## API Reference
81
+
82
+ ### `create<T>(initializer)`
83
+
84
+ Creates a new store with the given state and actions.
85
+
86
+ #### Parameters
87
+
88
+ - **initializer** `(set: (partial: Partial<T> | ((state: T) => Partial<T>)) => void) => T`
89
+ - A function that receives the `set` function and returns the initial state object
90
+ - The `set` function accepts either a partial state object or a function that takes the current state and returns a partial state object
91
+
92
+ #### Returns
93
+
94
+ A React hook function that provides access to the store state.
95
+
96
+ #### Type Parameters
97
+
98
+ - **T** `extends object` - The shape of your store state
99
+
100
+ ## Advanced Examples
101
+
102
+ ### 1. Combining Multiple Stores
103
+
104
+ ```typescript
105
+ import { create } from 'zustic';
106
+
107
+ // User store
108
+ export const useUserStore = create<UserStore>((set) => ({
109
+ user: null,
110
+ setUser: (user) => set({ user }),
111
+ clearUser: () => set({ user: null }),
112
+ }));
113
+
114
+ // Todos store
115
+ export const useTodosStore = create<TodosStore>((set) => ({
116
+ todos: [],
117
+ addTodo: (todo) => set((state) => ({
118
+ todos: [...state.todos, todo]
119
+ })),
120
+ removeTodo: (id) => set((state) => ({
121
+ todos: state.todos.filter(t => t.id !== id)
122
+ })),
123
+ }));
124
+
125
+ // Use both in a component
126
+ function App() {
127
+ const user = useUserStore();
128
+ const todos = useTodosStore();
129
+
130
+ return (
131
+ <>
132
+ <User />
133
+ <TodoList />
134
+ </>
135
+ );
136
+ }
137
+ ```
138
+
139
+ ### 2. Complex State Updates
140
+
141
+ ```typescript
142
+ const useShopStore = create<ShopStore>((set) => ({
143
+ items: [],
144
+ cart: [],
145
+ total: 0,
146
+
147
+ addToCart: (item) => set((state) => ({
148
+ cart: [...state.cart, item],
149
+ total: state.total + item.price,
150
+ })),
151
+
152
+ removeFromCart: (itemId) => set((state) => ({
153
+ cart: state.cart.filter(item => item.id !== itemId),
154
+ total: state.total - state.cart.find(item => item.id === itemId)?.price || 0,
155
+ })),
156
+
157
+ clearCart: () => set({
158
+ cart: [],
159
+ total: 0,
160
+ }),
161
+ }));
162
+ ```
163
+
164
+ ### 3. Computed Values
165
+
166
+ ```typescript
167
+ const useStatsStore = create<StatsStore>((set) => ({
168
+ scores: [],
169
+
170
+ addScore: (score) => set((state) => ({
171
+ scores: [...state.scores, score],
172
+ })),
173
+
174
+ // You can compute values directly in the component
175
+ // or create selector functions
176
+ getAverage: (state) => {
177
+ if (state.scores.length === 0) return 0;
178
+ return state.scores.reduce((a, b) => a + b, 0) / state.scores.length;
179
+ },
180
+ }));
181
+
182
+ function Stats() {
183
+ const { scores, addScore, getAverage } = useStatsStore();
184
+ const average = getAverage(useStatsStore());
185
+
186
+ return <div>Average: {average}</div>;
187
+ }
188
+ ```
189
+
190
+ ### 4. Next.js Usage
191
+
192
+ ```typescript
193
+ // store/counterStore.ts
194
+ import { create } from 'zustic';
195
+
196
+ export const useCounterStore = create<CounterStore>((set) => ({
197
+ count: 0,
198
+ increment: () => set((state) => ({ count: state.count + 1 })),
199
+ decrement: () => set((state) => ({ count: state.count - 1 })),
200
+ }));
201
+ ```
202
+
203
+ ```typescript
204
+ // app/page.tsx
205
+ 'use client';
206
+
207
+ import { useCounterStore } from '@/store/counterStore';
208
+
209
+ export default function Home() {
210
+ const { count, increment, decrement } = useCounterStore();
211
+
212
+ return (
213
+ <main>
214
+ <h1>Count: {count}</h1>
215
+ <button onClick={increment}>+</button>
216
+ <button onClick={decrement}>-</button>
217
+ </main>
218
+ );
219
+ }
220
+ ```
221
+
222
+ ### 5. React Native Usage
223
+
224
+ ```typescript
225
+ import { create } from 'zustic';
226
+ import { View, Text, TouchableOpacity } from 'react-native';
227
+
228
+ const useThemeStore = create<ThemeStore>((set) => ({
229
+ isDark: false,
230
+ toggleTheme: () => set((state) => ({ isDark: !state.isDark })),
231
+ }));
232
+
233
+ function App() {
234
+ const { isDark, toggleTheme } = useThemeStore();
235
+
236
+ return (
237
+ <View style={{ backgroundColor: isDark ? '#000' : '#fff' }}>
238
+ <Text>{isDark ? 'Dark Mode' : 'Light Mode'}</Text>
239
+ <TouchableOpacity onPress={toggleTheme}>
240
+ <Text>Toggle Theme</Text>
241
+ </TouchableOpacity>
242
+ </View>
243
+ );
244
+ }
245
+ ```
246
+
247
+ ## Best Practices
248
+
249
+ ### 1. **Organize Stores**
250
+ Keep your stores organized in a dedicated directory:
251
+
252
+ ```
253
+ src/
254
+ ├── stores/
255
+ │ ├── counterStore.ts
256
+ │ ├── userStore.ts
257
+ │ └── index.ts
258
+ └── components/
259
+ ```
260
+
261
+ ### 2. **Type Your Store**
262
+ Always define proper TypeScript types for better type safety:
263
+
264
+ ```typescript
265
+ interface CounterState {
266
+ count: number;
267
+ inc: () => void;
268
+ dec: () => void;
269
+ }
270
+
271
+ export const useCounter = create<CounterState>((set) => ({
272
+ count: 0,
273
+ inc: () => set((state) => ({ count: state.count + 1 })),
274
+ dec: () => set((state) => ({ count: state.count - 1 })),
275
+ }));
276
+ ```
277
+
278
+ ### 3. **Keep State Flat**
279
+ Try to keep your state structure as flat as possible for better performance:
280
+
281
+ ```typescript
282
+ // ❌ Avoid deeply nested structures
283
+ const state = { user: { profile: { settings: { theme: 'dark' } } } };
284
+
285
+ // ✅ Prefer flat structures
286
+ const state = { userTheme: 'dark' };
287
+ ```
288
+
289
+ ### 4. **Use Immutable Updates**
290
+ Always return new objects instead of mutating state:
291
+
292
+ ```typescript
293
+ // ❌ Bad - mutating state
294
+ set((state) => {
295
+ state.items.push(newItem);
296
+ return state;
297
+ });
298
+
299
+ // ✅ Good - immutable updates
300
+ set((state) => ({
301
+ items: [...state.items, newItem],
302
+ }));
303
+ ```
304
+
305
+ ## Performance Tips
306
+
307
+ 1. **Minimize Subscriptions** - Only subscribe to the parts of the state you need
308
+ 2. **Use Memoization** - Memoize components that depend on store state
309
+ 3. **Avoid Large Objects** - Split large stores into multiple smaller ones
310
+ 4. **Batch Updates** - Group related state updates together
311
+
312
+ ## Browser Support
313
+
314
+ Zustic works in all modern browsers that support ES6 and React 16.8+.
315
+
316
+ - Chrome/Edge (latest)
317
+ - Firefox (latest)
318
+ - Safari (latest)
319
+ - Mobile browsers supporting React Native
320
+
321
+ ## Comparison
322
+
323
+ | Feature | Zustic | Zustand | Redux | Context API |
324
+ |---------|--------|---------|-------|-------------|
325
+ | Bundle Size | ~500B | ~2KB | ~7KB | - |
326
+ | Learning Curve | Very Easy | Easy | Hard | Medium |
327
+ | Boilerplate | Minimal | Minimal | Lots | Medium |
328
+ | DevTools | No | Yes | Yes | No |
329
+ | Middleware | No | Yes | Yes | No |
330
+ | TypeScript | ✅ | ✅ | ✅ | ✅ |
331
+
332
+ ## Troubleshooting
333
+
334
+ ### State not updating?
335
+ Make sure you're using the `set` function correctly. Always return a new object:
336
+
337
+ ```typescript
338
+ // ❌ Wrong
339
+ set({ count: state.count + 1 }); // state is undefined here
340
+
341
+ // ✅ Correct
342
+ set((state) => ({ count: state.count + 1 }));
343
+ ```
344
+
345
+ ### Component not re-rendering?
346
+ Ensure you're using the hook at the top level of your component:
347
+
348
+ ```typescript
349
+ // ❌ Bad
350
+ if (condition) {
351
+ const state = useStore();
352
+ }
353
+
354
+ // ✅ Good
355
+ const state = useStore();
356
+ ```
357
+
358
+ ## Migration Guide
359
+
360
+ ### From Context API
361
+
362
+ Before:
363
+ ```typescript
364
+ const CounterContext = createContext();
365
+
366
+ export function CounterProvider({ children }) {
367
+ const [count, setCount] = useState(0);
368
+
369
+ return (
370
+ <CounterContext.Provider value={{ count, setCount }}>
371
+ {children}
372
+ </CounterContext.Provider>
373
+ );
374
+ }
375
+
376
+ function useCounter() {
377
+ return useContext(CounterContext);
378
+ }
379
+ ```
380
+
381
+ After:
382
+ ```typescript
383
+ export const useCounter = create((set) => ({
384
+ count: 0,
385
+ setCount: (count) => set({ count }),
386
+ }));
387
+ ```
388
+
389
+ ### From Redux
390
+
391
+ Before:
392
+ ```typescript
393
+ const counterSlice = createSlice({
394
+ name: 'counter',
395
+ initialState: { count: 0 },
396
+ reducers: {
397
+ increment: (state) => { state.count += 1; },
398
+ },
399
+ });
400
+
401
+ export const { increment } = counterSlice.actions;
402
+ export default useSelector((state) => state.counter);
403
+ ```
404
+
405
+ After:
406
+ ```typescript
407
+ export const useCounter = create((set) => ({
408
+ count: 0,
409
+ increment: () => set((state) => ({ count: state.count + 1 })),
410
+ }));
411
+ ```
412
+
413
+ ## Contributing
414
+
415
+ Contributions are welcome! Please feel free to submit a Pull Request.
416
+
417
+ ## License
418
+
419
+ ISC © 2024 [Rejaul Karim](https://github.com/DeveloperRejaul)
420
+
421
+ ## Support
422
+
423
+ - 📖 [Documentation](https://github.com/DeveloperRejaul/zustic)
424
+ - 🐛 [Bug Reports](https://github.com/DeveloperRejaul/zustic/issues)
425
+ - 💬 [Discussions](https://github.com/DeveloperRejaul/zustic/discussions)
426
+
427
+ ## Related Projects
428
+
429
+ - [Zustand](https://github.com/pmndrs/zustand) - A small, fast and scalable bearbones state-management solution
430
+ - [Jotai](https://github.com/pmndrs/jotai) - Primitive and flexible state management for React
431
+ - [Recoil](https://recoiljs.org/) - A state management library for React
432
+
433
+ ## Changelog
434
+
435
+ ### v1.0.0 (2026)
436
+ - Initial release
437
+ - Basic state management with `create` function
438
+ - TypeScript support
439
+ - React, React Native, and Next.js compatibility
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Create a store with state and actions.
3
+ *
4
+ * Example usage:
5
+ * ```ts
6
+ * type CreateType = {
7
+ * count: number;
8
+ * inc: () => void;
9
+ * dec: () => void;
10
+ * }
11
+ *
12
+ * export const useCounter = create<CreateType>((set) => ({
13
+ * count: 1,
14
+ * inc: () => set((state) => ({ count: state.count + 1 })),
15
+ * dec: () => set((state) => ({ count: state.count - 1 })),
16
+ * })));
17
+ *
18
+ * // In a React component:
19
+ * const Counter = () => {
20
+ * const { count, inc, dec } = useCounter();
21
+ * return (
22
+ * <>
23
+ * <Text>{count}</Text>
24
+ * <Button title="+" onPress={inc} />
25
+ * <Button title="-" onPress={dec} />
26
+ * </>
27
+ * );
28
+ * }
29
+ * ```
30
+ *
31
+ * @param initializer Function that receives `set` and returns the initial state object.
32
+ * @returns A hook that provides access to the store state and actions.
33
+ */
34
+ declare function create<T extends object>(initializer: (set: (partial: Partial<T> | ((state: T) => Partial<T>)) => void) => T): () => T;
35
+
36
+ export { create };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Create a store with state and actions.
3
+ *
4
+ * Example usage:
5
+ * ```ts
6
+ * type CreateType = {
7
+ * count: number;
8
+ * inc: () => void;
9
+ * dec: () => void;
10
+ * }
11
+ *
12
+ * export const useCounter = create<CreateType>((set) => ({
13
+ * count: 1,
14
+ * inc: () => set((state) => ({ count: state.count + 1 })),
15
+ * dec: () => set((state) => ({ count: state.count - 1 })),
16
+ * })));
17
+ *
18
+ * // In a React component:
19
+ * const Counter = () => {
20
+ * const { count, inc, dec } = useCounter();
21
+ * return (
22
+ * <>
23
+ * <Text>{count}</Text>
24
+ * <Button title="+" onPress={inc} />
25
+ * <Button title="-" onPress={dec} />
26
+ * </>
27
+ * );
28
+ * }
29
+ * ```
30
+ *
31
+ * @param initializer Function that receives `set` and returns the initial state object.
32
+ * @returns A hook that provides access to the store state and actions.
33
+ */
34
+ declare function create<T extends object>(initializer: (set: (partial: Partial<T> | ((state: T) => Partial<T>)) => void) => T): () => T;
35
+
36
+ export { create };
package/dist/index.js ADDED
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
9
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
+ var __spreadValues = (a, b) => {
11
+ for (var prop in b || (b = {}))
12
+ if (__hasOwnProp.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ if (__getOwnPropSymbols)
15
+ for (var prop of __getOwnPropSymbols(b)) {
16
+ if (__propIsEnum.call(b, prop))
17
+ __defNormalProp(a, prop, b[prop]);
18
+ }
19
+ return a;
20
+ };
21
+ var __export = (target, all) => {
22
+ for (var name in all)
23
+ __defProp(target, name, { get: all[name], enumerable: true });
24
+ };
25
+ var __copyProps = (to, from, except, desc) => {
26
+ if (from && typeof from === "object" || typeof from === "function") {
27
+ for (let key of __getOwnPropNames(from))
28
+ if (!__hasOwnProp.call(to, key) && key !== except)
29
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
30
+ }
31
+ return to;
32
+ };
33
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
34
+
35
+ // src/index.ts
36
+ var index_exports = {};
37
+ __export(index_exports, {
38
+ create: () => create
39
+ });
40
+ module.exports = __toCommonJS(index_exports);
41
+ var import_react = require("react");
42
+ function create(initializer) {
43
+ let state;
44
+ let listeners = [];
45
+ const setState = (partial) => {
46
+ const partialState = typeof partial === "function" ? partial(state) : partial;
47
+ state = __spreadValues(__spreadValues({}, state), partialState);
48
+ listeners.forEach((l) => l());
49
+ };
50
+ state = initializer(setState);
51
+ const subscribe = (listener) => {
52
+ listeners.push(listener);
53
+ return () => {
54
+ listeners = listeners.filter((l) => l !== listener);
55
+ };
56
+ };
57
+ const getSnapshot = () => state;
58
+ return function useStore() {
59
+ const snapshot = (0, import_react.useSyncExternalStore)(subscribe, getSnapshot);
60
+ return snapshot;
61
+ };
62
+ }
63
+ // Annotate the CommonJS export names for ESM import in node:
64
+ 0 && (module.exports = {
65
+ create
66
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __spreadValues = (a, b) => {
8
+ for (var prop in b || (b = {}))
9
+ if (__hasOwnProp.call(b, prop))
10
+ __defNormalProp(a, prop, b[prop]);
11
+ if (__getOwnPropSymbols)
12
+ for (var prop of __getOwnPropSymbols(b)) {
13
+ if (__propIsEnum.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ }
16
+ return a;
17
+ };
18
+
19
+ // src/index.ts
20
+ import { useSyncExternalStore } from "react";
21
+ function create(initializer) {
22
+ let state;
23
+ let listeners = [];
24
+ const setState = (partial) => {
25
+ const partialState = typeof partial === "function" ? partial(state) : partial;
26
+ state = __spreadValues(__spreadValues({}, state), partialState);
27
+ listeners.forEach((l) => l());
28
+ };
29
+ state = initializer(setState);
30
+ const subscribe = (listener) => {
31
+ listeners.push(listener);
32
+ return () => {
33
+ listeners = listeners.filter((l) => l !== listener);
34
+ };
35
+ };
36
+ const getSnapshot = () => state;
37
+ return function useStore() {
38
+ const snapshot = useSyncExternalStore(subscribe, getSnapshot);
39
+ return snapshot;
40
+ };
41
+ }
42
+ export {
43
+ create
44
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "zustic",
3
+ "version": "1.0.0",
4
+ "description": "A fast, minimal state management solution for React ecosystems. Works seamlessly with React, Next.js, and React Native, offering predictable state updates with a tiny footprint.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean --external react",
10
+ "start:cjs": "node dist/cjs/index.js",
11
+ "start:esm": "node dist/esm/index.js",
12
+ "start": "ts-node src/index.ts",
13
+ "test": "npm run build && npm link"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "require": "./dist/index.js",
18
+ "import": "./dist/index.mjs"
19
+ }
20
+ },
21
+ "directories": {
22
+ "dist": "dist"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/DeveloperRejaul/zustic.git"
27
+ },
28
+ "author": "Rejaul Karim",
29
+ "license": "ISC",
30
+ "bugs": {
31
+ "url": "https://github.com/DeveloperRejaul/zustic/issues"
32
+ },
33
+ "keywords": [
34
+ "javascript",
35
+ "zustic",
36
+ "react",
37
+ "react-native",
38
+ "nextjs",
39
+ "state"
40
+ ],
41
+ "homepage": "https://github.com/DeveloperRejaul/zustic#readme",
42
+ "files": [
43
+ "dist/**/*",
44
+ "README.md"
45
+ ],
46
+ "publishConfig": {
47
+ "registry": "https://registry.npmjs.org/",
48
+ "access": "public"
49
+ },
50
+ "devDependencies": {
51
+ "@types/react": "^19.1.16",
52
+ "react": "^19.1.1",
53
+ "@types/node": "^22.7.4",
54
+ "ts-node": "^10.9.2",
55
+ "tslib": "^2.7.0",
56
+ "tsup": "^8.3.0",
57
+ "typescript": "^5.6.2"
58
+ },
59
+ "peerDependencies": {
60
+ "react": "*"
61
+ },
62
+ "sideEffects": false
63
+ }