@blac/react 2.0.0-rc.1 → 2.0.0-rc.11

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/dist/index.cjs CHANGED
@@ -1,13 +1,178 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.useExternalBlocStore = exports.useBlocNext = exports.useBloc = void 0;
7
- var useBloc_1 = require("./useBloc");
8
- Object.defineProperty(exports, "useBloc", { enumerable: true, get: function () { return __importDefault(useBloc_1).default; } });
9
- var useBloc_2 = require("./useBloc");
10
- Object.defineProperty(exports, "useBlocNext", { enumerable: true, get: function () { return __importDefault(useBloc_2).default; } });
11
- var useExternalBlocStore_1 = require("./useExternalBlocStore");
12
- Object.defineProperty(exports, "useExternalBlocStore", { enumerable: true, get: function () { return __importDefault(useExternalBlocStore_1).default; } });
13
- //# sourceMappingURL=index.js.map
1
+ let react = require("react");
2
+ let __blac_core = require("@blac/core");
3
+
4
+ //#region src/utils/instance-keys.ts
5
+ /**
6
+ * Instance key generation utilities for React integration
7
+ */
8
+ /**
9
+ * Generate an instance key for a bloc
10
+ *
11
+ * Logic:
12
+ * - If user provides instanceId, use it (convert number to string)
13
+ * - If isolated, generate or reuse a unique key for this component
14
+ * - Otherwise, return undefined (use default key)
15
+ *
16
+ * @param componentRef - React component reference (persists across remounts)
17
+ * @param isIsolated - Whether the bloc is isolated
18
+ * @param providedId - User-provided instance ID (from options)
19
+ * @returns Instance key string or undefined for default
20
+ */
21
+ function generateInstanceKey(componentRef, isIsolated, providedId) {
22
+ if (providedId !== void 0) return typeof providedId === "number" ? String(providedId) : providedId;
23
+ if (isIsolated) {
24
+ if (!componentRef.__blocInstanceId) componentRef.__blocInstanceId = (0, __blac_core.generateIsolatedKey)();
25
+ return componentRef.__blocInstanceId;
26
+ }
27
+ }
28
+
29
+ //#endregion
30
+ //#region src/useBloc.ts
31
+ function determineTrackingMode(options) {
32
+ return {
33
+ useManualDeps: options?.dependencies !== void 0,
34
+ autoTrackEnabled: options?.autoTrack !== false
35
+ };
36
+ }
37
+ /**
38
+ * React hook that connects a component to a state container with automatic re-render on state changes.
39
+ *
40
+ * Supports three tracking modes:
41
+ * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy
42
+ * - **Manual dependencies**: Explicit dependency array like useEffect
43
+ * - **No tracking**: Returns full state without optimization
44
+ *
45
+ * @template T - The state container constructor type
46
+ * @param BlocClass - The state container class to connect to
47
+ * @param options - Configuration options for tracking mode and instance management
48
+ * @returns Tuple with [state, bloc instance, ref]
49
+ *
50
+ * @example Basic usage
51
+ * ```ts
52
+ * const [state, myBloc, ref] = useBloc(MyBloc);
53
+ * ```
54
+ *
55
+ * @example With manual dependencies
56
+ * ```ts
57
+ * const [state, myBloc] = useBloc(MyBloc, {
58
+ * dependencies: (state) => [state.count]
59
+ * });
60
+ * ```
61
+ *
62
+ * @example With isolated instance
63
+ * ```ts
64
+ * const [state, myBloc] = useBloc(MyBloc, {
65
+ * instanceId: 'unique-id'
66
+ * });
67
+ * ```
68
+ */
69
+ function useBloc(BlocClass, options) {
70
+ const componentRef = (0, react.useRef)({});
71
+ const Constructor = BlocClass;
72
+ const isIsolated = (0, __blac_core.isIsolatedClass)(BlocClass);
73
+ const initialPropsRef = (0, react.useRef)(options?.props);
74
+ const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] = (0, react.useMemo)(() => {
75
+ const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
76
+ const instance = BlocClass.resolve(instanceKey$1, initialPropsRef.current);
77
+ if (initialPropsRef.current !== void 0) instance.updateProps(initialPropsRef.current);
78
+ const { useManualDeps, autoTrackEnabled } = determineTrackingMode(options);
79
+ let subscribeFn;
80
+ let getSnapshotFn;
81
+ let adapterState$1;
82
+ if (useManualDeps && options?.dependencies) {
83
+ adapterState$1 = (0, __blac_core.initManualDepsState)(instance);
84
+ subscribeFn = (0, __blac_core.createManualDepsSubscribe)(instance, adapterState$1, { dependencies: options.dependencies });
85
+ getSnapshotFn = (0, __blac_core.createManualDepsSnapshot)(instance, adapterState$1, { dependencies: options.dependencies });
86
+ } else if (!autoTrackEnabled) {
87
+ adapterState$1 = (0, __blac_core.initNoTrackState)(instance);
88
+ subscribeFn = (0, __blac_core.createNoTrackSubscribe)(instance);
89
+ getSnapshotFn = (0, __blac_core.createNoTrackSnapshot)(instance);
90
+ } else {
91
+ adapterState$1 = (0, __blac_core.initAutoTrackState)(instance);
92
+ subscribeFn = (0, __blac_core.createAutoTrackSubscribe)(instance, adapterState$1);
93
+ getSnapshotFn = (0, __blac_core.createAutoTrackSnapshot)(instance, adapterState$1);
94
+ }
95
+ return [
96
+ adapterState$1.proxiedBloc,
97
+ subscribeFn,
98
+ getSnapshotFn,
99
+ instanceKey$1,
100
+ adapterState$1,
101
+ instance
102
+ ];
103
+ }, [BlocClass, options?.instanceId]);
104
+ const state = (0, react.useSyncExternalStore)(subscribe, getSnapshot);
105
+ const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
106
+ const externalDepsManager = (0, react.useRef)(new __blac_core.ExternalDependencyManager());
107
+ (0, react.useEffect)(() => {
108
+ if (options?.props !== initialPropsRef.current) rawInstance.updateProps(options?.props);
109
+ }, [options?.props, rawInstance]);
110
+ (0, react.useEffect)(() => {
111
+ (0, __blac_core.disableGetterTracking)(adapterState, rawInstance);
112
+ externalDepsManager.current.updateSubscriptions(adapterState.getterTracker, rawInstance, forceUpdate);
113
+ });
114
+ (0, react.useEffect)(() => {
115
+ if (options?.onMount) options.onMount(bloc);
116
+ return () => {
117
+ externalDepsManager.current.cleanup();
118
+ if (options?.onUnmount) options.onUnmount(bloc);
119
+ Constructor.release(instanceKey);
120
+ if (isIsolated && !rawInstance.isDisposed) rawInstance.dispose();
121
+ };
122
+ }, []);
123
+ return [
124
+ state,
125
+ bloc,
126
+ componentRef
127
+ ];
128
+ }
129
+
130
+ //#endregion
131
+ //#region src/useBlocActions.ts
132
+ /**
133
+ * React hook that connects to a state container instance without triggering re-renders.
134
+ * Use this when you only need to call actions on the bloc without subscribing to state changes.
135
+ *
136
+ * @template T - The state container constructor type
137
+ * @param BlocClass - The state container class to connect to
138
+ * @param options - Configuration options for instance management and lifecycle
139
+ * @returns The state container instance for calling actions
140
+ *
141
+ * @example Basic usage
142
+ * ```ts
143
+ * const myBloc = useBlocActions(MyBloc);
144
+ * // Call methods on the bloc without re-rendering
145
+ * myBloc.someMethod();
146
+ * ```
147
+ *
148
+ * @example With isolated instance
149
+ * ```ts
150
+ * const myBloc = useBlocActions(MyBloc, {
151
+ * instanceId: 'unique-id'
152
+ * });
153
+ * ```
154
+ */
155
+ function useBlocActions(BlocClass, options) {
156
+ const componentRef = (0, react.useRef)({});
157
+ const initialPropsRef = (0, react.useRef)(options?.props);
158
+ const [bloc, instanceKey] = (0, react.useMemo)(() => {
159
+ const isIsolated = (0, __blac_core.isIsolatedClass)(BlocClass);
160
+ const Constructor = BlocClass;
161
+ const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
162
+ return [Constructor.resolve(instanceKey$1, initialPropsRef.current), instanceKey$1];
163
+ }, [BlocClass]);
164
+ (0, react.useEffect)(() => {
165
+ if (options?.onMount) options.onMount(bloc);
166
+ return () => {
167
+ if (options?.onUnmount) options.onUnmount(bloc);
168
+ BlocClass.release(instanceKey);
169
+ if ((0, __blac_core.isIsolatedClass)(BlocClass) && !bloc.isDisposed) bloc.dispose();
170
+ };
171
+ }, []);
172
+ return bloc;
173
+ }
174
+
175
+ //#endregion
176
+ exports.useBloc = useBloc;
177
+ exports.useBlocActions = useBlocActions;
178
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["instanceKey","subscribeFn: (callback: () => void) => () => void","getSnapshotFn: () => ExtractState<TBloc>","adapterState: AdapterState<TBloc>","adapterState","ExternalDependencyManager","instanceKey"],"sources":["../src/utils/instance-keys.ts","../src/useBloc.ts","../src/useBlocActions.ts"],"sourcesContent":["/**\n * Instance key generation utilities for React integration\n */\n\nimport { generateIsolatedKey } from '@blac/core';\nimport type { ComponentRef } from '../types';\n\n/**\n * Generate an instance key for a bloc\n *\n * Logic:\n * - If user provides instanceId, use it (convert number to string)\n * - If isolated, generate or reuse a unique key for this component\n * - Otherwise, return undefined (use default key)\n *\n * @param componentRef - React component reference (persists across remounts)\n * @param isIsolated - Whether the bloc is isolated\n * @param providedId - User-provided instance ID (from options)\n * @returns Instance key string or undefined for default\n */\nexport function generateInstanceKey(\n componentRef: ComponentRef,\n isIsolated: boolean,\n providedId?: string | number,\n): string | undefined {\n // User explicitly provided an ID - use it\n if (providedId !== undefined) {\n return typeof providedId === 'number' ? String(providedId) : providedId;\n }\n\n // Isolated bloc - generate unique key per component\n if (isIsolated) {\n if (!componentRef.__blocInstanceId) {\n componentRef.__blocInstanceId = generateIsolatedKey();\n }\n return componentRef.__blocInstanceId;\n }\n\n // Shared bloc - use default key (undefined)\n return undefined;\n}\n","import {\n useMemo,\n useSyncExternalStore,\n useEffect,\n useRef,\n useReducer,\n} from 'react';\nimport {\n type BlocConstructor,\n StateContainer,\n type ExtractState,\n type AdapterState,\n ExternalDependencyManager,\n createAutoTrackSubscribe,\n createManualDepsSubscribe,\n createNoTrackSubscribe,\n createAutoTrackSnapshot,\n createManualDepsSnapshot,\n createNoTrackSnapshot,\n initAutoTrackState,\n initManualDepsState,\n initNoTrackState,\n disableGetterTracking,\n isIsolatedClass,\n} from '@blac/core';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\n\ntype StateContainerConstructor<TBloc extends StateContainer<any, any>> =\n BlocConstructor<TBloc> & {\n resolve(instanceKey?: string, ...args: any[]): TBloc;\n release(instanceKey?: string): void;\n };\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainer<any, any>>(\n options?: UseBlocOptions<TBloc>,\n): TrackingMode {\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled: options?.autoTrack !== false,\n };\n}\n\n/**\n * React hook that connects a component to a state container with automatic re-render on state changes.\n *\n * Supports three tracking modes:\n * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy\n * - **Manual dependencies**: Explicit dependency array like useEffect\n * - **No tracking**: Returns full state without optimization\n *\n * @template T - The state container constructor type\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options for tracking mode and instance management\n * @returns Tuple with [state, bloc instance, ref]\n *\n * @example Basic usage\n * ```ts\n * const [state, myBloc, ref] = useBloc(MyBloc);\n * ```\n *\n * @example With manual dependencies\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * dependencies: (state) => [state.count]\n * });\n * ```\n *\n * @example With isolated instance\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * instanceId: 'unique-id'\n * });\n * ```\n */\nexport function useBloc<\n T extends new (...args: any[]) => StateContainer<any, any>,\n>(\n BlocClass: T & BlocConstructor<InstanceType<T>>,\n options?: UseBlocOptions<InstanceType<T>>,\n): UseBlocReturn<InstanceType<T>> {\n type TBloc = InstanceType<T>;\n const componentRef = useRef<ComponentRef>({});\n const Constructor = BlocClass as StateContainerConstructor<TBloc>;\n const isIsolated = isIsolatedClass(BlocClass);\n\n const initialPropsRef = useRef(options?.props);\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<TBloc>,\n string | undefined,\n AdapterState<TBloc>,\n TBloc,\n ]\n >(() => {\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = BlocClass.resolve(instanceKey, initialPropsRef.current);\n\n if (initialPropsRef.current !== undefined) {\n instance.updateProps(initialPropsRef.current);\n }\n\n const { useManualDeps, autoTrackEnabled } =\n determineTrackingMode(options);\n\n let subscribeFn: (callback: () => void) => () => void;\n let getSnapshotFn: () => ExtractState<TBloc>;\n let adapterState: AdapterState<TBloc>;\n\n if (useManualDeps && options?.dependencies) {\n adapterState = initManualDepsState(instance);\n subscribeFn = createManualDepsSubscribe(instance, adapterState, {\n dependencies: options.dependencies,\n });\n getSnapshotFn = createManualDepsSnapshot(instance, adapterState, {\n dependencies: options.dependencies,\n });\n } else if (!autoTrackEnabled) {\n adapterState = initNoTrackState(instance);\n subscribeFn = createNoTrackSubscribe(instance);\n getSnapshotFn = createNoTrackSnapshot(instance);\n } else {\n adapterState = initAutoTrackState(instance);\n subscribeFn = createAutoTrackSubscribe(instance, adapterState);\n getSnapshotFn = createAutoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc!,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n }, [BlocClass, options?.instanceId]);\n\n const state = useSyncExternalStore(subscribe, getSnapshot);\n\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n const externalDepsManager = useRef(new ExternalDependencyManager());\n\n useEffect(() => {\n if (options?.props !== initialPropsRef.current) {\n rawInstance.updateProps(options?.props);\n }\n }, [options?.props, rawInstance]);\n\n useEffect(() => {\n disableGetterTracking(adapterState, rawInstance);\n externalDepsManager.current.updateSubscriptions(\n adapterState.getterTracker,\n rawInstance,\n forceUpdate,\n );\n });\n\n useEffect(() => {\n if (options?.onMount) {\n options.onMount(bloc);\n }\n\n return () => {\n externalDepsManager.current.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc);\n }\n\n Constructor.release(instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<TBloc>;\n}\n","import { useMemo, useEffect, useRef } from 'react';\nimport {\n type BlocConstructor,\n StateContainer,\n isIsolatedClass,\n} from '@blac/core';\nimport type { ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\n\ntype StateContainerConstructor<TBloc extends StateContainer<any, any>> =\n BlocConstructor<TBloc> & {\n resolve(instanceKey?: string, ...args: any[]): TBloc;\n release(instanceKey?: string): void;\n };\n\n/**\n * Configuration options for useBlocActions hook\n * @template TBloc - The state container type\n * @template TProps - Props type passed to the container\n */\nexport interface UseBlocActionsOptions<TBloc, TProps = any> {\n /** Props passed to bloc constructor or updateProps */\n props?: TProps;\n /** Custom instance identifier for shared or isolated instances */\n instanceId?: string | number;\n /** Callback invoked when bloc instance mounts */\n onMount?: (bloc: TBloc) => void;\n /** Callback invoked when bloc instance unmounts */\n onUnmount?: (bloc: TBloc) => void;\n}\n\n/**\n * React hook that connects to a state container instance without triggering re-renders.\n * Use this when you only need to call actions on the bloc without subscribing to state changes.\n *\n * @template T - The state container constructor type\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options for instance management and lifecycle\n * @returns The state container instance for calling actions\n *\n * @example Basic usage\n * ```ts\n * const myBloc = useBlocActions(MyBloc);\n * // Call methods on the bloc without re-rendering\n * myBloc.someMethod();\n * ```\n *\n * @example With isolated instance\n * ```ts\n * const myBloc = useBlocActions(MyBloc, {\n * instanceId: 'unique-id'\n * });\n * ```\n */\nexport function useBlocActions<\n T extends new (...args: any[]) => StateContainer<any, any>,\n>(\n BlocClass: T & BlocConstructor<InstanceType<T>>,\n options?: UseBlocActionsOptions<InstanceType<T>>,\n): InstanceType<T> {\n type TBloc = InstanceType<T>;\n const componentRef = useRef<ComponentRef>({});\n const initialPropsRef = useRef(options?.props);\n\n const [bloc, instanceKey] = useMemo(() => {\n const isIsolated = isIsolatedClass(BlocClass);\n const Constructor = BlocClass as StateContainerConstructor<TBloc>;\n\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = Constructor.resolve(instanceKey, initialPropsRef.current);\n\n return [instance, instanceKey] as const;\n }, [BlocClass]);\n\n useEffect(() => {\n if (options?.onMount) {\n options.onMount(bloc);\n }\n\n return () => {\n if (options?.onUnmount) {\n options.onUnmount(bloc);\n }\n\n const Constructor = BlocClass as StateContainerConstructor<TBloc>;\n Constructor.release(instanceKey);\n\n if (isIsolatedClass(BlocClass) && !bloc.isDisposed) {\n bloc.dispose();\n }\n };\n }, []);\n\n return bloc;\n}\n"],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import { BlocConstructor } from '@blac/core';
2
+ import type { ExtractState } from '@blac/core';
3
+ import type { RefObject } from 'react';
4
+ import { StateContainer } from '@blac/core';
5
+
6
+ /* Excluded from this release type: ComponentRef */
7
+
8
+ /**
9
+ * React hook that connects a component to a state container with automatic re-render on state changes.
10
+ *
11
+ * Supports three tracking modes:
12
+ * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy
13
+ * - **Manual dependencies**: Explicit dependency array like useEffect
14
+ * - **No tracking**: Returns full state without optimization
15
+ *
16
+ * @template T - The state container constructor type
17
+ * @param BlocClass - The state container class to connect to
18
+ * @param options - Configuration options for tracking mode and instance management
19
+ * @returns Tuple with [state, bloc instance, ref]
20
+ *
21
+ * @example Basic usage
22
+ * ```ts
23
+ * const [state, myBloc, ref] = useBloc(MyBloc);
24
+ * ```
25
+ *
26
+ * @example With manual dependencies
27
+ * ```ts
28
+ * const [state, myBloc] = useBloc(MyBloc, {
29
+ * dependencies: (state) => [state.count]
30
+ * });
31
+ * ```
32
+ *
33
+ * @example With isolated instance
34
+ * ```ts
35
+ * const [state, myBloc] = useBloc(MyBloc, {
36
+ * instanceId: 'unique-id'
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function useBloc<T extends new (...args: any[]) => StateContainer<any, any>>(BlocClass: T & BlocConstructor<InstanceType<T>>, options?: UseBlocOptions<InstanceType<T>>): UseBlocReturn<InstanceType<T>>;
41
+
42
+ /**
43
+ * React hook that connects to a state container instance without triggering re-renders.
44
+ * Use this when you only need to call actions on the bloc without subscribing to state changes.
45
+ *
46
+ * @template T - The state container constructor type
47
+ * @param BlocClass - The state container class to connect to
48
+ * @param options - Configuration options for instance management and lifecycle
49
+ * @returns The state container instance for calling actions
50
+ *
51
+ * @example Basic usage
52
+ * ```ts
53
+ * const myBloc = useBlocActions(MyBloc);
54
+ * // Call methods on the bloc without re-rendering
55
+ * myBloc.someMethod();
56
+ * ```
57
+ *
58
+ * @example With isolated instance
59
+ * ```ts
60
+ * const myBloc = useBlocActions(MyBloc, {
61
+ * instanceId: 'unique-id'
62
+ * });
63
+ * ```
64
+ */
65
+ export declare function useBlocActions<T extends new (...args: any[]) => StateContainer<any, any>>(BlocClass: T & BlocConstructor<InstanceType<T>>, options?: UseBlocActionsOptions<InstanceType<T>>): InstanceType<T>;
66
+
67
+ /**
68
+ * Configuration options for useBlocActions hook
69
+ * @template TBloc - The state container type
70
+ * @template TProps - Props type passed to the container
71
+ */
72
+ export declare interface UseBlocActionsOptions<TBloc, TProps = any> {
73
+ /** Props passed to bloc constructor or updateProps */
74
+ props?: TProps;
75
+ /** Custom instance identifier for shared or isolated instances */
76
+ instanceId?: string | number;
77
+ /** Callback invoked when bloc instance mounts */
78
+ onMount?: (bloc: TBloc) => void;
79
+ /** Callback invoked when bloc instance unmounts */
80
+ onUnmount?: (bloc: TBloc) => void;
81
+ }
82
+
83
+ /**
84
+ * Configuration options for useBloc hook
85
+ * @template TBloc - The state container type
86
+ * @template TProps - Props type passed to the container
87
+ */
88
+ export declare interface UseBlocOptions<TBloc, TProps = any> {
89
+ /** Props passed to bloc constructor or updateProps */
90
+ props?: TProps;
91
+ /** Custom instance identifier for shared or isolated instances */
92
+ instanceId?: string | number;
93
+ /** Manual dependency array like useEffect (disables autoTrack) */
94
+ dependencies?: (state: ExtractState<TBloc>, bloc: TBloc) => unknown[];
95
+ /** Enable automatic property tracking via Proxy (default: true) */
96
+ autoTrack?: boolean;
97
+ /** Disable caching for getter tracking */
98
+ disableGetterCache?: boolean;
99
+ /** Callback invoked when bloc instance mounts */
100
+ onMount?: (bloc: TBloc) => void;
101
+ /** Callback invoked when bloc instance unmounts */
102
+ onUnmount?: (bloc: TBloc) => void;
103
+ }
104
+
105
+ /**
106
+ * Tuple return type from useBloc hook containing state, bloc instance, and ref
107
+ * - [0] Current state value
108
+ * - [1] State container instance (bloc) for calling actions
109
+ * - [2] Ref object for accessing component ref (advanced use cases)
110
+ */
111
+ export declare type UseBlocReturn<TBloc> = [
112
+ ExtractState<TBloc>,
113
+ TBloc,
114
+ RefObject<ComponentRef>
115
+ ];
116
+
117
+ export { }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,117 @@
1
- export { default as useBloc } from './useBloc';
2
- export { default as useBlocNext } from './useBloc';
3
- export { default as useExternalBlocStore } from './useExternalBlocStore';
4
- //# sourceMappingURL=index.d.ts.map
1
+ import { BlocConstructor } from '@blac/core';
2
+ import type { ExtractState } from '@blac/core';
3
+ import type { RefObject } from 'react';
4
+ import { StateContainer } from '@blac/core';
5
+
6
+ /* Excluded from this release type: ComponentRef */
7
+
8
+ /**
9
+ * React hook that connects a component to a state container with automatic re-render on state changes.
10
+ *
11
+ * Supports three tracking modes:
12
+ * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy
13
+ * - **Manual dependencies**: Explicit dependency array like useEffect
14
+ * - **No tracking**: Returns full state without optimization
15
+ *
16
+ * @template T - The state container constructor type
17
+ * @param BlocClass - The state container class to connect to
18
+ * @param options - Configuration options for tracking mode and instance management
19
+ * @returns Tuple with [state, bloc instance, ref]
20
+ *
21
+ * @example Basic usage
22
+ * ```ts
23
+ * const [state, myBloc, ref] = useBloc(MyBloc);
24
+ * ```
25
+ *
26
+ * @example With manual dependencies
27
+ * ```ts
28
+ * const [state, myBloc] = useBloc(MyBloc, {
29
+ * dependencies: (state) => [state.count]
30
+ * });
31
+ * ```
32
+ *
33
+ * @example With isolated instance
34
+ * ```ts
35
+ * const [state, myBloc] = useBloc(MyBloc, {
36
+ * instanceId: 'unique-id'
37
+ * });
38
+ * ```
39
+ */
40
+ export declare function useBloc<T extends new (...args: any[]) => StateContainer<any, any>>(BlocClass: T & BlocConstructor<InstanceType<T>>, options?: UseBlocOptions<InstanceType<T>>): UseBlocReturn<InstanceType<T>>;
41
+
42
+ /**
43
+ * React hook that connects to a state container instance without triggering re-renders.
44
+ * Use this when you only need to call actions on the bloc without subscribing to state changes.
45
+ *
46
+ * @template T - The state container constructor type
47
+ * @param BlocClass - The state container class to connect to
48
+ * @param options - Configuration options for instance management and lifecycle
49
+ * @returns The state container instance for calling actions
50
+ *
51
+ * @example Basic usage
52
+ * ```ts
53
+ * const myBloc = useBlocActions(MyBloc);
54
+ * // Call methods on the bloc without re-rendering
55
+ * myBloc.someMethod();
56
+ * ```
57
+ *
58
+ * @example With isolated instance
59
+ * ```ts
60
+ * const myBloc = useBlocActions(MyBloc, {
61
+ * instanceId: 'unique-id'
62
+ * });
63
+ * ```
64
+ */
65
+ export declare function useBlocActions<T extends new (...args: any[]) => StateContainer<any, any>>(BlocClass: T & BlocConstructor<InstanceType<T>>, options?: UseBlocActionsOptions<InstanceType<T>>): InstanceType<T>;
66
+
67
+ /**
68
+ * Configuration options for useBlocActions hook
69
+ * @template TBloc - The state container type
70
+ * @template TProps - Props type passed to the container
71
+ */
72
+ export declare interface UseBlocActionsOptions<TBloc, TProps = any> {
73
+ /** Props passed to bloc constructor or updateProps */
74
+ props?: TProps;
75
+ /** Custom instance identifier for shared or isolated instances */
76
+ instanceId?: string | number;
77
+ /** Callback invoked when bloc instance mounts */
78
+ onMount?: (bloc: TBloc) => void;
79
+ /** Callback invoked when bloc instance unmounts */
80
+ onUnmount?: (bloc: TBloc) => void;
81
+ }
82
+
83
+ /**
84
+ * Configuration options for useBloc hook
85
+ * @template TBloc - The state container type
86
+ * @template TProps - Props type passed to the container
87
+ */
88
+ export declare interface UseBlocOptions<TBloc, TProps = any> {
89
+ /** Props passed to bloc constructor or updateProps */
90
+ props?: TProps;
91
+ /** Custom instance identifier for shared or isolated instances */
92
+ instanceId?: string | number;
93
+ /** Manual dependency array like useEffect (disables autoTrack) */
94
+ dependencies?: (state: ExtractState<TBloc>, bloc: TBloc) => unknown[];
95
+ /** Enable automatic property tracking via Proxy (default: true) */
96
+ autoTrack?: boolean;
97
+ /** Disable caching for getter tracking */
98
+ disableGetterCache?: boolean;
99
+ /** Callback invoked when bloc instance mounts */
100
+ onMount?: (bloc: TBloc) => void;
101
+ /** Callback invoked when bloc instance unmounts */
102
+ onUnmount?: (bloc: TBloc) => void;
103
+ }
104
+
105
+ /**
106
+ * Tuple return type from useBloc hook containing state, bloc instance, and ref
107
+ * - [0] Current state value
108
+ * - [1] State container instance (bloc) for calling actions
109
+ * - [2] Ref object for accessing component ref (advanced use cases)
110
+ */
111
+ export declare type UseBlocReturn<TBloc> = [
112
+ ExtractState<TBloc>,
113
+ TBloc,
114
+ RefObject<ComponentRef>
115
+ ];
116
+
117
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,177 @@
1
+ import { useEffect, useMemo, useReducer, useRef, useSyncExternalStore } from "react";
2
+ import { ExternalDependencyManager, createAutoTrackSnapshot, createAutoTrackSubscribe, createManualDepsSnapshot, createManualDepsSubscribe, createNoTrackSnapshot, createNoTrackSubscribe, disableGetterTracking, generateIsolatedKey, initAutoTrackState, initManualDepsState, initNoTrackState, isIsolatedClass } from "@blac/core";
3
+
4
+ //#region src/utils/instance-keys.ts
5
+ /**
6
+ * Instance key generation utilities for React integration
7
+ */
8
+ /**
9
+ * Generate an instance key for a bloc
10
+ *
11
+ * Logic:
12
+ * - If user provides instanceId, use it (convert number to string)
13
+ * - If isolated, generate or reuse a unique key for this component
14
+ * - Otherwise, return undefined (use default key)
15
+ *
16
+ * @param componentRef - React component reference (persists across remounts)
17
+ * @param isIsolated - Whether the bloc is isolated
18
+ * @param providedId - User-provided instance ID (from options)
19
+ * @returns Instance key string or undefined for default
20
+ */
21
+ function generateInstanceKey(componentRef, isIsolated, providedId) {
22
+ if (providedId !== void 0) return typeof providedId === "number" ? String(providedId) : providedId;
23
+ if (isIsolated) {
24
+ if (!componentRef.__blocInstanceId) componentRef.__blocInstanceId = generateIsolatedKey();
25
+ return componentRef.__blocInstanceId;
26
+ }
27
+ }
28
+
29
+ //#endregion
30
+ //#region src/useBloc.ts
31
+ function determineTrackingMode(options) {
32
+ return {
33
+ useManualDeps: options?.dependencies !== void 0,
34
+ autoTrackEnabled: options?.autoTrack !== false
35
+ };
36
+ }
37
+ /**
38
+ * React hook that connects a component to a state container with automatic re-render on state changes.
39
+ *
40
+ * Supports three tracking modes:
41
+ * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy
42
+ * - **Manual dependencies**: Explicit dependency array like useEffect
43
+ * - **No tracking**: Returns full state without optimization
44
+ *
45
+ * @template T - The state container constructor type
46
+ * @param BlocClass - The state container class to connect to
47
+ * @param options - Configuration options for tracking mode and instance management
48
+ * @returns Tuple with [state, bloc instance, ref]
49
+ *
50
+ * @example Basic usage
51
+ * ```ts
52
+ * const [state, myBloc, ref] = useBloc(MyBloc);
53
+ * ```
54
+ *
55
+ * @example With manual dependencies
56
+ * ```ts
57
+ * const [state, myBloc] = useBloc(MyBloc, {
58
+ * dependencies: (state) => [state.count]
59
+ * });
60
+ * ```
61
+ *
62
+ * @example With isolated instance
63
+ * ```ts
64
+ * const [state, myBloc] = useBloc(MyBloc, {
65
+ * instanceId: 'unique-id'
66
+ * });
67
+ * ```
68
+ */
69
+ function useBloc(BlocClass, options) {
70
+ const componentRef = useRef({});
71
+ const Constructor = BlocClass;
72
+ const isIsolated = isIsolatedClass(BlocClass);
73
+ const initialPropsRef = useRef(options?.props);
74
+ const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] = useMemo(() => {
75
+ const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
76
+ const instance = BlocClass.resolve(instanceKey$1, initialPropsRef.current);
77
+ if (initialPropsRef.current !== void 0) instance.updateProps(initialPropsRef.current);
78
+ const { useManualDeps, autoTrackEnabled } = determineTrackingMode(options);
79
+ let subscribeFn;
80
+ let getSnapshotFn;
81
+ let adapterState$1;
82
+ if (useManualDeps && options?.dependencies) {
83
+ adapterState$1 = initManualDepsState(instance);
84
+ subscribeFn = createManualDepsSubscribe(instance, adapterState$1, { dependencies: options.dependencies });
85
+ getSnapshotFn = createManualDepsSnapshot(instance, adapterState$1, { dependencies: options.dependencies });
86
+ } else if (!autoTrackEnabled) {
87
+ adapterState$1 = initNoTrackState(instance);
88
+ subscribeFn = createNoTrackSubscribe(instance);
89
+ getSnapshotFn = createNoTrackSnapshot(instance);
90
+ } else {
91
+ adapterState$1 = initAutoTrackState(instance);
92
+ subscribeFn = createAutoTrackSubscribe(instance, adapterState$1);
93
+ getSnapshotFn = createAutoTrackSnapshot(instance, adapterState$1);
94
+ }
95
+ return [
96
+ adapterState$1.proxiedBloc,
97
+ subscribeFn,
98
+ getSnapshotFn,
99
+ instanceKey$1,
100
+ adapterState$1,
101
+ instance
102
+ ];
103
+ }, [BlocClass, options?.instanceId]);
104
+ const state = useSyncExternalStore(subscribe, getSnapshot);
105
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
106
+ const externalDepsManager = useRef(new ExternalDependencyManager());
107
+ useEffect(() => {
108
+ if (options?.props !== initialPropsRef.current) rawInstance.updateProps(options?.props);
109
+ }, [options?.props, rawInstance]);
110
+ useEffect(() => {
111
+ disableGetterTracking(adapterState, rawInstance);
112
+ externalDepsManager.current.updateSubscriptions(adapterState.getterTracker, rawInstance, forceUpdate);
113
+ });
114
+ useEffect(() => {
115
+ if (options?.onMount) options.onMount(bloc);
116
+ return () => {
117
+ externalDepsManager.current.cleanup();
118
+ if (options?.onUnmount) options.onUnmount(bloc);
119
+ Constructor.release(instanceKey);
120
+ if (isIsolated && !rawInstance.isDisposed) rawInstance.dispose();
121
+ };
122
+ }, []);
123
+ return [
124
+ state,
125
+ bloc,
126
+ componentRef
127
+ ];
128
+ }
129
+
130
+ //#endregion
131
+ //#region src/useBlocActions.ts
132
+ /**
133
+ * React hook that connects to a state container instance without triggering re-renders.
134
+ * Use this when you only need to call actions on the bloc without subscribing to state changes.
135
+ *
136
+ * @template T - The state container constructor type
137
+ * @param BlocClass - The state container class to connect to
138
+ * @param options - Configuration options for instance management and lifecycle
139
+ * @returns The state container instance for calling actions
140
+ *
141
+ * @example Basic usage
142
+ * ```ts
143
+ * const myBloc = useBlocActions(MyBloc);
144
+ * // Call methods on the bloc without re-rendering
145
+ * myBloc.someMethod();
146
+ * ```
147
+ *
148
+ * @example With isolated instance
149
+ * ```ts
150
+ * const myBloc = useBlocActions(MyBloc, {
151
+ * instanceId: 'unique-id'
152
+ * });
153
+ * ```
154
+ */
155
+ function useBlocActions(BlocClass, options) {
156
+ const componentRef = useRef({});
157
+ const initialPropsRef = useRef(options?.props);
158
+ const [bloc, instanceKey] = useMemo(() => {
159
+ const isIsolated = isIsolatedClass(BlocClass);
160
+ const Constructor = BlocClass;
161
+ const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
162
+ return [Constructor.resolve(instanceKey$1, initialPropsRef.current), instanceKey$1];
163
+ }, [BlocClass]);
164
+ useEffect(() => {
165
+ if (options?.onMount) options.onMount(bloc);
166
+ return () => {
167
+ if (options?.onUnmount) options.onUnmount(bloc);
168
+ BlocClass.release(instanceKey);
169
+ if (isIsolatedClass(BlocClass) && !bloc.isDisposed) bloc.dispose();
170
+ };
171
+ }, []);
172
+ return bloc;
173
+ }
174
+
175
+ //#endregion
176
+ export { useBloc, useBlocActions };
177
+ //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,qCAA+C;AAAtC,mHAAA,OAAO,OAAW;AAC3B,qCAAmD;AAA1C,uHAAA,OAAO,OAAe;AAC/B,+DAAyE;AAAhE,6IAAA,OAAO,OAAwB"}
1
+ {"version":3,"file":"index.js","names":["instanceKey","subscribeFn: (callback: () => void) => () => void","getSnapshotFn: () => ExtractState<TBloc>","adapterState: AdapterState<TBloc>","adapterState","instanceKey"],"sources":["../src/utils/instance-keys.ts","../src/useBloc.ts","../src/useBlocActions.ts"],"sourcesContent":["/**\n * Instance key generation utilities for React integration\n */\n\nimport { generateIsolatedKey } from '@blac/core';\nimport type { ComponentRef } from '../types';\n\n/**\n * Generate an instance key for a bloc\n *\n * Logic:\n * - If user provides instanceId, use it (convert number to string)\n * - If isolated, generate or reuse a unique key for this component\n * - Otherwise, return undefined (use default key)\n *\n * @param componentRef - React component reference (persists across remounts)\n * @param isIsolated - Whether the bloc is isolated\n * @param providedId - User-provided instance ID (from options)\n * @returns Instance key string or undefined for default\n */\nexport function generateInstanceKey(\n componentRef: ComponentRef,\n isIsolated: boolean,\n providedId?: string | number,\n): string | undefined {\n // User explicitly provided an ID - use it\n if (providedId !== undefined) {\n return typeof providedId === 'number' ? String(providedId) : providedId;\n }\n\n // Isolated bloc - generate unique key per component\n if (isIsolated) {\n if (!componentRef.__blocInstanceId) {\n componentRef.__blocInstanceId = generateIsolatedKey();\n }\n return componentRef.__blocInstanceId;\n }\n\n // Shared bloc - use default key (undefined)\n return undefined;\n}\n","import {\n useMemo,\n useSyncExternalStore,\n useEffect,\n useRef,\n useReducer,\n} from 'react';\nimport {\n type BlocConstructor,\n StateContainer,\n type ExtractState,\n type AdapterState,\n ExternalDependencyManager,\n createAutoTrackSubscribe,\n createManualDepsSubscribe,\n createNoTrackSubscribe,\n createAutoTrackSnapshot,\n createManualDepsSnapshot,\n createNoTrackSnapshot,\n initAutoTrackState,\n initManualDepsState,\n initNoTrackState,\n disableGetterTracking,\n isIsolatedClass,\n} from '@blac/core';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\n\ntype StateContainerConstructor<TBloc extends StateContainer<any, any>> =\n BlocConstructor<TBloc> & {\n resolve(instanceKey?: string, ...args: any[]): TBloc;\n release(instanceKey?: string): void;\n };\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainer<any, any>>(\n options?: UseBlocOptions<TBloc>,\n): TrackingMode {\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled: options?.autoTrack !== false,\n };\n}\n\n/**\n * React hook that connects a component to a state container with automatic re-render on state changes.\n *\n * Supports three tracking modes:\n * - **Auto-tracking** (default): Automatically detects accessed state properties via Proxy\n * - **Manual dependencies**: Explicit dependency array like useEffect\n * - **No tracking**: Returns full state without optimization\n *\n * @template T - The state container constructor type\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options for tracking mode and instance management\n * @returns Tuple with [state, bloc instance, ref]\n *\n * @example Basic usage\n * ```ts\n * const [state, myBloc, ref] = useBloc(MyBloc);\n * ```\n *\n * @example With manual dependencies\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * dependencies: (state) => [state.count]\n * });\n * ```\n *\n * @example With isolated instance\n * ```ts\n * const [state, myBloc] = useBloc(MyBloc, {\n * instanceId: 'unique-id'\n * });\n * ```\n */\nexport function useBloc<\n T extends new (...args: any[]) => StateContainer<any, any>,\n>(\n BlocClass: T & BlocConstructor<InstanceType<T>>,\n options?: UseBlocOptions<InstanceType<T>>,\n): UseBlocReturn<InstanceType<T>> {\n type TBloc = InstanceType<T>;\n const componentRef = useRef<ComponentRef>({});\n const Constructor = BlocClass as StateContainerConstructor<TBloc>;\n const isIsolated = isIsolatedClass(BlocClass);\n\n const initialPropsRef = useRef(options?.props);\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<TBloc>,\n string | undefined,\n AdapterState<TBloc>,\n TBloc,\n ]\n >(() => {\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = BlocClass.resolve(instanceKey, initialPropsRef.current);\n\n if (initialPropsRef.current !== undefined) {\n instance.updateProps(initialPropsRef.current);\n }\n\n const { useManualDeps, autoTrackEnabled } =\n determineTrackingMode(options);\n\n let subscribeFn: (callback: () => void) => () => void;\n let getSnapshotFn: () => ExtractState<TBloc>;\n let adapterState: AdapterState<TBloc>;\n\n if (useManualDeps && options?.dependencies) {\n adapterState = initManualDepsState(instance);\n subscribeFn = createManualDepsSubscribe(instance, adapterState, {\n dependencies: options.dependencies,\n });\n getSnapshotFn = createManualDepsSnapshot(instance, adapterState, {\n dependencies: options.dependencies,\n });\n } else if (!autoTrackEnabled) {\n adapterState = initNoTrackState(instance);\n subscribeFn = createNoTrackSubscribe(instance);\n getSnapshotFn = createNoTrackSnapshot(instance);\n } else {\n adapterState = initAutoTrackState(instance);\n subscribeFn = createAutoTrackSubscribe(instance, adapterState);\n getSnapshotFn = createAutoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc!,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n }, [BlocClass, options?.instanceId]);\n\n const state = useSyncExternalStore(subscribe, getSnapshot);\n\n const [, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n const externalDepsManager = useRef(new ExternalDependencyManager());\n\n useEffect(() => {\n if (options?.props !== initialPropsRef.current) {\n rawInstance.updateProps(options?.props);\n }\n }, [options?.props, rawInstance]);\n\n useEffect(() => {\n disableGetterTracking(adapterState, rawInstance);\n externalDepsManager.current.updateSubscriptions(\n adapterState.getterTracker,\n rawInstance,\n forceUpdate,\n );\n });\n\n useEffect(() => {\n if (options?.onMount) {\n options.onMount(bloc);\n }\n\n return () => {\n externalDepsManager.current.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc);\n }\n\n Constructor.release(instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<TBloc>;\n}\n","import { useMemo, useEffect, useRef } from 'react';\nimport {\n type BlocConstructor,\n StateContainer,\n isIsolatedClass,\n} from '@blac/core';\nimport type { ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\n\ntype StateContainerConstructor<TBloc extends StateContainer<any, any>> =\n BlocConstructor<TBloc> & {\n resolve(instanceKey?: string, ...args: any[]): TBloc;\n release(instanceKey?: string): void;\n };\n\n/**\n * Configuration options for useBlocActions hook\n * @template TBloc - The state container type\n * @template TProps - Props type passed to the container\n */\nexport interface UseBlocActionsOptions<TBloc, TProps = any> {\n /** Props passed to bloc constructor or updateProps */\n props?: TProps;\n /** Custom instance identifier for shared or isolated instances */\n instanceId?: string | number;\n /** Callback invoked when bloc instance mounts */\n onMount?: (bloc: TBloc) => void;\n /** Callback invoked when bloc instance unmounts */\n onUnmount?: (bloc: TBloc) => void;\n}\n\n/**\n * React hook that connects to a state container instance without triggering re-renders.\n * Use this when you only need to call actions on the bloc without subscribing to state changes.\n *\n * @template T - The state container constructor type\n * @param BlocClass - The state container class to connect to\n * @param options - Configuration options for instance management and lifecycle\n * @returns The state container instance for calling actions\n *\n * @example Basic usage\n * ```ts\n * const myBloc = useBlocActions(MyBloc);\n * // Call methods on the bloc without re-rendering\n * myBloc.someMethod();\n * ```\n *\n * @example With isolated instance\n * ```ts\n * const myBloc = useBlocActions(MyBloc, {\n * instanceId: 'unique-id'\n * });\n * ```\n */\nexport function useBlocActions<\n T extends new (...args: any[]) => StateContainer<any, any>,\n>(\n BlocClass: T & BlocConstructor<InstanceType<T>>,\n options?: UseBlocActionsOptions<InstanceType<T>>,\n): InstanceType<T> {\n type TBloc = InstanceType<T>;\n const componentRef = useRef<ComponentRef>({});\n const initialPropsRef = useRef(options?.props);\n\n const [bloc, instanceKey] = useMemo(() => {\n const isIsolated = isIsolatedClass(BlocClass);\n const Constructor = BlocClass as StateContainerConstructor<TBloc>;\n\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = Constructor.resolve(instanceKey, initialPropsRef.current);\n\n return [instance, instanceKey] as const;\n }, [BlocClass]);\n\n useEffect(() => {\n if (options?.onMount) {\n options.onMount(bloc);\n }\n\n return () => {\n if (options?.onUnmount) {\n options.onUnmount(bloc);\n }\n\n const Constructor = BlocClass as StateContainerConstructor<TBloc>;\n Constructor.release(instanceKey);\n\n if (isIsolatedClass(BlocClass) && !bloc.isDisposed) {\n bloc.dispose();\n }\n };\n }, []);\n\n return bloc;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,oBACd,cACA,YACA,YACoB;AAEpB,KAAI,eAAe,OACjB,QAAO,OAAO,eAAe,WAAW,OAAO,WAAW,GAAG;AAI/D,KAAI,YAAY;AACd,MAAI,CAAC,aAAa,iBAChB,cAAa,mBAAmB,qBAAqB;AAEvD,SAAO,aAAa;;;;;;ACIxB,SAAS,sBACP,SACc;AACd,QAAO;EACL,eAAe,SAAS,iBAAiB;EACzC,kBAAkB,SAAS,cAAc;EAC1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCH,SAAgB,QAGd,WACA,SACgC;CAEhC,MAAM,eAAe,OAAqB,EAAE,CAAC;CAC7C,MAAM,cAAc;CACpB,MAAM,aAAa,gBAAgB,UAAU;CAE7C,MAAM,kBAAkB,OAAO,SAAS,MAAM;CAE9C,MAAM,CAAC,MAAM,WAAW,aAAa,aAAa,cAAc,eAC9D,cASQ;EACN,MAAMA,gBAAc,oBAClB,aAAa,SACb,YACA,SAAS,WACV;EAED,MAAM,WAAW,UAAU,QAAQA,eAAa,gBAAgB,QAAQ;AAExE,MAAI,gBAAgB,YAAY,OAC9B,UAAS,YAAY,gBAAgB,QAAQ;EAG/C,MAAM,EAAE,eAAe,qBACrB,sBAAsB,QAAQ;EAEhC,IAAIC;EACJ,IAAIC;EACJ,IAAIC;AAEJ,MAAI,iBAAiB,SAAS,cAAc;AAC1C,oBAAe,oBAAoB,SAAS;AAC5C,iBAAc,0BAA0B,UAAUC,gBAAc,EAC9D,cAAc,QAAQ,cACvB,CAAC;AACF,mBAAgB,yBAAyB,UAAUA,gBAAc,EAC/D,cAAc,QAAQ,cACvB,CAAC;aACO,CAAC,kBAAkB;AAC5B,oBAAe,iBAAiB,SAAS;AACzC,iBAAc,uBAAuB,SAAS;AAC9C,mBAAgB,sBAAsB,SAAS;SAC1C;AACL,oBAAe,mBAAmB,SAAS;AAC3C,iBAAc,yBAAyB,UAAUA,eAAa;AAC9D,mBAAgB,wBAAwB,UAAUA,eAAa;;AAGjE,SAAO;GACLA,eAAa;GACb;GACA;GACAJ;GACAI;GACA;GACD;IACA,CAAC,WAAW,SAAS,WAAW,CAAC;CAEtC,MAAM,QAAQ,qBAAqB,WAAW,YAAY;CAE1D,MAAM,GAAG,eAAe,YAAY,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,sBAAsB,OAAO,IAAI,2BAA2B,CAAC;AAEnE,iBAAgB;AACd,MAAI,SAAS,UAAU,gBAAgB,QACrC,aAAY,YAAY,SAAS,MAAM;IAExC,CAAC,SAAS,OAAO,YAAY,CAAC;AAEjC,iBAAgB;AACd,wBAAsB,cAAc,YAAY;AAChD,sBAAoB,QAAQ,oBAC1B,aAAa,eACb,aACA,YACD;GACD;AAEF,iBAAgB;AACd,MAAI,SAAS,QACX,SAAQ,QAAQ,KAAK;AAGvB,eAAa;AACX,uBAAoB,QAAQ,SAAS;AAErC,OAAI,SAAS,UACX,SAAQ,UAAU,KAAK;AAGzB,eAAY,QAAQ,YAAY;AAEhC,OAAI,cAAc,CAAC,YAAY,WAC7B,aAAY,SAAS;;IAGxB,EAAE,CAAC;AAEN,QAAO;EAAC;EAAO;EAAM;EAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1IpC,SAAgB,eAGd,WACA,SACiB;CAEjB,MAAM,eAAe,OAAqB,EAAE,CAAC;CAC7C,MAAM,kBAAkB,OAAO,SAAS,MAAM;CAE9C,MAAM,CAAC,MAAM,eAAe,cAAc;EACxC,MAAM,aAAa,gBAAgB,UAAU;EAC7C,MAAM,cAAc;EAEpB,MAAMC,gBAAc,oBAClB,aAAa,SACb,YACA,SAAS,WACV;AAID,SAAO,CAFU,YAAY,QAAQA,eAAa,gBAAgB,QAAQ,EAExDA,cAAY;IAC7B,CAAC,UAAU,CAAC;AAEf,iBAAgB;AACd,MAAI,SAAS,QACX,SAAQ,QAAQ,KAAK;AAGvB,eAAa;AACX,OAAI,SAAS,UACX,SAAQ,UAAU,KAAK;AAIzB,GADoB,UACR,QAAQ,YAAY;AAEhC,OAAI,gBAAgB,UAAU,IAAI,CAAC,KAAK,WACtC,MAAK,SAAS;;IAGjB,EAAE,CAAC;AAEN,QAAO"}