chizu 0.2.43 → 0.2.44
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 +65 -7
- package/dist/action/index.d.ts +26 -4
- package/dist/chizu.js +734 -655
- package/dist/chizu.umd.cjs +1 -1
- package/dist/consumer/components/renderer/index.d.ts +23 -0
- package/dist/consumer/components/renderer/types.d.ts +9 -0
- package/dist/consumer/index.d.ts +19 -0
- package/dist/consumer/types.d.ts +28 -0
- package/dist/consumer/utils.d.ts +13 -0
- package/dist/error/types.d.ts +3 -1
- package/dist/hooks/index.d.ts +0 -15
- package/dist/hooks/types.d.ts +32 -0
- package/dist/hooks/utils.d.ts +7 -28
- package/dist/index.d.ts +1 -0
- package/dist/regulator/utils.d.ts +26 -7
- package/dist/types/index.d.ts +90 -3
- package/dist/utils/index.d.ts +15 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ Strongly typed React framework using generators and efficiently updated views al
|
|
|
17
17
|
1. [Model annotations](#model-annotations)
|
|
18
18
|
1. [Lifecycle actions](#lifecycle-actions)
|
|
19
19
|
1. [Distributed actions](#distributed-actions)
|
|
20
|
+
1. [Consuming actions](#consuming-actions)
|
|
21
|
+
1. [Stateful props](#stateful-props)
|
|
20
22
|
1. [Action decorators](#action-decorators)
|
|
21
23
|
1. [Real-time applications](#real-time-applications)
|
|
22
24
|
1. [Utility functions](#utility-functions)
|
|
@@ -281,7 +283,7 @@ class {
|
|
|
281
283
|
- **`Lifecycle.Mount`** – Triggered once when the component mounts (`useLayoutEffect`).
|
|
282
284
|
- **`Lifecycle.Node`** – Triggered after the component renders (`useEffect`).
|
|
283
285
|
- **`Lifecycle.Error`** – Triggered when an action throws an error. Receives `ErrorDetails` as payload.
|
|
284
|
-
- **`Lifecycle.Unmount`** – Triggered when the component unmounts.
|
|
286
|
+
- **`Lifecycle.Unmount`** – Triggered when the component unmounts. All in-flight actions are automatically aborted before this handler runs.
|
|
285
287
|
|
|
286
288
|
**Note:** Actions should ideally be self-contained and handle expected errors internally using patterns like [Option](https://mobily.github.io/ts-belt/api/option) or [Result](https://mobily.github.io/ts-belt/api/result) types to update the model accordingly. `Lifecycle.Error` is intended for timeouts, aborts, and uncaught catastrophic errors – not routine error handling.
|
|
287
289
|
|
|
@@ -305,6 +307,8 @@ export class Actions extends DistributedActions {
|
|
|
305
307
|
}
|
|
306
308
|
```
|
|
307
309
|
|
|
310
|
+
`createDistributedAction()` returns a `DistributedPayload<T>` type, which is distinct from the `Payload<T>` returned by `createAction()`. This enables compile-time enforcement – only distributed actions can be passed to `actions.consume()`.
|
|
311
|
+
|
|
308
312
|
Any component that defines a handler for `DistributedActions.SignedOut` will receive the action when it's dispatched from any other component. For direct access to the broadcast emitter, use `useBroadcast()`:
|
|
309
313
|
|
|
310
314
|
```ts
|
|
@@ -321,6 +325,41 @@ broadcast.on(DistributedActions.SignedOut, (payload) => {
|
|
|
321
325
|
});
|
|
322
326
|
```
|
|
323
327
|
|
|
328
|
+
## Consuming actions
|
|
329
|
+
|
|
330
|
+
The `consume()` method subscribes to a distributed action and re-renders content whenever a new value is dispatched, making it ideal for global context scenarios where you want to fetch data once and access it throughout your app without prop drilling. The callback receives a `Box<T>` from [Immertation](https://github.com/Wildhoney/Immertation) containing the `value` and an `inspect` proxy for checking annotation status.
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
export default function Visitor(): React.ReactElement {
|
|
334
|
+
const [model, actions] = useVisitorActions();
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
<div>
|
|
338
|
+
{actions.consume(Actions.Visitor, (visitor) =>
|
|
339
|
+
visitor.inspect.pending() ? <>Loading…</> : visitor.value.name,
|
|
340
|
+
)}
|
|
341
|
+
</div>
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
> **Important:** The `consume()` method only accepts distributed actions created with `createDistributedAction()`. Attempting to pass a local action created with `createAction()` will result in a TypeScript error. This is enforced at compile-time to prevent confusion – local actions are scoped to a single component and cannot be consumed across the application.
|
|
347
|
+
|
|
348
|
+
> **Note:** When a component mounts, `consume()` displays the most recent value for that action, even if it was dispatched before the component mounted. This is managed by the `Consumer` context provider. If no value has been dispatched yet, `consume()` renders `null` until the first dispatch occurs.
|
|
349
|
+
|
|
350
|
+
## Stateful props
|
|
351
|
+
|
|
352
|
+
Chizu uses the `Box<T>` type from [Immertation](https://github.com/Wildhoney/Immertation) to wrap values with metadata about their async state. Passing `Box<T>` to React components allows them to observe an object's state – checking if a value is pending, how many operations are in flight, and what the optimistic draft value is – all without additional state management.
|
|
353
|
+
|
|
354
|
+
The `Box<T>` type has two properties:
|
|
355
|
+
|
|
356
|
+
- **`box.value`** – The payload (e.g., `Country` object with `name`, `flag`, etc.).
|
|
357
|
+
- **`box.inspect`** – An `Inspect<T>` proxy for checking annotation status:
|
|
358
|
+
- `box.inspect.pending()` – Returns `true` if any pending annotations exist.
|
|
359
|
+
- `box.inspect.remaining()` – Returns the count of pending annotations.
|
|
360
|
+
- `box.inspect.draft()` – Returns the draft value from the latest annotation.
|
|
361
|
+
- `box.inspect.is(Op.Update)` – Checks if the annotation matches a specific operation.
|
|
362
|
+
|
|
324
363
|
## Action decorators
|
|
325
364
|
|
|
326
365
|
Chizu provides decorators to add common functionality to your actions. Import `use` from Chizu and apply decorators to action properties:
|
|
@@ -659,7 +698,7 @@ The regulator is accessed via `context.regulator` inside your action handlers. I
|
|
|
659
698
|
const fetchAction = useAction<Model, typeof Actions, "Fetch">(
|
|
660
699
|
async (context) => {
|
|
661
700
|
// Disallow future dispatches of these actions
|
|
662
|
-
context.regulator.policy.disallow.matching(Actions.Fetch, Actions.Save);
|
|
701
|
+
context.regulator.policy.disallow.matching([Actions.Fetch, Actions.Save]);
|
|
663
702
|
|
|
664
703
|
// Future dispatches via useAction will be aborted immediately
|
|
665
704
|
// and the error handler will receive Reason.Disallowed
|
|
@@ -669,7 +708,7 @@ const fetchAction = useAction<Model, typeof Actions, "Fetch">(
|
|
|
669
708
|
const resetAction = useAction<Model, typeof Actions, "Reset">(
|
|
670
709
|
async (context) => {
|
|
671
710
|
// Allow the actions again
|
|
672
|
-
context.regulator.policy.allow.matching(Actions.Fetch, Actions.Save);
|
|
711
|
+
context.regulator.policy.allow.matching([Actions.Fetch, Actions.Save]);
|
|
673
712
|
},
|
|
674
713
|
);
|
|
675
714
|
```
|
|
@@ -678,7 +717,7 @@ You can also abort running actions:
|
|
|
678
717
|
|
|
679
718
|
```ts
|
|
680
719
|
// Abort specific actions across all components
|
|
681
|
-
context.regulator.abort.matching(Actions.Fetch);
|
|
720
|
+
context.regulator.abort.matching([Actions.Fetch]);
|
|
682
721
|
|
|
683
722
|
// Abort all actions across all components
|
|
684
723
|
context.regulator.abort.all();
|
|
@@ -692,20 +731,23 @@ context.regulator.abort.self();
|
|
|
692
731
|
**Abort methods:**
|
|
693
732
|
|
|
694
733
|
- `abort.all()` — Aborts all running actions across all components in the context.
|
|
695
|
-
- `abort.matching(
|
|
734
|
+
- `abort.matching(actions)` — Aborts specific actions (array) across all components.
|
|
696
735
|
- `abort.self()` — Aborts only the current action instance.
|
|
736
|
+
- `abort.own()` — Aborts all actions belonging to the current component only (called automatically on unmount).
|
|
697
737
|
|
|
698
738
|
**Allow methods:**
|
|
699
739
|
|
|
700
740
|
- `policy.allow.all()` — Clears all disallow policies across all components.
|
|
701
|
-
- `policy.allow.matching(
|
|
741
|
+
- `policy.allow.matching(actions)` — Allows specific actions (array) across all components.
|
|
702
742
|
- `policy.allow.self()` — Allows the current action.
|
|
743
|
+
- `policy.allow.own()` — Clears all disallow policies belonging to the current component only.
|
|
703
744
|
|
|
704
745
|
**Disallow methods:**
|
|
705
746
|
|
|
706
747
|
- `policy.disallow.all()` — Clears all allow policies across all components.
|
|
707
|
-
- `policy.disallow.matching(
|
|
748
|
+
- `policy.disallow.matching(actions)` — Disallows specific actions (array) across all components.
|
|
708
749
|
- `policy.disallow.self()` — Disallows the current action.
|
|
750
|
+
- `policy.disallow.own()` — Clears all allow policies belonging to the current component only.
|
|
709
751
|
|
|
710
752
|
The regulator is useful for advanced scenarios where you need to centrally manage cancellation and permission of asynchronous actions, such as rate limiting, feature toggling, or global aborts.
|
|
711
753
|
|
|
@@ -740,3 +782,19 @@ function Example({ children }) {
|
|
|
740
782
|
```
|
|
741
783
|
|
|
742
784
|
This is useful for libraries that need action control without affecting the host application's actions. An `abort.all()` inside the provider won't abort actions outside it.
|
|
785
|
+
|
|
786
|
+
### `Consumer`
|
|
787
|
+
|
|
788
|
+
Creates an isolated consumer context for storing distributed action values. The Consumer stores the latest payload for each distributed action, enabling the `consume()` method to display the most recent value even when components mount after the action was dispatched:
|
|
789
|
+
|
|
790
|
+
```tsx
|
|
791
|
+
import { Consumer } from "chizu";
|
|
792
|
+
|
|
793
|
+
function MyLibraryRoot({ children }) {
|
|
794
|
+
return <Consumer>{children}</Consumer>;
|
|
795
|
+
}
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
Components inside `<Consumer>` have their own isolated value store. Actions consumed inside won't see values dispatched outside, and vice versa. This is useful for libraries that want to use `consume()` without interfering with the host application's consumed values.
|
|
799
|
+
|
|
800
|
+
**Note:** In most applications, you don't need to provide a `Consumer` – one is created automatically at the default context level. Only use `<Consumer>` when you need isolation for library boundaries or testing.
|
package/dist/action/index.d.ts
CHANGED
|
@@ -1,22 +1,44 @@
|
|
|
1
|
-
import { Payload } from '../types/index.ts';
|
|
1
|
+
import { Payload, DistributedPayload } from '../types/index.ts';
|
|
2
2
|
import { Action } from '../regulator/types.ts';
|
|
3
3
|
/**
|
|
4
|
-
* Defines a new action with a given payload type.
|
|
4
|
+
* Defines a new local action with a given payload type.
|
|
5
|
+
* Local actions are scoped to the component that defines them and cannot be consumed
|
|
6
|
+
* by other components. Use `createDistributedAction()` for actions that need to be
|
|
7
|
+
* shared across components via `actions.consume()`.
|
|
5
8
|
*
|
|
6
9
|
* @template T The type of the payload that the action will carry.
|
|
7
10
|
* @param name An optional name for the action, used for debugging purposes.
|
|
8
11
|
* @returns A new action symbol.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const Increment = createAction<number>("Increment");
|
|
16
|
+
*
|
|
17
|
+
* // Dispatch within the same component
|
|
18
|
+
* actions.dispatch(Increment, 5);
|
|
19
|
+
* ```
|
|
9
20
|
*/
|
|
10
21
|
export declare function createAction<T = never>(name?: string): Payload<T>;
|
|
11
22
|
/**
|
|
12
23
|
* Defines a new distributed action with a given payload type.
|
|
13
24
|
* Distributed actions are broadcast to all mounted components that have defined a handler for them.
|
|
14
25
|
*
|
|
26
|
+
* Returns a `DistributedPayload<T>` which is required by `actions.consume()`. Local actions
|
|
27
|
+
* created with `createAction()` cannot be consumed – this is enforced at compile-time.
|
|
28
|
+
*
|
|
15
29
|
* @template T The type of the payload that the action will carry.
|
|
16
30
|
* @param name An optional name for the action, used for debugging purposes.
|
|
17
|
-
* @returns A new distributed action symbol
|
|
31
|
+
* @returns A new distributed action symbol that can be used with `consume()`.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const SignedOut = createDistributedAction<User>("SignedOut");
|
|
36
|
+
*
|
|
37
|
+
* // Can be consumed across components
|
|
38
|
+
* actions.consume(SignedOut, (box) => <div>{box.value.name}</div>);
|
|
39
|
+
* ```
|
|
18
40
|
*/
|
|
19
|
-
export declare function createDistributedAction<T = never>(name?: string):
|
|
41
|
+
export declare function createDistributedAction<T = never>(name?: string): DistributedPayload<T>;
|
|
20
42
|
/**
|
|
21
43
|
* Checks whether an action is a distributed action.
|
|
22
44
|
* Distributed actions are broadcast to all mounted components that have defined a handler for them.
|