@blac/react 2.0.22 → 2.1.1

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.
@@ -18,14 +18,11 @@ export interface BlocProviderProps<T extends StateContainerConstructor> {
18
18
  }
19
19
  /**
20
20
  * Provides args to descendant `useBloc` calls for a specific bloc class via
21
- * React context.
22
- *
23
- * Descendants calling `useBloc(Bloc)` without their own `args` resolve to the
24
- * args supplied here. Own `args` on the `useBloc` call always win.
21
+ * React context. Own `args` on the `useBloc` call always win.
25
22
  *
26
23
  * Multiple `BlocProvider` wrappers for different bloc classes compose: each
27
- * provider merges its entry into the inherited map, so nested providers for
28
- * different blocs do not interfere.
24
+ * merges its entry into the inherited map, so nested providers for different
25
+ * blocs do not interfere.
29
26
  *
30
27
  * @example
31
28
  * ```tsx
@@ -18,14 +18,11 @@ export interface BlocProviderProps<T extends StateContainerConstructor> {
18
18
  }
19
19
  /**
20
20
  * Provides args to descendant `useBloc` calls for a specific bloc class via
21
- * React context.
22
- *
23
- * Descendants calling `useBloc(Bloc)` without their own `args` resolve to the
24
- * args supplied here. Own `args` on the `useBloc` call always win.
21
+ * React context. Own `args` on the `useBloc` call always win.
25
22
  *
26
23
  * Multiple `BlocProvider` wrappers for different bloc classes compose: each
27
- * provider merges its entry into the inherited map, so nested providers for
28
- * different blocs do not interfere.
24
+ * merges its entry into the inherited map, so nested providers for different
25
+ * blocs do not interfere.
29
26
  *
30
27
  * @example
31
28
  * ```tsx
@@ -0,0 +1,40 @@
1
+ import { createContext, useContext } from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { getRegistry } from "@blac/core";
4
+ //#region src/RegistryProvider.tsx
5
+ const RegistryContext = createContext(null);
6
+ /**
7
+ * Scopes descendant `useBloc` calls to a specific registry instead of the
8
+ * module-global default.
9
+ *
10
+ * Useful for test isolation, SSR isolation, and micro-frontends that must
11
+ * not share bloc instances with the host page.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <RegistryProvider registry={new StateContainerRegistry()}>
16
+ * <App />
17
+ * </RegistryProvider>
18
+ * ```
19
+ * @public
20
+ */
21
+ function RegistryProvider({ registry, children }) {
22
+ return /* @__PURE__ */ jsx(RegistryContext.Provider, {
23
+ value: registry,
24
+ children
25
+ });
26
+ }
27
+ /**
28
+ * The registry `useBloc` uses here: the nearest {@link RegistryProvider}'s,
29
+ * else `getRegistry()`. The plain `@blac/core` helpers (`acquire`, `ensure`,
30
+ * `watch`, …) can't read React context and always use `getRegistry()`; call
31
+ * this registry's methods directly to stay inside a provider's scope.
32
+ * @public
33
+ */
34
+ function useRegistry() {
35
+ return useContext(RegistryContext) ?? getRegistry();
36
+ }
37
+ //#endregion
38
+ export { useRegistry as n, RegistryProvider as t };
39
+
40
+ //# sourceMappingURL=RegistryProvider-BjSXfLeK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegistryProvider-BjSXfLeK.js","names":[],"sources":["../src/RegistryProvider.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { getRegistry, type StateContainerRegistry } from '@blac/core';\n\nconst RegistryContext = createContext<StateContainerRegistry | null>(null);\n\n/**\n * Props for {@link RegistryProvider}.\n * @public\n */\nexport interface RegistryProviderProps {\n registry: StateContainerRegistry;\n children: ReactNode;\n}\n\n/**\n * Scopes descendant `useBloc` calls to a specific registry instead of the\n * module-global default.\n *\n * Useful for test isolation, SSR isolation, and micro-frontends that must\n * not share bloc instances with the host page.\n *\n * @example\n * ```tsx\n * <RegistryProvider registry={new StateContainerRegistry()}>\n * <App />\n * </RegistryProvider>\n * ```\n * @public\n */\nexport function RegistryProvider({\n registry,\n children,\n}: RegistryProviderProps): ReactElement {\n return (\n <RegistryContext.Provider value={registry}>\n {children}\n </RegistryContext.Provider>\n );\n}\n\n/**\n * The registry `useBloc` uses here: the nearest {@link RegistryProvider}'s,\n * else `getRegistry()`. The plain `@blac/core` helpers (`acquire`, `ensure`,\n * `watch`, …) can't read React context and always use `getRegistry()`; call\n * this registry's methods directly to stay inside a provider's scope.\n * @public\n */\nexport function useRegistry(): StateContainerRegistry {\n return useContext(RegistryContext) ?? getRegistry();\n}\n"],"mappings":";;;;AAQA,MAAM,kBAAkB,cAA6C,IAAI;;;;;;;;;;;;;;;;AA0BzE,SAAgB,iBAAiB,EAC/B,UACA,YACsC;CACtC,OACE,oBAAC,gBAAgB,UAAjB;EAA0B,OAAO;EAC9B;CACuB,CAAA;AAE9B;;;;;;;;AASA,SAAgB,cAAsC;CACpD,OAAO,WAAW,eAAe,KAAK,YAAY;AACpD"}
@@ -0,0 +1,51 @@
1
+ let react = require("react");
2
+ let react_jsx_runtime = require("react/jsx-runtime");
3
+ let _blac_core = require("@blac/core");
4
+ //#region src/RegistryProvider.tsx
5
+ const RegistryContext = (0, react.createContext)(null);
6
+ /**
7
+ * Scopes descendant `useBloc` calls to a specific registry instead of the
8
+ * module-global default.
9
+ *
10
+ * Useful for test isolation, SSR isolation, and micro-frontends that must
11
+ * not share bloc instances with the host page.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <RegistryProvider registry={new StateContainerRegistry()}>
16
+ * <App />
17
+ * </RegistryProvider>
18
+ * ```
19
+ * @public
20
+ */
21
+ function RegistryProvider({ registry, children }) {
22
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegistryContext.Provider, {
23
+ value: registry,
24
+ children
25
+ });
26
+ }
27
+ /**
28
+ * The registry `useBloc` uses here: the nearest {@link RegistryProvider}'s,
29
+ * else `getRegistry()`. The plain `@blac/core` helpers (`acquire`, `ensure`,
30
+ * `watch`, …) can't read React context and always use `getRegistry()`; call
31
+ * this registry's methods directly to stay inside a provider's scope.
32
+ * @public
33
+ */
34
+ function useRegistry() {
35
+ return (0, react.useContext)(RegistryContext) ?? (0, _blac_core.getRegistry)();
36
+ }
37
+ //#endregion
38
+ Object.defineProperty(exports, "RegistryProvider", {
39
+ enumerable: true,
40
+ get: function() {
41
+ return RegistryProvider;
42
+ }
43
+ });
44
+ Object.defineProperty(exports, "useRegistry", {
45
+ enumerable: true,
46
+ get: function() {
47
+ return useRegistry;
48
+ }
49
+ });
50
+
51
+ //# sourceMappingURL=RegistryProvider-F2qb_prD.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RegistryProvider-F2qb_prD.cjs","names":[],"sources":["../src/RegistryProvider.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { getRegistry, type StateContainerRegistry } from '@blac/core';\n\nconst RegistryContext = createContext<StateContainerRegistry | null>(null);\n\n/**\n * Props for {@link RegistryProvider}.\n * @public\n */\nexport interface RegistryProviderProps {\n registry: StateContainerRegistry;\n children: ReactNode;\n}\n\n/**\n * Scopes descendant `useBloc` calls to a specific registry instead of the\n * module-global default.\n *\n * Useful for test isolation, SSR isolation, and micro-frontends that must\n * not share bloc instances with the host page.\n *\n * @example\n * ```tsx\n * <RegistryProvider registry={new StateContainerRegistry()}>\n * <App />\n * </RegistryProvider>\n * ```\n * @public\n */\nexport function RegistryProvider({\n registry,\n children,\n}: RegistryProviderProps): ReactElement {\n return (\n <RegistryContext.Provider value={registry}>\n {children}\n </RegistryContext.Provider>\n );\n}\n\n/**\n * The registry `useBloc` uses here: the nearest {@link RegistryProvider}'s,\n * else `getRegistry()`. The plain `@blac/core` helpers (`acquire`, `ensure`,\n * `watch`, …) can't read React context and always use `getRegistry()`; call\n * this registry's methods directly to stay inside a provider's scope.\n * @public\n */\nexport function useRegistry(): StateContainerRegistry {\n return useContext(RegistryContext) ?? getRegistry();\n}\n"],"mappings":";;;;AAQA,MAAM,mBAAA,GAAA,MAAA,eAA+D,IAAI;;;;;;;;;;;;;;;;AA0BzE,SAAgB,iBAAiB,EAC/B,UACA,YACsC;CACtC,OACE,iBAAA,GAAA,kBAAA,KAAC,gBAAgB,UAAjB;EAA0B,OAAO;EAC9B;CACuB,CAAA;AAE9B;;;;;;;;AASA,SAAgB,cAAsC;CACpD,QAAA,GAAA,MAAA,YAAkB,eAAe,MAAA,GAAA,WAAA,aAAiB;AACpD"}
@@ -1,10 +1,5 @@
1
1
  import { type ReactElement, type ReactNode } from 'react';
