@yoltra/react 0.6.0 → 0.8.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.
@@ -1,4 +1,4 @@
1
- import { DeepReadonly, EffectSpec, EMFromReducersStrict, EventMapBase, EventUnion, MiddlewareFunction, ReducersMapAny, StateFromReducers, StoreInstance } from '@yoltra/core';
1
+ import { DeepReadonly, EffectSpec, EMAddOf, EMFromReducersStrict, EventMapBase, EventUnion, Merge, MiddlewareFunction, MiddlewareInput, ReducersMapAny, ReducerSpec, SatisfiesSlices, StateFromReducers, StateOfSpec, StoreInstance, WidenNames, WidenState } from '@yoltra/core';
2
2
  import { default as React, ReactNode } from 'react';
3
3
  import { YoltraHooks } from './hooks/createHooks.js';
4
4
  /**
@@ -12,7 +12,7 @@ import { YoltraHooks } from './hooks/createHooks.js';
12
12
  *
13
13
  * @public
14
14
  */
15
- export interface Yoltra<R extends string, S extends Record<R, any>, EM extends EventMapBase> extends YoltraHooks<R, S, EM> {
15
+ export interface Yoltra<R extends string, S extends Record<R, any>, EM extends EventMapBase> extends YoltraHooks<R, S, EM>, YoltraDecoration<R, S, EM> {
16
16
  /** The store created by this call; the hooks default to it (no Provider needed). */
17
17
  store: StoreInstance<R, S, EM>;
18
18
  /** Raw context carrying the store — usually you only need `StoreProvider`. */
@@ -23,6 +23,44 @@ export interface Yoltra<R extends string, S extends Record<R, any>, EM extends E
23
23
  children: ReactNode;
24
24
  }>;
25
25
  }
