chizu 0.4.0 → 0.5.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 +63 -65
- package/dist/chizu.js +6 -6
- package/dist/chizu.umd.cjs +1 -1
- package/dist/{action → src/library/action}/utils.d.ts +3 -3
- package/dist/src/library/boundary/components/mode/index.d.ts +15 -0
- package/dist/src/library/boundary/components/mode/types.d.ts +7 -0
- package/dist/src/library/boundary/components/mode/utils.d.ts +55 -0
- package/dist/src/library/boundary/components/scope/index.d.ts +40 -0
- package/dist/src/library/boundary/components/scope/types.d.ts +20 -0
- package/dist/{boundary → src/library/boundary}/components/scope/utils.d.ts +3 -6
- package/dist/{boundary → src/library/boundary}/index.d.ts +1 -1
- package/dist/src/library/error/index.d.ts +2 -0
- package/dist/{error → src/library/error}/types.d.ts +1 -18
- package/dist/{hooks → src/library/hooks}/index.d.ts +2 -2
- package/dist/{hooks → src/library/hooks}/types.d.ts +1 -17
- package/dist/{hooks → src/library/hooks}/utils.d.ts +25 -25
- package/dist/{index.d.ts → src/library/index.d.ts} +5 -5
- package/dist/{types → src/library/types}/index.d.ts +55 -306
- package/package.json +5 -2
- package/dist/boundary/components/regulators/index.d.ts +0 -14
- package/dist/boundary/components/regulators/types.d.ts +0 -52
- package/dist/boundary/components/regulators/utils.d.ts +0 -21
- package/dist/boundary/components/scope/index.d.ts +0 -82
- package/dist/boundary/components/scope/types.d.ts +0 -28
- package/dist/error/index.d.ts +0 -2
- /package/dist/{action → src/library/action}/index.d.ts +0 -0
- /package/dist/{annotate → src/library/annotate}/index.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/broadcast/index.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/broadcast/types.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/broadcast/utils.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/consumer/components/partition/index.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/consumer/components/partition/types.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/consumer/index.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/consumer/types.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/consumer/utils.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/tasks/index.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/tasks/types.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/components/tasks/utils.d.ts +0 -0
- /package/dist/{boundary → src/library/boundary}/types.d.ts +0 -0
- /package/dist/{error → src/library/error}/utils.d.ts +0 -0
- /package/dist/{resource → src/library/resource}/index.d.ts +0 -0
- /package/dist/{utils → src/library/utils}/index.d.ts +0 -0
- /package/dist/{utils → src/library/utils}/utils.d.ts +0 -0
- /package/dist/{utils.d.ts → src/library/utils.d.ts} +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Operation, Process, Inspect, Box } from 'immertation';
|
|
2
2
|
import { ActionId, Task, Tasks } from '../boundary/components/tasks/types.ts';
|
|
3
|
-
import { Regulator } from '../boundary/components/regulators/types.ts';
|
|
4
3
|
import { Fault } from '../error/types.ts';
|
|
5
4
|
import * as React from "react";
|
|
6
5
|
export type { ActionId, Box, Task, Tasks };
|
|
@@ -54,13 +53,11 @@ export declare class Brand {
|
|
|
54
53
|
static readonly Action: unique symbol;
|
|
55
54
|
/** Identifies channeled actions (result of calling Action(channel)) */
|
|
56
55
|
static readonly Channel: unique symbol;
|
|
57
|
-
/** Node capture events used by Lifecycle.Node */
|
|
58
|
-
static readonly Node: unique symbol;
|
|
59
56
|
}
|
|
60
57
|
/**
|
|
61
58
|
* Internal symbol for the global `Lifecycle.Fault` broadcast. Exposed so the
|
|
62
|
-
* dispatch pipeline can fire faults
|
|
63
|
-
*
|
|
59
|
+
* dispatch pipeline can fire faults without depending on the `Lifecycle`
|
|
60
|
+
* class at runtime.
|
|
64
61
|
*
|
|
65
62
|
* @internal
|
|
66
63
|
*/
|
|
@@ -68,8 +65,9 @@ export declare const FaultSymbol: unique symbol;
|
|
|
68
65
|
/**
|
|
69
66
|
* Factory functions for lifecycle actions.
|
|
70
67
|
*
|
|
71
|
-
* Each call returns a **unique** action symbol
|
|
72
|
-
*
|
|
68
|
+
* Each call returns a **unique** action symbol so that each component can
|
|
69
|
+
* subscribe independently. Assign the result as a static property in your
|
|
70
|
+
* Actions class:
|
|
73
71
|
*
|
|
74
72
|
* @example
|
|
75
73
|
* ```ts
|
|
@@ -78,13 +76,9 @@ export declare const FaultSymbol: unique symbol;
|
|
|
78
76
|
* static Unmount = Lifecycle.Unmount();
|
|
79
77
|
* static Error = Lifecycle.Error();
|
|
80
78
|
* static Update = Lifecycle.Update();
|
|
81
|
-
* static Node = Lifecycle.Node();
|
|
82
79
|
*
|
|
83
80
|
* static Increment = Action("Increment");
|
|
84
81
|
* }
|
|
85
|
-
*
|
|
86
|
-
* // Now regulating Lifecycle.Mount only blocks THIS component's mount:
|
|
87
|
-
* context.regulator.disallow(Actions.Mount);
|
|
88
82
|
* ```
|
|
89
83
|
*
|
|
90
84
|
* `Lifecycle.Fault` is a singleton broadcast (not a factory). All components
|
|
@@ -99,40 +93,13 @@ export declare class Lifecycle {
|
|
|
99
93
|
static Error(): HandlerPayload<Fault>;
|
|
100
94
|
/** Creates an Update lifecycle action. Triggered when `context.data` changes (not on initial mount). */
|
|
101
95
|
static Update(): HandlerPayload<Record<string, unknown>>;
|
|
102
|
-
/**
|
|
103
|
-
* Creates a Node lifecycle action. Triggered when a DOM node is captured
|
|
104
|
-
* or released via `actions.node()`. Supports channeled subscriptions by
|
|
105
|
-
* node name.
|
|
106
|
-
*
|
|
107
|
-
* @example
|
|
108
|
-
* ```ts
|
|
109
|
-
* export class Actions {
|
|
110
|
-
* static Node = Lifecycle.Node();
|
|
111
|
-
* }
|
|
112
|
-
*
|
|
113
|
-
* // Subscribe to ALL node changes
|
|
114
|
-
* actions.useAction(Actions.Node, (context, node) => {
|
|
115
|
-
* console.log("Node changed:", node);
|
|
116
|
-
* });
|
|
117
|
-
*
|
|
118
|
-
* // Subscribe to a specific node by name (channeled)
|
|
119
|
-
* actions.useAction(Actions.Node({ Name: "input" }), (context, node) => {
|
|
120
|
-
* if (node) node.focus();
|
|
121
|
-
* });
|
|
122
|
-
* ```
|
|
123
|
-
*/
|
|
124
|
-
static Node(): HandlerPayload<unknown, {
|
|
125
|
-
Name: string;
|
|
126
|
-
}>;
|
|
127
96
|
/**
|
|
128
97
|
* Global fault broadcast. Receives a `Fault` whenever any action in the
|
|
129
|
-
* `<Boundary>` errors, times out,
|
|
130
|
-
*
|
|
98
|
+
* `<Boundary>` errors, times out, or is supplanted. Subscribe via
|
|
99
|
+
* `actions.useAction(Lifecycle.Fault, handler)`.
|
|
131
100
|
*
|
|
132
101
|
* Unlike the per-component `Lifecycle.Error()` factory, `Fault` is a single
|
|
133
|
-
* shared broadcast — every subscriber points at the same symbol.
|
|
134
|
-
* regulator policy does not apply to `Fault`; faults always reach
|
|
135
|
-
* subscribers so error visibility cannot be silenced.
|
|
102
|
+
* shared broadcast — every subscriber points at the same symbol.
|
|
136
103
|
*
|
|
137
104
|
* @example
|
|
138
105
|
* ```tsx
|
|
@@ -152,18 +119,24 @@ export declare class Lifecycle {
|
|
|
152
119
|
*
|
|
153
120
|
* - **Unicast** – Action is scoped to the component that defines it and cannot be
|
|
154
121
|
* consumed by other components. This is the default behaviour.
|
|
155
|
-
* - **Broadcast** – Action is distributed to all mounted components that have
|
|
156
|
-
* a handler for it. Values are cached for late-mounting components.
|
|
122
|
+
* - **Broadcast** – Action is distributed to all mounted components that have
|
|
123
|
+
* defined a handler for it. Values are cached for late-mounting components.
|
|
124
|
+
* - **Multicast** – Action defines its own scope. Components reach it by
|
|
125
|
+
* wrapping a subtree in `withScope(<theMulticastAction>, Component)`.
|
|
157
126
|
*
|
|
158
127
|
* @example
|
|
159
128
|
* ```ts
|
|
160
|
-
* export class
|
|
161
|
-
* //
|
|
162
|
-
* static
|
|
163
|
-
*
|
|
164
|
-
* // Broadcast action - can be consumed across components
|
|
165
|
-
* static Counter = new Action("Counter", Distribution.Broadcast);
|
|
129
|
+
* export class Scope {
|
|
130
|
+
* // The action itself acts as the scope identifier.
|
|
131
|
+
* static Mood = Action<Mood>("Mood", Distribution.Multicast);
|
|
166
132
|
* }
|
|
133
|
+
*
|
|
134
|
+
* // Wrap the subtree where the scope applies.
|
|
135
|
+
* export default withScope(Scope.Mood, Component);
|
|
136
|
+
*
|
|
137
|
+
* // Dispatch / subscribe — no extra options.
|
|
138
|
+
* actions.dispatch(Scope.Mood, mood);
|
|
139
|
+
* actions.useAction(Scope.Mood, (context, mood) => { ... });
|
|
167
140
|
* ```
|
|
168
141
|
*/
|
|
169
142
|
export declare enum Distribution {
|
|
@@ -171,7 +144,7 @@ export declare enum Distribution {
|
|
|
171
144
|
Unicast = "unicast",
|
|
172
145
|
/** Action is broadcast to all mounted components and can be consumed. */
|
|
173
146
|
Broadcast = "broadcast",
|
|
174
|
-
/** Action is multicast to
|
|
147
|
+
/** Action is multicast to every component inside its `withScope` boundary. */
|
|
175
148
|
Multicast = "multicast"
|
|
176
149
|
}
|
|
177
150
|
/**
|
|
@@ -306,10 +279,12 @@ export type BroadcastPayload<P = unknown, C extends Filter = never> = HandlerPay
|
|
|
306
279
|
*
|
|
307
280
|
* @example
|
|
308
281
|
* ```tsx
|
|
309
|
-
*
|
|
282
|
+
* export enum Scope {
|
|
283
|
+
* Counter = "counter",
|
|
284
|
+
* }
|
|
285
|
+
*
|
|
310
286
|
* class MulticastActions {
|
|
311
|
-
* static
|
|
312
|
-
* static Update = Action<number>("Update", Distribution.Multicast);
|
|
287
|
+
* static Update = Action<number>("Update", Distribution.Multicast(Scope.Counter));
|
|
313
288
|
* }
|
|
314
289
|
*
|
|
315
290
|
* // Reference from component-level Actions
|
|
@@ -317,32 +292,23 @@ export type BroadcastPayload<P = unknown, C extends Filter = never> = HandlerPay
|
|
|
317
292
|
* static Multicast = MulticastActions;
|
|
318
293
|
* }
|
|
319
294
|
*
|
|
320
|
-
* //
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
295
|
+
* // Wrap the subtree where the scope applies via the withScope HOC.
|
|
296
|
+
* export default withScope(Scope.Counter, function Counters() {
|
|
297
|
+
* return (
|
|
298
|
+
* <>
|
|
299
|
+
* <CounterA />
|
|
300
|
+
* <CounterB />
|
|
301
|
+
* </>
|
|
302
|
+
* );
|
|
303
|
+
* });
|
|
325
304
|
*
|
|
326
|
-
* //
|
|
327
|
-
* actions.dispatch(Actions.Multicast.Update, 42
|
|
328
|
-
* // CounterA and CounterB both receive the event
|
|
305
|
+
* // Dispatch — the scope is read from the action itself.
|
|
306
|
+
* actions.dispatch(Actions.Multicast.Update, 42);
|
|
329
307
|
* ```
|
|
330
308
|
*/
|
|
331
309
|
export type MulticastPayload<P = unknown, C extends Filter = never> = HandlerPayload<P, C> & {
|
|
332
310
|
readonly [Brand.Multicast]: true;
|
|
333
311
|
};
|
|
334
|
-
/**
|
|
335
|
-
* Options for multicast dispatch.
|
|
336
|
-
* Required when dispatching a multicast action.
|
|
337
|
-
*/
|
|
338
|
-
export type MulticastOptions = {
|
|
339
|
-
/**
|
|
340
|
-
* Scope name. By convention this is a `static Scope` literal co-located
|
|
341
|
-
* with the multicast action declarations (e.g. `Actions.Multicast.Scope`),
|
|
342
|
-
* giving every call site a single source of truth.
|
|
343
|
-
*/
|
|
344
|
-
scope: string;
|
|
345
|
-
};
|
|
346
312
|
/**
|
|
347
313
|
* Extracts the payload type `P` from a `HandlerPayload<P>` or `ChanneledAction<P, C>`.
|
|
348
314
|
* Use this in handler signatures to get the action's payload type.
|
|
@@ -423,108 +389,6 @@ type AssertSync<F> = IsAsync<F> extends true ? "Error: async functions are not a
|
|
|
423
389
|
* Represents any object that can be captured as reactive data.
|
|
424
390
|
*/
|
|
425
391
|
export type Props = Record<string, unknown>;
|
|
426
|
-
/**
|
|
427
|
-
* Extracts the nodes type from a Model.
|
|
428
|
-
* If the model has a `meta.nodes` property, returns its type.
|
|
429
|
-
* Otherwise returns an empty record.
|
|
430
|
-
*
|
|
431
|
-
* @example
|
|
432
|
-
* ```ts
|
|
433
|
-
* type Model = {
|
|
434
|
-
* count: number;
|
|
435
|
-
* meta: { nodes: { container: HTMLButtonElement | null } };
|
|
436
|
-
* };
|
|
437
|
-
*
|
|
438
|
-
* type N = ExtractNodes<Model>; // { container: HTMLButtonElement | null }
|
|
439
|
-
* ```
|
|
440
|
-
*/
|
|
441
|
-
export type ExtractNodes<M> = M extends {
|
|
442
|
-
meta: {
|
|
443
|
-
nodes: infer N extends Record<string, unknown>;
|
|
444
|
-
};
|
|
445
|
-
} ? N : Record<never, unknown>;
|
|
446
|
-
/**
|
|
447
|
-
* Transforms `meta.nodes` values to include `| null`, reflecting
|
|
448
|
-
* that node refs are initially `null` until a DOM element is captured.
|
|
449
|
-
* Models without `meta.nodes` pass through unchanged.
|
|
450
|
-
*
|
|
451
|
-
* @internal
|
|
452
|
-
*/
|
|
453
|
-
export type NullableNodes<M> = M extends {
|
|
454
|
-
meta: infer Meta & {
|
|
455
|
-
nodes: infer N extends Record<string, unknown>;
|
|
456
|
-
};
|
|
457
|
-
} ? Omit<M, "meta"> & {
|
|
458
|
-
meta: Omit<Meta, "nodes"> & {
|
|
459
|
-
nodes: {
|
|
460
|
-
[K in keyof N]: N[K] | null;
|
|
461
|
-
};
|
|
462
|
-
};
|
|
463
|
-
} : M;
|
|
464
|
-
/**
|
|
465
|
-
* Extracts the `meta.features` property from a Model type.
|
|
466
|
-
* If the model has a `meta.features` property whose values are all booleans,
|
|
467
|
-
* returns its type. Otherwise returns an empty record, making the
|
|
468
|
-
* `features` methods effectively uncallable.
|
|
469
|
-
*
|
|
470
|
-
* @example
|
|
471
|
-
* ```ts
|
|
472
|
-
* type Model = { count: number; meta: { features: { sidebar: boolean; modal: boolean } } };
|
|
473
|
-
* type F = FeatureFlags<Model>; // { sidebar: boolean; modal: boolean }
|
|
474
|
-
* ```
|
|
475
|
-
*/
|
|
476
|
-
export type FeatureFlags<M> = M extends {
|
|
477
|
-
meta: {
|
|
478
|
-
features: infer F extends Record<string, boolean>;
|
|
479
|
-
};
|
|
480
|
-
} ? F : Record<never, boolean>;
|
|
481
|
-
/**
|
|
482
|
-
* Resolves to `unknown` when the model has no `meta.features` or all
|
|
483
|
-
* feature values are booleans. Resolves to a descriptive string literal when
|
|
484
|
-
* any value is not a boolean, causing an intersection with the model type
|
|
485
|
-
* to become `never` and producing a compile-time error.
|
|
486
|
-
*
|
|
487
|
-
* @internal
|
|
488
|
-
*/
|
|
489
|
-
export type ValidateFeatures<M> = M extends {
|
|
490
|
-
meta: {
|
|
491
|
-
features: infer F;
|
|
492
|
-
};
|
|
493
|
-
} ? F extends Record<string, boolean> ? unknown : "meta.features values must all be boolean" : unknown;
|
|
494
|
-
/**
|
|
495
|
-
* Utility type for the `meta` model property. Combines optional `nodes`
|
|
496
|
-
* and `features` sub-objects into a single meta shape.
|
|
497
|
-
*
|
|
498
|
-
* - When `N` is provided, produces `{ nodes: { [K in keyof N]: N[K] | null } }`.
|
|
499
|
-
* - When `F` is provided, produces `{ features: F }`.
|
|
500
|
-
* - Pass `void` to omit either sub-object.
|
|
501
|
-
*
|
|
502
|
-
* @template N - Node type record (e.g. `{ input: HTMLInputElement }`)
|
|
503
|
-
* @template F - Feature flags record (e.g. `{ sidebar: boolean }`)
|
|
504
|
-
*
|
|
505
|
-
* @example
|
|
506
|
-
* ```ts
|
|
507
|
-
* import type { Meta } from "chizu";
|
|
508
|
-
*
|
|
509
|
-
* type Model = {
|
|
510
|
-
* count: number;
|
|
511
|
-
* meta: Meta<{ input: HTMLInputElement }, { sidebar: boolean }>;
|
|
512
|
-
* };
|
|
513
|
-
* // Equivalent to:
|
|
514
|
-
* // meta: { nodes: { input: HTMLInputElement | null }; features: { sidebar: boolean } }
|
|
515
|
-
* ```
|
|
516
|
-
*/
|
|
517
|
-
export type Meta<N extends Record<string, unknown> | void = void, F extends Record<string, boolean> | void = void> = ([N] extends [void] ? unknown : {
|
|
518
|
-
nodes: {
|
|
519
|
-
[K in keyof N]: N[K] | null;
|
|
520
|
-
};
|
|
521
|
-
}) & ([F] extends [void] ? unknown : {
|
|
522
|
-
features: F;
|
|
523
|
-
});
|
|
524
|
-
export declare namespace Meta {
|
|
525
|
-
type Nodes<N extends Record<string, unknown>> = Meta<N>;
|
|
526
|
-
type Features<F extends Record<string, boolean>> = Meta<void, F>;
|
|
527
|
-
}
|
|
528
392
|
/**
|
|
529
393
|
* Constraint type for action containers.
|
|
530
394
|
* Actions are symbols grouped in an object (typically a class with static properties).
|
|
@@ -626,64 +490,13 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
626
490
|
* ```
|
|
627
491
|
*/
|
|
628
492
|
readonly tasks: ReadonlySet<Task>;
|
|
629
|
-
/**
|
|
630
|
-
* Meta properties including captured DOM nodes and feature flags.
|
|
631
|
-
*
|
|
632
|
-
* @example
|
|
633
|
-
* ```ts
|
|
634
|
-
* actions.useAction(Actions.Focus, (context) => {
|
|
635
|
-
* context.meta.nodes.input?.focus();
|
|
636
|
-
* });
|
|
637
|
-
* ```
|
|
638
|
-
*/
|
|
639
|
-
readonly meta: {
|
|
640
|
-
readonly nodes: {
|
|
641
|
-
[K in keyof ExtractNodes<M>]: ExtractNodes<M>[K] | null;
|
|
642
|
-
};
|
|
643
|
-
readonly features: Readonly<FeatureFlags<M>>;
|
|
644
|
-
};
|
|
645
|
-
/**
|
|
646
|
-
* The regulator API for controlling which actions may be dispatched.
|
|
647
|
-
*
|
|
648
|
-
* Each call replaces the previous policy entirely (last-write-wins).
|
|
649
|
-
* The policy is shared across all components within the same `<Boundary>`.
|
|
650
|
-
*
|
|
651
|
-
* @example
|
|
652
|
-
* ```ts
|
|
653
|
-
* actions.useAction(Actions.Mount, (context) => {
|
|
654
|
-
* // Block all actions except Critical
|
|
655
|
-
* context.regulator.allow(Actions.Critical);
|
|
656
|
-
* });
|
|
657
|
-
*
|
|
658
|
-
* actions.useAction(Actions.Unlock, (context) => {
|
|
659
|
-
* // Re-allow all actions
|
|
660
|
-
* context.regulator.allow();
|
|
661
|
-
* });
|
|
662
|
-
* ```
|
|
663
|
-
*/
|
|
664
|
-
readonly regulator: Regulator;
|
|
665
493
|
readonly actions: {
|
|
666
494
|
produce<F extends (draft: {
|
|
667
|
-
model:
|
|
495
|
+
model: M;
|
|
668
496
|
readonly inspect: Readonly<Inspect<M>>;
|
|
669
497
|
}) => void>(ƒ: F & AssertSync<F>): void;
|
|
670
|
-
dispatch(action: ActionOrChanneled, payload?: unknown
|
|
498
|
+
dispatch(action: ActionOrChanneled, payload?: unknown): Promise<void>;
|
|
671
499
|
annotate<T>(operation: Operation, value: T): T;
|
|
672
|
-
/**
|
|
673
|
-
* Feature toggle methods for mutating boolean flags on the model.
|
|
674
|
-
*
|
|
675
|
-
* @example
|
|
676
|
-
* ```ts
|
|
677
|
-
* context.actions.features.on("sidebar");
|
|
678
|
-
* context.actions.features.off("sidebar");
|
|
679
|
-
* context.actions.features.invert("sidebar");
|
|
680
|
-
* ```
|
|
681
|
-
*/
|
|
682
|
-
features: {
|
|
683
|
-
on<K extends keyof FeatureFlags<M>>(name: K): void;
|
|
684
|
-
off<K extends keyof FeatureFlags<M>>(name: K): void;
|
|
685
|
-
invert<K extends keyof FeatureFlags<M>>(name: K): void;
|
|
686
|
-
};
|
|
687
500
|
/**
|
|
688
501
|
* Returns the resolved broadcast or multicast value, waiting for any
|
|
689
502
|
* pending annotations to settle before resolving.
|
|
@@ -692,8 +505,8 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
692
505
|
* Otherwise it waits until the next dispatch of the action.
|
|
693
506
|
* Resolves with `null` if the task is aborted before a value arrives.
|
|
694
507
|
*
|
|
695
|
-
* @param action - The broadcast or multicast action to resolve.
|
|
696
|
-
*
|
|
508
|
+
* @param action - The broadcast or multicast action to resolve. Multicast
|
|
509
|
+
* actions read their scope from the action declaration.
|
|
697
510
|
* @returns The dispatched value, or `null` if aborted.
|
|
698
511
|
*
|
|
699
512
|
* @example
|
|
@@ -708,15 +521,14 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
708
521
|
* });
|
|
709
522
|
* ```
|
|
710
523
|
*/
|
|
711
|
-
resolution<T>(action: BroadcastPayload<T>): Promise<T | null>;
|
|
712
|
-
resolution<T>(action: MulticastPayload<T>, options: MulticastOptions): Promise<T | null>;
|
|
524
|
+
resolution<T>(action: BroadcastPayload<T> | MulticastPayload<T>): Promise<T | null>;
|
|
713
525
|
/**
|
|
714
526
|
* Returns the latest broadcast or multicast value immediately without
|
|
715
527
|
* waiting for annotations to settle. Use this when you need the current
|
|
716
528
|
* cached value and do not need to wait for pending operations to complete.
|
|
717
529
|
*
|
|
718
|
-
* @param action - The broadcast or multicast action to peek at.
|
|
719
|
-
*
|
|
530
|
+
* @param action - The broadcast or multicast action to peek at. Multicast
|
|
531
|
+
* actions read their scope from the action declaration.
|
|
720
532
|
* @returns The cached value, or `null` if no value has been dispatched.
|
|
721
533
|
*
|
|
722
534
|
* @example
|
|
@@ -728,8 +540,7 @@ export type HandlerContext<M extends Model | void, _AC extends Actions | void, D
|
|
|
728
540
|
* });
|
|
729
541
|
* ```
|
|
730
542
|
*/
|
|
731
|
-
peek<T>(action: BroadcastPayload<T>): T | null;
|
|
732
|
-
peek<T>(action: MulticastPayload<T>, options: MulticastOptions): T | null;
|
|
543
|
+
peek<T>(action: BroadcastPayload<T> | MulticastPayload<T>): T | null;
|
|
733
544
|
};
|
|
734
545
|
};
|
|
735
546
|
/**
|
|
@@ -815,80 +626,18 @@ export type Handlers<M extends Model | void, AC extends Actions | void, D extend
|
|
|
815
626
|
[K in OwnKeys<AC>]: OwnKeys<AC[K]> extends never ? (context: HandlerContext<M, AC, D>, ...args: [Payload<AC[K] & HandlerPayload<unknown>>] extends [never] ? [] : [payload: Payload<AC[K] & HandlerPayload<unknown>>]) => void | Promise<void> | AsyncGenerator | Generator : Handlers<M, AC[K] & Actions, D>;
|
|
816
627
|
};
|
|
817
628
|
export type UseActions<M extends Model | void, AC extends Actions | void, D extends Props = Props> = [
|
|
818
|
-
Readonly<
|
|
629
|
+
Readonly<M>,
|
|
819
630
|
{
|
|
820
631
|
/**
|
|
821
|
-
* Dispatches an action with an optional payload.
|
|
822
|
-
*
|
|
823
|
-
*
|
|
824
|
-
* ```ts
|
|
825
|
-
* actions.dispatch(Actions.Multicast.Update, payload, { scope: Actions.Multicast });
|
|
826
|
-
* ```
|
|
827
|
-
*
|
|
828
|
-
* @param action - The action to dispatch
|
|
829
|
-
* @param payload - The payload to send with the action
|
|
830
|
-
* @param options - For multicast actions, must include `{ scope: MulticastActions }`
|
|
632
|
+
* Dispatches an action with an optional payload. Multicast actions read
|
|
633
|
+
* their scope from the action declaration, so no extra options are
|
|
634
|
+
* required at the call site.
|
|
831
635
|
*/
|
|
832
|
-
dispatch<P>(action: HandlerPayload<P>, payload?: P
|
|
833
|
-
dispatch<P>(action: BroadcastPayload<P>, payload?: P
|
|
834
|
-
dispatch<P>(action: MulticastPayload<P>, payload
|
|
835
|
-
dispatch<P, C extends Filter>(action: ChanneledAction<P, C>, payload?: P
|
|
636
|
+
dispatch<P>(action: HandlerPayload<P>, payload?: P): Promise<void>;
|
|
637
|
+
dispatch<P>(action: BroadcastPayload<P>, payload?: P): Promise<void>;
|
|
638
|
+
dispatch<P>(action: MulticastPayload<P>, payload?: P): Promise<void>;
|
|
639
|
+
dispatch<P, C extends Filter>(action: ChanneledAction<P, C>, payload?: P): Promise<void>;
|
|
836
640
|
inspect: Inspect<M>;
|
|
837
|
-
/**
|
|
838
|
-
* Meta properties including captured DOM nodes and feature flags.
|
|
839
|
-
*
|
|
840
|
-
* @example
|
|
841
|
-
* ```tsx
|
|
842
|
-
* actions.meta.nodes.input?.focus();
|
|
843
|
-
* actions.meta.features.sidebar; // boolean
|
|
844
|
-
* ```
|
|
845
|
-
*/
|
|
846
|
-
meta: {
|
|
847
|
-
readonly nodes: {
|
|
848
|
-
[K in keyof ExtractNodes<M>]: ExtractNodes<M>[K] | null;
|
|
849
|
-
};
|
|
850
|
-
readonly features: Readonly<FeatureFlags<M>>;
|
|
851
|
-
};
|
|
852
|
-
/**
|
|
853
|
-
* Captures a DOM node for later access via `meta.nodes`.
|
|
854
|
-
* Use as a ref callback on JSX elements.
|
|
855
|
-
*
|
|
856
|
-
* @param name - The node key (must match a key in the model's `meta.nodes`)
|
|
857
|
-
* @param node - The DOM node or null (when unmounting)
|
|
858
|
-
*
|
|
859
|
-
* @example
|
|
860
|
-
* ```tsx
|
|
861
|
-
* type Model = {
|
|
862
|
-
* count: number;
|
|
863
|
-
* meta: Meta<{ container: HTMLDivElement; input: HTMLInputElement }>;
|
|
864
|
-
* };
|
|
865
|
-
*
|
|
866
|
-
* const [model, actions] = useActions<Model, typeof Actions>(model);
|
|
867
|
-
*
|
|
868
|
-
* return (
|
|
869
|
-
* <div ref={node => actions.node('container', node)}>
|
|
870
|
-
* <input ref={node => actions.node('input', node)} />
|
|
871
|
-
* </div>
|
|
872
|
-
* );
|
|
873
|
-
* ```
|
|
874
|
-
*/
|
|
875
|
-
node<K extends keyof ExtractNodes<M>>(name: K, node: ExtractNodes<M>[K] | null): void;
|
|
876
|
-
/**
|
|
877
|
-
* Feature toggle methods for mutating boolean flags on the model.
|
|
878
|
-
*
|
|
879
|
-
* @example
|
|
880
|
-
* ```tsx
|
|
881
|
-
* actions.features.on("sidebar");
|
|
882
|
-
* actions.features.invert("sidebar");
|
|
883
|
-
*
|
|
884
|
-
* {model.meta.features.sidebar && <Sidebar />}
|
|
885
|
-
* ```
|
|
886
|
-
*/
|
|
887
|
-
features: {
|
|
888
|
-
on<K extends keyof FeatureFlags<M>>(name: K): void;
|
|
889
|
-
off<K extends keyof FeatureFlags<M>>(name: K): void;
|
|
890
|
-
invert<K extends keyof FeatureFlags<M>>(name: K): void;
|
|
891
|
-
};
|
|
892
641
|
/**
|
|
893
642
|
* Streams broadcast values declaratively in JSX using a render-prop pattern.
|
|
894
643
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chizu",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"packageManager": "yarn@1.22.22",
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
"immer": "^10.0.0",
|
|
23
23
|
"react": "^18.0.0 || ^19.0.0"
|
|
24
24
|
},
|
|
25
|
+
"resolutions": {
|
|
26
|
+
"vitest/vite": "^7.3.1"
|
|
27
|
+
},
|
|
25
28
|
"files": [
|
|
26
29
|
"dist"
|
|
27
30
|
],
|
|
@@ -88,7 +91,7 @@
|
|
|
88
91
|
"traverse": "^0.6.11",
|
|
89
92
|
"ts-jest": "^29.4.6",
|
|
90
93
|
"ts-node": "^10.9.2",
|
|
91
|
-
"typescript": "^
|
|
94
|
+
"typescript": "^6.0.3",
|
|
92
95
|
"typescript-eslint": "^8.55.0",
|
|
93
96
|
"vite": "^7.3.1",
|
|
94
97
|
"vite-plugin-dts": "^4.5.4",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Props } from './types.ts';
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
export { useRegulators, isAllowed } from './utils.ts';
|
|
4
|
-
export type { Regulator, RegulatorPolicy } from './types.ts';
|
|
5
|
-
/**
|
|
6
|
-
* Provides a shared regulator policy to all descendant components.
|
|
7
|
-
*
|
|
8
|
-
* Wrap this around your component tree (or use `<Boundary>` which includes it)
|
|
9
|
-
* to enable action regulation via `context.regulator`.
|
|
10
|
-
*
|
|
11
|
-
* @param props.children - The children to render within the regulator context.
|
|
12
|
-
* @returns The children wrapped in a regulator context provider.
|
|
13
|
-
*/
|
|
14
|
-
export declare function Regulators({ children }: Props): React.ReactNode;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { ActionId } from '../tasks/types.ts';
|
|
2
|
-
import type * as React from "react";
|
|
3
|
-
/**
|
|
4
|
-
* The four policy modes that the regulator supports.
|
|
5
|
-
*
|
|
6
|
-
* - `allow-all` (default) – every action is permitted (`allow()` with no args).
|
|
7
|
-
* - `disallow-all` – every action is blocked (`disallow()` with no args).
|
|
8
|
-
* - `disallow-matching` – only the listed actions are blocked (`disallow(A, B)`).
|
|
9
|
-
* - `allow-matching` – only the listed actions are permitted (`allow(A, B)`).
|
|
10
|
-
*
|
|
11
|
-
* For "except" patterns, compose two calls:
|
|
12
|
-
* - Block all except X: `disallow()` then `allow(X)`.
|
|
13
|
-
* - Allow all except X: `allow()` then `disallow(X)`.
|
|
14
|
-
*/
|
|
15
|
-
export type RegulatorMode = "allow-all" | "disallow-all" | "disallow-matching" | "allow-matching";
|
|
16
|
-
/**
|
|
17
|
-
* Mutable policy object shared across all components in a `<Boundary>`.
|
|
18
|
-
* Mutated in-place by the `context.regulator` API – last write wins.
|
|
19
|
-
*/
|
|
20
|
-
export type RegulatorPolicy = {
|
|
21
|
-
mode: RegulatorMode;
|
|
22
|
-
actions: Set<ActionId>;
|
|
23
|
-
};
|
|
24
|
-
/**
|
|
25
|
-
* The `context.regulator` API shape exposed to action handlers.
|
|
26
|
-
*
|
|
27
|
-
* - `disallow()` – block all actions.
|
|
28
|
-
* - `disallow(A, B)` – block only the listed actions.
|
|
29
|
-
* - `allow()` – allow all actions (reset to default).
|
|
30
|
-
* - `allow(A, B)` – allow only the listed actions.
|
|
31
|
-
*
|
|
32
|
-
* Each call replaces the previous policy entirely (last-write-wins).
|
|
33
|
-
*/
|
|
34
|
-
export type Regulator = {
|
|
35
|
-
/**
|
|
36
|
-
* Block actions. Called with no arguments, blocks everything.
|
|
37
|
-
* Called with specific actions, blocks only those actions.
|
|
38
|
-
*/
|
|
39
|
-
disallow(...actions: ReadonlyArray<{
|
|
40
|
-
readonly [x: symbol]: unknown;
|
|
41
|
-
}>): void;
|
|
42
|
-
/**
|
|
43
|
-
* Allow actions. Called with no arguments, allows everything (reset).
|
|
44
|
-
* Called with specific actions, allows only those actions.
|
|
45
|
-
*/
|
|
46
|
-
allow(...actions: ReadonlyArray<{
|
|
47
|
-
readonly [x: symbol]: unknown;
|
|
48
|
-
}>): void;
|
|
49
|
-
};
|
|
50
|
-
export type Props = {
|
|
51
|
-
children: React.ReactNode;
|
|
52
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { ActionId } from '../tasks/types.ts';
|
|
2
|
-
import { RegulatorPolicy } from './types.ts';
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
/**
|
|
5
|
-
* React context holding the shared, mutable regulator policy.
|
|
6
|
-
*/
|
|
7
|
-
export declare const Context: React.Context<RegulatorPolicy>;
|
|
8
|
-
/**
|
|
9
|
-
* Hook to access the regulator policy from the nearest `<Regulators>` provider.
|
|
10
|
-
*
|
|
11
|
-
* @returns The mutable `RegulatorPolicy` object from context.
|
|
12
|
-
*/
|
|
13
|
-
export declare function useRegulators(): RegulatorPolicy;
|
|
14
|
-
/**
|
|
15
|
-
* Determines whether a given action is allowed under the current policy.
|
|
16
|
-
*
|
|
17
|
-
* @param action - The action identifier (symbol) to check.
|
|
18
|
-
* @param policy - The current regulator policy.
|
|
19
|
-
* @returns `true` if the action may proceed, `false` if it should be blocked.
|
|
20
|
-
*/
|
|
21
|
-
export declare function isAllowed(action: ActionId, policy: RegulatorPolicy): boolean;
|