2
- import type { StateContainerRegistry } from '@blac/core';
3
- /**
4
- * Internal context value: a registry to use in place of the module-global
5
- * default (`getRegistry()`), or `null` when no provider is present.
6
- */
7
- export declare const RegistryContext: import("react").Context<StateContainerRegistry | null>;
2
+ import { type StateContainerRegistry } from '@blac/core';
8
3
  /**
9
4
  * Props for {@link RegistryProvider}.
10
5
  * @public
@@ -29,3 +24,11 @@ export interface RegistryProviderProps {
29
24
  * @public
30
25
  */
31
26
  export declare function RegistryProvider({ registry, children, }: RegistryProviderProps): ReactElement;
27
+ /**
28
+ * The registry `useBloc` uses here: the nearest {@link RegistryProvider}'s,
29
+ * else `getRegistry()`. The plain `@blac/core` helpers (`acquire`, `ensure`,
30
+ * `watch`, …) can't read React context and always use `getRegistry()`; call
31
+ * this registry's methods directly to stay inside a provider's scope.
32
+ * @public
33
+ */
34
+ export declare function useRegistry(): StateContainerRegistry;
@@ -1,10 +1,5 @@
1
1
  import { type ReactElement, type ReactNode } from 'react';
2
- import type { StateContainerRegistry } from '@blac/core';
3
- /**
4
- * Internal context value: a registry to use in place of the module-global
5
- * default (`getRegistry()`), or `null` when no provider is present.
6
- */
7
- export declare const RegistryContext: import("react").Context<StateContainerRegistry | null>;
2
+ import { type StateContainerRegistry } from '@blac/core';
8
3
  /**
9
4
  * Props for {@link RegistryProvider}.
10
5
  * @public
@@ -29,3 +24,11 @@ export interface RegistryProviderProps {
29
24
  * @public
30
25
  */