26
+ /**
27
+ * The chainable decoration surface on a {@link Yoltra}.
28
+ *
29
+ * @remarks
30
+ * `Yoltra` extends this, so every hook set is chainable.
31
+ *
32
+ * Every method returns a **new hook set bound to the same context object**, re-typed. The
33
+ * context is never recreated, so a `StoreProvider` from any view in the chain serves the
34
+ * hooks of every other, and the Suspense cache is shared - it keys on store identity through
35
+ * a `WeakMap`, and the widened store is the same object.
36
+ *
37
+ * Call these at **module scope, once, before first render**. `createHooks` allocates fresh
38
+ * function objects per call, so decorating inside a component would hand React a different
39
+ * hook set on every render.
40
+ *
41
+ * @public
42
+ */
43
+ export interface YoltraDecoration<R extends string, S extends Record<R, any>, EM extends EventMapBase> {
44
+ /** Mounts a slice and returns a widened `Yoltra`: the same store, a new hook set. */
45
+ withSlice<N extends string, Spec extends ReducerSpec<any, any>>(name: N, spec: Spec, options?: {
46
+ owner?: string;
47
+ }): DecoratableYoltra<WidenNames<R, N>, SatisfiesSlices<WidenState<S, N, StateOfSpec<Spec>>, WidenNames<R, N>>, Merge<EM, EMAddOf<Spec>>>;
48
+ /**
49
+ * Registers middleware and returns a `Yoltra` widened by whatever event map it declares.
50
+ *
51
+ * Only the spec form can widen; a bare `MiddlewareFunction` contributes nothing, because
52
+ * its event parameter is `EventUnion<EM>` and TypeScript cannot infer `EM` back out of it.
53
+ */
54
+ withMiddleware<M extends MiddlewareInput<any, any>>(mw: M): DecoratableYoltra<R, S, Merge<EM, EMAddOf<M>>>;
55
+ /** Registers an effect and returns a `Yoltra` widened by whatever event map it declares. */
56
+ withEffect<Spec extends EffectSpec<any, any>>(spec: Spec): DecoratableYoltra<R, S, Merge<EM, EMAddOf<Spec>>>;
57
+ }
58
+ /**
59
+ * A {@link Yoltra} carrying the chainable decoration surface.
60
+ *
61
+ * @public
62
+ */
63
+ export type DecoratableYoltra<R extends string, S extends Record<R, any>, EM extends EventMapBase> = Yoltra<R, S, EM>;
26
64
  /**
27
65
  * One-call setup: create a store and its fully-typed React hooks together.
28
66
  *
@@ -41,7 +79,7 @@ export interface Yoltra<R extends string, S extends Record<R, any>, EM extends E
41
79
  * **The Suspense hooks are part of this set.** Take `useSuspenseAtomicProp` and
42
80
  * `useSuspenseAtomicProps` from here, not from the `@yoltra/react` barrel: the
43
81
  * barrel's copies read the *package-level* context, which this function never
44
- * fills, so they would throw `useStore must be used inside <StoreProvider>` at
82
+ * fills, so they would throw `[yoltra] No store in context` at
45
83
  * runtime with nothing in the types to warn you — the two are identical in
46
84
  * shape. The ones returned here are bound to this store's own context and need
47
85
  * no provider, like the rest of the set.
@@ -94,3 +132,26 @@ export declare function createYoltra<RM extends ReducersMapAny>(cfg: {
94
132
  };
95
133
  onEffectError?: (error: unknown, event: EventUnion<EMFromReducersStrict<RM>>) => void;
96
134
  }): Yoltra<keyof RM & string, StateFromReducers<RM>, EMFromReducersStrict<RM>>;
135
+ /**
136
+ * {@link YoltraDecoration.withSlice} as a free function.
137
+ *
138
+ * @remarks
139
+ * For a library handed a `Yoltra` it did not create. Identical to the method.
140
+ *
141
+ * @public
142
+ */
143
+ export declare function withSlice<R extends string, S extends Record<R, any>, EM extends EventMapBase, N extends string, Spec extends ReducerSpec<any, any>>(yoltra: Yoltra<R, S, EM>, name: N, spec: Spec, options?: {
144
+ owner?: string;
145
+ }): DecoratableYoltra<WidenNames<R, N>, SatisfiesSlices<WidenState<S, N, StateOfSpec<Spec>>, WidenNames<R, N>>, Merge<EM, EMAddOf<Spec>>>;
146
+ /**
147
+ * {@link YoltraDecoration.withMiddleware} as a free function.
148
+ *
149
+ * @public
150
+ */
151
+ export declare function withMiddleware<R extends string, S extends Record<R, any>, EM extends EventMapBase, M extends MiddlewareInput<any, any>>(yoltra: Yoltra<R, S, EM>, mw: M): DecoratableYoltra<R, S, Merge<EM, EMAddOf<M>>>;
152
+ /**
153
+ * {@link YoltraDecoration.withEffect} as a free function.
154
+ *
155
+ * @public
156
+ */
157
+ export declare function withEffect<R extends string, S extends Record<R, any>, EM extends EventMapBase, Spec extends EffectSpec<any, any>>(yoltra: Yoltra<R, S, EM>, spec: Spec): DecoratableYoltra<R, S, Merge<EM, EMAddOf<Spec>>>;
@@ -109,7 +109,17 @@ export type UseAtomicProps<R extends string, S extends Record<R, any>> = {
109
109
  *
110
110
  * @public
111
111
  */
112
- export type UseEvent<EM extends EventMapBase, S> = <C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, handler: (event: Event<EM, C, T>, getState: () => DeepReadonly<S>, emit: Emit<EM>, phase: NotifiedPhase) => void | Promise<void>, phase?: EventPhase) => void;
112
+ export type UseEvent<EM extends EventMapBase, S> = <C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, handler: (event: Event<EM, C, T>, getState: () => DeepReadonly<S>, emit: Emit<EM>, phase: NotifiedPhase) => void | Promise<void>, phase?: EventPhase, options?: {
113
+ /**
114
+ * Also run this handler while devtools is replaying, which it does not by default.
115
+ *
116
+ * @remarks
117
+ * Opt in only for a handler that derives view state purely from the event stream. A
118
+ * handler that publishes, writes or notifies must stay out: scrubbing a timeline is a
119
+ * debugging operation and should not reach a peer, a socket or an analytics endpoint.
120
+ */
121
+ duringReplay?: boolean;
122
+ }) => void;
113
123
  /**
114
124
  * The bundle of fully-typed hooks returned by {@link createHooks} (and, with the
115
125
  * store and provider added, by {@link createYoltra}).
@@ -243,4 +243,14 @@ export declare function useAtomicProps<R extends string, S extends Record<R, any
243
243
  *
244
244
  * @public
245
245
  */
