stunk 1.2.3 → 1.2.5
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 +93 -69
- package/dist/utils.js +12 -0
- package/package.json +32 -10
- package/src/utils.ts +12 -0
package/README.md
CHANGED
|
@@ -73,30 +73,6 @@ count.set(10);
|
|
|
73
73
|
// "Double count: 20"
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
## Batch Updates
|
|
77
|
-
|
|
78
|
-
Batch Update group multiple **state changes** together and notify **subscribers** only once at the end of the **batch**. This is particularly useful for **optimizing performance** when you need to **update multiple** chunks at the same time.
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
import { chunk, batch } from "stunk";
|
|
82
|
-
|
|
83
|
-
const nameChunk = chunk("Olamide");
|
|
84
|
-
const ageChunk = chunk(30);
|
|
85
|
-
|
|
86
|
-
batch(() => {
|
|
87
|
-
nameChunk.set("AbdulAzeez");
|
|
88
|
-
ageChunk.set(31);
|
|
89
|
-
}); // Only one notification will be sent to subscribers
|
|
90
|
-
|
|
91
|
-
// Nested batches are also supported
|
|
92
|
-
batch(() => {
|
|
93
|
-
firstName.set("Olanrewaju");
|
|
94
|
-
batch(() => {
|
|
95
|
-
age.set(29);
|
|
96
|
-
});
|
|
97
|
-
}); // Only one notification will be sent to subscribers
|
|
98
|
-
```
|
|
99
|
-
|
|
100
76
|
## State Selection
|
|
101
77
|
|
|
102
78
|
Efficiently access and react to specific state parts:
|
|
@@ -120,57 +96,30 @@ nameChunk.subscribe((name) => console.log("Name changed:", name));
|
|
|
120
96
|
nameChunk.set("Olamide"); // ❌ this will throw an error, because it is a readonly.
|
|
121
97
|
```
|
|
122
98
|
|
|
123
|
-
##
|
|
124
|
-
|
|
125
|
-
Middleware allows you to customize how values are set in a **chunk**. For example, you can add **logging**, **validation**, or any custom behavior when a chunk's value changes.
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
import { chunk } from "stunk";
|
|
129
|
-
import { logger, nonNegativeValidator } from "stunk/middleware";
|
|
130
|
-
|
|
131
|
-
// You can also create yours and pass it chunk as the second param
|
|
132
|
-
|
|
133
|
-
// Use middleware for logging and validation
|
|
134
|
-
const age = chunk(25, [logger, nonNegativeValidator]);
|
|
135
|
-
|
|
136
|
-
age.set(30); // Logs: "Setting value: 30"
|
|
137
|
-
age.set(-5); // ❌ Throws an error: "Value must be non-negative!"
|
|
138
|
-
```
|
|
99
|
+
## Batch Updates
|
|
139
100
|
|
|
140
|
-
|
|
101
|
+
Batch Update group multiple **state changes** together and notify **subscribers** only once at the end of the **batch**. This is particularly useful for **optimizing performance** when you need to **update multiple** chunks at the same time.
|
|
141
102
|
|
|
142
103
|
```typescript
|
|
143
|
-
import { chunk } from "stunk";
|
|
144
|
-
import { withHistory } from "stunk/midddleware";
|
|
145
|
-
|
|
146
|
-
const counterChunk = withHistory(chunk(0));
|
|
147
|
-
|
|
148
|
-
counterChunk.set(1);
|
|
149
|
-
counterChunk.set(2);
|
|
150
|
-
|
|
151
|
-
counterChunk.undo(); // Goes back to 1
|
|
152
|
-
counterChunk.undo(); // Goes back to 0
|
|
153
|
-
|
|
154
|
-
counterChunk.redo(); // Goes forward to 1
|
|
155
|
-
|
|
156
|
-
counterChunk.canUndo(); // Returns `true` if there is a previous state to revert to..
|
|
157
|
-
counterChunk.canRedo(); // Returns `true` if there is a next state to move to.
|
|
158
|
-
|
|
159
|
-
counterChunk.getHistory(); // Returns an array of all the values in the history.
|
|
104
|
+
import { chunk, batch } from "stunk";
|
|
160
105
|
|
|
161
|
-
|
|
162
|
-
|
|
106
|
+
const nameChunk = chunk("Olamide");
|
|
107
|
+
const ageChunk = chunk(30);
|
|
163
108
|
|
|
164
|
-
|
|
165
|
-
|
|
109
|
+
batch(() => {
|
|
110
|
+
nameChunk.set("AbdulAzeez");
|
|
111
|
+
ageChunk.set(31);
|
|
112
|
+
}); // Only one notification will be sent to subscribers
|
|
166
113
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
114
|
+
// Nested batches are also supported
|
|
115
|
+
batch(() => {
|
|
116
|
+
firstName.set("Olanrewaju");
|
|
117
|
+
batch(() => {
|
|
118
|
+
age.set(29);
|
|
119
|
+
});
|
|
120
|
+
}); // Only one notification will be sent to subscribers
|
|
170
121
|
```
|
|
171
122
|
|
|
172
|
-
This prevents the history from growing indefinitely and ensures efficient memory usage.
|
|
173
|
-
|
|
174
123
|
## Computed
|
|
175
124
|
|
|
176
125
|
Computed Chunks in Stunk allow you to create state derived from other chunks in a reactive way. Unlike derived chunks, computed chunks can depend on multiple sources, and they automatically recalculate when any of the source chunks change.
|
|
@@ -200,7 +149,7 @@ firstNameChunk.set("Ola");
|
|
|
200
149
|
ageChunk.set(10);
|
|
201
150
|
|
|
202
151
|
console.log(fullInfoChunk.get());
|
|
203
|
-
// ✅ { fullName: "
|
|
152
|
+
// ✅ { fullName: "Ola Doe", isAdult: true }
|
|
204
153
|
```
|
|
205
154
|
|
|
206
155
|
Computed chunks are ideal for scenarios where state depends on multiple sources or needs complex calculations. They ensure your application remains performant and maintainable.
|
|
@@ -275,7 +224,61 @@ const filteredPostsChunk = computed(
|
|
|
275
224
|
);
|
|
276
225
|
```
|
|
277
226
|
|
|
278
|
-
##
|
|
227
|
+
## Middleware
|
|
228
|
+
|
|
229
|
+
Middleware allows you to customize how values are set in a **chunk**. For example, you can add **logging**, **validation**, or any custom behavior when a chunk's value changes.
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import { chunk } from "stunk";
|
|
233
|
+
import { logger, nonNegativeValidator } from "stunk/middleware";
|
|
234
|
+
|
|
235
|
+
// You can also create yours and pass it chunk as the second param
|
|
236
|
+
|
|
237
|
+
// Use middleware for logging and validation
|
|
238
|
+
const age = chunk(25, [logger, nonNegativeValidator]);
|
|
239
|
+
|
|
240
|
+
age.set(30); // Logs: "Setting value: 30"
|
|
241
|
+
age.set(-5); // ❌ Throws an error: "Value must be non-negative!"
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Time Travel (Middleware)
|
|
245
|
+
|
|
246
|
+
The withHistory middleware extends a chunk to support undo and redo functionality. This allows you to navigate back and forth between previous states, making it useful for implementing features like undo/redo, form history, and state time travel.
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import { chunk } from "stunk";
|
|
250
|
+
import { withHistory } from "stunk/midddleware";
|
|
251
|
+
|
|
252
|
+
const counterChunk = withHistory(chunk(0));
|
|
253
|
+
|
|
254
|
+
counterChunk.set(1);
|
|
255
|
+
counterChunk.set(2);
|
|
256
|
+
|
|
257
|
+
counterChunk.undo(); // Goes back to 1
|
|
258
|
+
counterChunk.undo(); // Goes back to 0
|
|
259
|
+
|
|
260
|
+
counterChunk.redo(); // Goes forward to 1
|
|
261
|
+
|
|
262
|
+
counterChunk.canUndo(); // Returns `true` if there is a previous state to revert to..
|
|
263
|
+
counterChunk.canRedo(); // Returns `true` if there is a next state to move to.
|
|
264
|
+
|
|
265
|
+
counterChunk.getHistory(); // Returns an array of all the values in the history.
|
|
266
|
+
|
|
267
|
+
counterChunk.clearHistory(); // Clears the history, keeping only the current value.
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Example: Limiting History Size (Optional)**
|
|
271
|
+
You can specify a max history size to prevent excessive memory usage.
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
const counter = withHistory(chunk(0), { maxHistory: 5 });
|
|
275
|
+
// Only keeps the last 5 changes -- default is 100.
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
This prevents the history from growing indefinitely and ensures efficient memory usage.
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
## State Persistence (Middleware)
|
|
279
282
|
|
|
280
283
|
Stunk provides a persistence middleware to automatically save state changes to storage (localStorage, sessionStorage, etc).
|
|
281
284
|
|
|
@@ -291,6 +294,27 @@ const counterChunk = withPersistence(chunk({ count: 0 }), {
|
|
|
291
294
|
counterChunk.set({ count: 1 });
|
|
292
295
|
```
|
|
293
296
|
|
|
297
|
+
Using Different Storage
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
// Use sessionStorage instead of localStorage
|
|
301
|
+
const sessionStorageChunk = withPersistence(baseChunk, {
|
|
302
|
+
key: "counter",
|
|
303
|
+
storage: sessionStorage,
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Custom Serialization
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
// Add custom serialization/deserialization
|
|
311
|
+
const encryptedChunk = withPersistence(baseChunk, {
|
|
312
|
+
key: "encrypted-data",
|
|
313
|
+
serialize: (value) => encrypt(JSON.stringify(value)),
|
|
314
|
+
deserialize: (value) => JSON.parse(decrypt(value)),
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
294
318
|
## Async State
|
|
295
319
|
|
|
296
320
|
Async Chunks in Stunk are designed to manage asynchronous state seamlessly. They handle loading, error, and data states automatically, making it easier to work with APIs and other asynchronous operations.
|
package/dist/utils.js
CHANGED
|
@@ -12,6 +12,18 @@ export function isChunk(value) {
|
|
|
12
12
|
typeof value.reset === 'function' &&
|
|
13
13
|
typeof value.destroy === 'function';
|
|
14
14
|
}
|
|
15
|
+
export function once(fn) {
|
|
16
|
+
let called = false;
|
|
17
|
+
let result;
|
|
18
|
+
return () => {
|
|
19
|
+
if (!called) {
|
|
20
|
+
result = fn();
|
|
21
|
+
called = true;
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
;
|
|
15
27
|
export function combineAsyncChunks(chunks) {
|
|
16
28
|
// Create initial state with proper typing
|
|
17
29
|
const initialData = Object.keys(chunks).reduce((acc, key) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stunk",
|
|
3
|
-
"version": "1.2.
|
|
4
|
-
"description": "Stunk
|
|
3
|
+
"version": "1.2.5",
|
|
4
|
+
"description": "Stunk is a lightweight, framework-agnostic state management library for JavaScript and TypeScript. It uses chunk-based state units for efficient updates, reactivity, and performance optimization in React, Vue, Svelte, and Vanilla JS/TS applications.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/I-am-abdulazeez/stunk"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/I-am-abdulazeez/stunk#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/I-am-abdulazeez/stunk/issues"
|
|
12
|
+
},
|
|
5
13
|
"main": "dist/index.js",
|
|
6
14
|
"types": "dist/types/index.d.ts",
|
|
7
15
|
"scripts": {
|
|
@@ -13,19 +21,33 @@
|
|
|
13
21
|
"keywords": [
|
|
14
22
|
"state-management",
|
|
15
23
|
"atomic-state",
|
|
24
|
+
"chunk-based state",
|
|
16
25
|
"framework-agnostic",
|
|
17
|
-
"
|
|
18
|
-
"state",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
26
|
+
"reactive state library",
|
|
27
|
+
"frontend state management",
|
|
28
|
+
"JavaScript state management",
|
|
29
|
+
"TypeScript state management",
|
|
21
30
|
"React state management",
|
|
22
31
|
"Vue state management",
|
|
23
|
-
"management",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
32
|
+
"Svelte state management",
|
|
33
|
+
"recoil alternative",
|
|
34
|
+
"jotai alternative",
|
|
35
|
+
"zustand alternative",
|
|
36
|
+
"lightweight state management",
|
|
37
|
+
"state container",
|
|
38
|
+
"reusable state",
|
|
39
|
+
"efficient state updates",
|
|
40
|
+
"performance optimization",
|
|
41
|
+
"stunk",
|
|
42
|
+
"chunk"
|
|
27
43
|
],
|
|
28
44
|
"author": "AbdulAzeez",
|
|
45
|
+
"contributors": [
|
|
46
|
+
{
|
|
47
|
+
"name": "AbdulAzeez",
|
|
48
|
+
"url": "https://github.com/I-am-abdulazeez"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
29
51
|
"license": "MIT",
|
|
30
52
|
"devDependencies": {
|
|
31
53
|
"@types/jest": "^29.5.14",
|
package/src/utils.ts
CHANGED
|
@@ -18,6 +18,18 @@ export function isChunk<T>(value: any): value is Chunk<T> {
|
|
|
18
18
|
typeof value.destroy === 'function';
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export function once<T>(fn: () => T): () => T {
|
|
22
|
+
let called = false;
|
|
23
|
+
let result: T;
|
|
24
|
+
return () => {
|
|
25
|
+
if (!called) {
|
|
26
|
+
result = fn();
|
|
27
|
+
called = true;
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
21
33
|
export function combineAsyncChunks<T extends Record<string, AsyncChunk<any>>>(
|
|
22
34
|
chunks: T
|
|
23
35
|
): Chunk<{
|