31
26
  export declare function RegistryProvider({ registry, children, }: RegistryProviderProps): ReactElement;
27
+ /**
28
+ * The registry `useBloc` uses here: the nearest {@link RegistryProvider}'s,
29
+ * else `getRegistry()`. The plain `@blac/core` helpers (`acquire`, `ensure`,
30
+ * `watch`, …) can't read React context and always use `getRegistry()`; call
31
+ * this registry's methods directly to stay inside a provider's scope.
32
+ * @public
33
+ */
34
+ export declare function useRegistry(): StateContainerRegistry;
@@ -1,19 +1,18 @@
1
1
  /**
2
2
  * Build a per-consumer proxy for a bloc instance.
3
3
  *
4
- * Getters run with `this` bound to the **real instance**, not a proxy, so ES
4
+ * Getters run with `this` bound to the real instance, not the proxy, so ES
5
5
  * `#private` fields and methods work in user blocs. Path recording is done by
6
- * `[WITH_TRACKED_STATE]`, which makes the instance's own `state` getter report
7
- * the render's tracking proxy for the duration of the call; nested getter
8
- * chains stay tracked because the override is still set.
6
+ * `[WITH_TRACKED_STATE]`, which makes the instance's own `state` getter
7
+ * report the render's tracking proxy for the call's duration; nested getter
8
+ * chains stay tracked because the override remains set.
9
9
  *
10
10
  * One allocation per bloc acquisition (inside `useMemo`), so the proxy is
11
11
  * stable across renders.
12
12
  *
13
- * @param onDepHandle - Optional callback invoked when a read returns a branded
14
- * dep handle. Receives the original handle and returns the value to expose in
15
- * its place (the session-bound wrapper). The callback is responsible for
16
- * caching wrappers per handle to avoid re-allocation.
13
+ * @param onDepHandle - Invoked when a read returns a branded dep handle;
14
+ * returns the value (the session-bound wrapper) to expose in its place.
15
+ * Must cache wrappers per handle to avoid re-allocation.
17
16
  */