246
- export declare function useEvent<EM extends EventMapBase, C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, handler: (event: Event<EM, C, T>, getState: () => DeepReadonly<any>, emit: Emit<EM>, phase: NotifiedPhase) => void | Promise<void>, phase?: EventPhase): void;
246
+ export declare function useEvent<EM extends EventMapBase, C extends keyof EM & string, T extends keyof EM[C] & string>(channel: C, type: T, handler: (event: Event<EM, C, T>, getState: () => DeepReadonly<any>, emit: Emit<EM>, phase: NotifiedPhase) => void | Promise<void>, phase?: EventPhase, options?: {
247
+ /**
248
+ * Also run this handler while devtools is replaying, which it does not by default.
249
+ *
250
+ * @remarks
251
+ * Opt in only for a handler that derives view state purely from the event stream. A
252
+ * handler that publishes, writes or notifies must stay out: scrubbing a timeline is a
253
+ * debugging operation and should not reach a peer, a socket or an analytics endpoint.
254
+ */
255
+ duringReplay?: boolean;
256
+ }): void;
@@ -9,8 +9,8 @@ export type { SuspenseCache } from './hooks/suspense.js';
9
9
  export { createHooks } from './hooks/createHooks.js';
10
10
  export type { UseAtomicProp, UseAtomicProps, UseEvent, YoltraHooks } from './hooks/createHooks.js';
11
11
  export type { UseSuspenseAtomicProp, UseSuspenseAtomicProps } from './hooks/suspense.js';
12
- export { createYoltra } from './createYoltra.js';
13
- export type { Yoltra } from './createYoltra.js';
12
+ export { createYoltra, withEffect, withMiddleware, withSlice } from './createYoltra.js';
13
+ export type { DecoratableYoltra, Yoltra, YoltraDecoration } from './createYoltra.js';
14
14
  export type { OneOrMany, PathValue } from './hooks/hooks.js';
15
15
  export type { SuspenseAtomicPropOptions, SuspenseAtomicPropsOptions } from './hooks/suspense.js';
16
16
  export { useEntity, useEntityField, useEntityIds } from './entity/useEntity.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoltra/react",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "React bindings for Yoltra",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -18,7 +18,8 @@
18
18
  ],
19
19
  "repository": {
20
20
  "type": "git",
21
- "url": "https://github.com/yoltra/yoltra.git"
21
+ "url": "https://github.com/yoltra/yoltra.git",
22
+ "directory": "packages/react"
22
23
  },
23
24
  "bugs": {
24
25
  "url": "https://github.com/yoltra/yoltra/issues"
@@ -37,10 +38,10 @@
37
38
  "README.md"
38
39
  ],
39
40
  "engines": {
40
- "node": ">=18.18"
41
+ "node": ">=18"
41
42
  },
42
43
  "peerDependencies": {
43
- "@yoltra/core": "^0.6.0",
44
+ "@yoltra/core": "^0.8.0",
44
45
  "react": "^18 || ^19"
45
46
  },
46
47
  "peerDependenciesMeta": {
@@ -83,7 +84,7 @@
83
84
  "vite-tsconfig-paths": "^4.3.2",
84
85
  "vite": "^7.3.6",
85
86
  "vitest": "3.2.7",
86
- "@yoltra/core": "0.6.0"
87
+ "@yoltra/core": "0.8.0"
87
88
  },
88
89
  "exports": {
89
90
  ".": {
@@ -117,7 +118,8 @@
117
118
  "docs:stamp": "node ../../tools/repo-tools/bin/docs-stamp.mjs docs",
118
119
  "docs:md": "typedoc --options ./typedoc.react.json",
119
120
  "docs:js": "typedoc --options ./typedoc.react.json --json ./.typedoc/react-en.json",
120
- "size": "node ../../tools/repo-tools/bin/size-check.cjs",
121
+ "size": "node ../../tools/repo-tools/bin/size-check.cjs --check-readme",
122
+ "size:write": "node ../../tools/repo-tools/bin/size-check.cjs --write-readme",
121
123
  "bench": "vitest bench --run",
122
124
  "bench:check": "node ../../tools/repo-tools/bin/bench-check.cjs",
123
125
  "bench:record": "node ../../tools/repo-tools/bin/bench-check.cjs --record"