storion 0.2.2 โ†’ 0.2.3

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.
Files changed (2) hide show
  1. package/README.md +133 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -382,6 +382,139 @@ instance.subscribe("@save", (event) => {
382
382
  });
383
383
  ```
384
384
 
385
+ ### ๐Ÿงฉ Mixins โ€” Split & Reuse Store Logic
386
+
387
+ Large stores can be split into mixins using `use()`. Each mixin only knows about its own state slice:
388
+
389
+ ```tsx
390
+ import { store, effect, type StoreContext } from "storion/react";
391
+
392
+ // Each mixin defines its OWN state shape
393
+ interface UserState {
394
+ users: User[];
395
+ }
396
+
397
+ interface PostState {
398
+ posts: Post[];
399
+ }
400
+
401
+ interface NotificationState {
402
+ notifications: Notification[];
403
+ }
404
+
405
+ // Mixin 1: Notifications (base mixin)
406
+ const notificationMixin = ({ state }: StoreContext<NotificationState>) => ({
407
+ notify: (msg: string) => {
408
+ state.notifications.push({ id: Date.now(), message: msg });
409
+ },
410
+ clearAll: () => {
411
+ state.notifications = [];
412
+ },
413
+ });
414
+
415
+ // Mixin 2: User management โ€” uses notificationMixin!
416
+ const userMixin = ({
417
+ state,
418
+ use,
419
+ }: StoreContext<UserState & NotificationState>) => {
420
+ const { notify } = use(notificationMixin); // Compose another mixin
421
+
422
+ return {
423
+ addUser: (user: User) => {
424
+ state.users.push(user);
425
+ notify(`User ${user.name} added`); // Use action from other mixin
426
+ },
427
+ removeUser: (id: string) => {
428
+ state.users = state.users.filter((u) => u.id !== id);
429
+ notify(`User removed`);
430
+ },
431
+ };
432
+ };
433
+
434
+ // Mixin 3: Post management โ€” also uses notificationMixin!
435
+ const postMixin = ({
436
+ state,
437
+ use,
438
+ }: StoreContext<PostState & NotificationState>) => {
439
+ const { notify } = use(notificationMixin);
440
+
441
+ effect(() => {
442
+ console.log(`Posts updated: ${state.posts.length} total`);
443
+ });
444
+
445
+ return {
446
+ addPost: (post: Post) => {
447
+ state.posts.push(post);
448
+ notify(`New post: ${post.title}`);
449
+ },
450
+ deletePost: (id: string) => {
451
+ state.posts = state.posts.filter((p) => p.id !== id);
452
+ notify(`Post deleted`);
453
+ },
454
+ };
455
+ };
456
+
457
+ // Compose: AppState = UserState & PostState & NotificationState
458
+ const appStore = store({
459
+ name: "app",
460
+ state: {
461
+ users: [] as User[],
462
+ posts: [] as Post[],
463
+ notifications: [] as Notification[],
464
+ },
465
+ setup({ use }) {
466
+ // Each mixin works with its slice of state
467
+ const userActions = use(userMixin);
468
+ const postActions = use(postMixin);
469
+ const notificationActions = use(notificationMixin);
470
+
471
+ return {
472
+ ...userActions,
473
+ ...postActions,
474
+ ...notificationActions,
475
+ };
476
+ },
477
+ });
478
+ ```
479
+
480
+ **Benefits:**
481
+
482
+ - ๐Ÿ“ **Organization** โ€” Split 500+ line stores into focused modules
483
+ - โ™ป๏ธ **Reuse** โ€” Mixins are decoupled, reusable across stores
484
+ - ๐Ÿงช **Testable** โ€” Test mixins in isolation with minimal state
485
+ - ๐ŸŽญ **Effects** โ€” Mixins can define their own reactive effects
486
+
487
+ **Note:** `use()` runs the mixin fresh each call (no singleton). This enables parameterized mixins:
488
+
489
+ ```ts
490
+ const apiMixin = ({ state }, endpoint: string) => ({
491
+ fetch: () => fetch(endpoint),
492
+ });
493
+
494
+ use(apiMixin, "/api/users"); // Different instances
495
+ use(apiMixin, "/api/posts");
496
+ ```
497
+
498
+ If you need singleton per store, use `memoize` (e.g., from lodash):
499
+
500
+ ```ts
501
+ import memoize from "lodash/memoize";
502
+
503
+ // Memoized by first arg (StoreContext) โ€” singleton per store
504
+ const notificationMixin = memoize(
505
+ ({ state }: StoreContext<NotificationState>) => ({
506
+ notify: (msg: string) =>
507
+ state.notifications.push({ id: Date.now(), message: msg }),
508
+ clearAll: () => {
509
+ state.notifications = [];
510
+ },
511
+ })
512
+ );
513
+
514
+ // Same store context โ†’ same mixin instance
515
+ // Different store context โ†’ new mixin instance
516
+ ```
517
+
385
518
  ---
386
519
 
387
520
  ## API Reference
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storion",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Reactive stores for modern apps. Type-safe. Auto-tracked. Effortlessly composable",
5
5
  "type": "module",
6
6
  "main": "./dist/storion.js",