18
17
  export declare function buildTrackedProxy<T extends object>(instance: T, trackedStateRef: {
19
18
  current: unknown;
@@ -1,19 +1,18 @@
1
1
  /**
2
2
  * Build a per-consumer proxy for a bloc instance.
3
3
  *
4
- * Getters run with `this` bound to the **real instance**, not a proxy, so ES
4
+ * Getters run with `this` bound to the real instance, not the proxy, so ES
5
5
  * `#private` fields and methods work in user blocs. Path recording is done by
6
- * `[WITH_TRACKED_STATE]`, which makes the instance's own `state` getter report
7
- * the render's tracking proxy for the duration of the call; nested getter
8
- * chains stay tracked because the override is still set.
6
+ * `[WITH_TRACKED_STATE]`, which makes the instance's own `state` getter
7
+ * report the render's tracking proxy for the call's duration; nested getter
8
+ * chains stay tracked because the override remains set.
9
9
  *
10
10
  * One allocation per bloc acquisition (inside `useMemo`), so the proxy is
11
11
  * stable across renders.
12
12
  *
13
- * @param onDepHandle - Optional callback invoked when a read returns a branded
14
- * dep handle. Receives the original handle and returns the value to expose in
15
- * its place (the session-bound wrapper). The callback is responsible for
16
- * caching wrappers per handle to avoid re-allocation.
13
+ * @param onDepHandle - Invoked when a read returns a branded dep handle;
14
+ * returns the value (the session-bound wrapper) to expose in its place.
15
+ * Must cache wrappers per handle to avoid re-allocation.
17
16
  */
18
17
  export declare function buildTrackedProxy<T extends object>(instance: T, trackedStateRef: {
19
18
  current: unknown;
@@ -0,0 +1,54 @@
1
+ import type { StateContainer, StateContainerConstructor, StateContainerRegistry } from '@blac/core';
2
+ import { DEP_BRAND } from '@blac/core/internal';
3
+ import { type PathSet } from '@dirtytalk/structural';
4
+ /**
5
+ * The containers one `useBloc` consumer reads during a render: its primary
6
+ * bloc plus every dep reached through `this.<handle>.track()`.
7
+ *
8
+ * The render records entries; the commit calls `reconcile`, which subscribes
9
+ * and takes a ref on new deps and drops the ones no longer read. `dispose`
10
+ * releases everything. Refs are only taken at commit, so an uncommitted render
11
+ * never leaks one.
12
+ */
13
+ export declare class DepSession {
14
+ private readonly consumerId;
15
+ private readonly onChange;
16
+ private readonly entries;
17
+ private readonly subs;
18
+ private lastReconciled;
19
+ private readonly refId;
20
+ constructor(consumerId: string, onChange: () => void);
21
+ begin(primary: StateContainer, paths: PathSet): void;
22
+ record(dep: StateContainer, paths: PathSet, Type: StateContainerConstructor, key: string, args: unknown): void;
23
+ /** Forces the next `reconcile` to run in full. */
24
+ invalidate(): void;
25
+ isUnchanged(): boolean;
26
+ reconcile(registry: StateContainerRegistry): void;
27
+ dispose(): void;
28
+ private drop;
29
+ }
30
+ interface DepAccessOptionsLike {
31
+ args?: unknown;
32
+ }
33
+ /** Structural shape of a branded `depend()` handle as seen from React. */
34
+ export interface DepHandleLike {
35
+ track(options?: DepAccessOptionsLike): [unknown, StateContainer];
36
+ untracked(options?: DepAccessOptionsLike): StateContainer;
37
+ readonly [DEP_BRAND]: {
38
+ Type: StateContainerConstructor;
39
+ defaultArgs?: unknown;
40
+ };
41
+ }
42
+ /**
43
+ * Wrap a dep handle read inside a tracked getter. During a render (`tracked`
44
+ * is set) `.track()` records the dep's read paths into `session` and returns
45
+ * a tracked proxy, so the dep's own getters track too. Outside a render it
46
+ * returns the live `[state, dep]`, like the core handle.
47
+ *
48
+ * Args resolve per call, so one handle can reach several instances; proxies
49
+ * are cached per resolved instance.
50
+ */
51
+ export declare function makeDepWrapper(handle: DepHandleLike, registry: StateContainerRegistry, session: DepSession, tracked: {
52
+ current: unknown;
53
+ }, onDepHandle: (handle: object) => unknown): DepHandleLike;
54
+ export {};
@@ -0,0 +1,54 @@
1
+ import type { StateContainer, StateContainerConstructor, StateContainerRegistry } from '@blac/core';
2
+ import { DEP_BRAND } from '@blac/core/internal';
3
+ import { type PathSet } from '@dirtytalk/structural';
4
+ /**
5
+ * The containers one `useBloc` consumer reads during a render: its primary
6
+ * bloc plus every dep reached through `this.<handle>.track()`.
7
+ *
8
+ * The render records entries; the commit calls `reconcile`, which subscribes
9
+ * and takes a ref on new deps and drops the ones no longer read. `dispose`
10
+ * releases everything. Refs are only taken at commit, so an uncommitted render
11
+ * never leaks one.
12
+ */
13
+ export declare class DepSession {
14
+ private readonly consumerId;
15
+ private readonly onChange;
16
+ private readonly entries;
17
+ private readonly subs;
18
+ private lastReconciled;
19
+ private readonly refId;
20
+ constructor(consumerId: string, onChange: () => void);
21
+ begin(primary: StateContainer, paths: PathSet): void;
22
+ record(dep: StateContainer, paths: PathSet, Type: StateContainerConstructor, key: string, args: unknown): void;
23
+ /** Forces the next `reconcile` to run in full. */
24
+ invalidate(): void;
25
+ isUnchanged(): boolean;
26
+ reconcile(registry: StateContainerRegistry): void;
27
+ dispose(): void;
28
+ private drop;
29
+ }
30
+ interface DepAccessOptionsLike {
31
+ args?: unknown;
32
+ }
33
+ /** Structural shape of a branded `depend()` handle as seen from React. */
34
+ export interface DepHandleLike {
35
+ track(options?: DepAccessOptionsLike): [unknown, StateContainer];
36
+ untracked(options?: DepAccessOptionsLike): StateContainer;
37
+ readonly [DEP_BRAND]: {
38
+ Type: StateContainerConstructor;
39
+ defaultArgs?: unknown;
40
+ };
41
+ }
42
+ /**
43
+ * Wrap a dep handle read inside a tracked getter. During a render (`tracked`
44
+ * is set) `.track()` records the dep's read paths into `session` and returns
45
+ * a tracked proxy, so the dep's own getters track too. Outside a render it
46
+ * returns the live `[state, dep]`, like the core handle.
47
+ *
48
+ * Args resolve per call, so one handle can reach several instances; proxies
49
+ * are cached per resolved instance.
50
+ */
51
+ export declare function makeDepWrapper(handle: DepHandleLike, registry: StateContainerRegistry, session: DepSession, tracked: {
52
+ current: unknown;
53
+ }, onDepHandle: (handle: object) => unknown): DepHandleLike;
54
+ export {};
@@ -0,0 +1,14 @@
1
+ import { type PathInterner, type PathSet } from '@dirtytalk/structural';
2
+ /**
3
+ * Add an ancestor-watch id for every ancestor of every tracked leaf, so a
4
+ * `patch` that replaces a parent atomically (e.g. the array `items`) wakes a
5
+ * consumer that read a child (`items.length`).
6
+ *
7
+ * Ancestor-watch ids only match marks the source emits for atomic
8
+ * replacements, never a plain-object pulse-up: `{'user.email'}` does not wake
9
+ * when a sibling `user.name` changes. The `''` root is never added; a root
10
+ * change already marks `ALL_PATHS`.
11
+ *
12
+ * Returns `paths` itself when no leaf has an ancestor.
13
+ */
14
+ export declare function expandWithAncestors(paths: PathSet, interner: PathInterner): PathSet;
@@ -0,0 +1,14 @@
1
+ import { type PathInterner, type PathSet } from '@dirtytalk/structural';
2
+ /**
3
+ * Add an ancestor-watch id for every ancestor of every tracked leaf, so a
4
+ * `patch` that replaces a parent atomically (e.g. the array `items`) wakes a
5
+ * consumer that read a child (`items.length`).
6
+ *
7
+ * Ancestor-watch ids only match marks the source emits for atomic
8
+ * replacements, never a plain-object pulse-up: `{'user.email'}` does not wake
9
+ * when a sibling `user.name` changes. The `''` root is never added; a root
10
+ * change already marks `ALL_PATHS`.
11
+ *
12
+ * Returns `paths` itself when no leaf has an ancestor.
13
+ */
14
+ export declare function expandWithAncestors(paths: PathSet, interner: PathInterner): PathSet;