Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

@blac/preact

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@blac/preact - npm Package Compare versions

Comparing version
2.0.2
to
2.0.3
+24
-110
dist/index.cjs
let preact_hooks = require("preact/hooks");
let preact_compat = require("preact/compat");
let _blac_core = require("@blac/core");
let _blac_adapter = require("@blac/adapter");

@@ -25,3 +25,3 @@ //#region src/utils/instance-keys.ts

if (isIsolated) {
if (!componentRef.__blocInstanceId) componentRef.__blocInstanceId = (0, _blac_core.generateIsolatedKey)();
if (!componentRef.__blocInstanceId) componentRef.__blocInstanceId = (0, _blac_adapter.generateIsolatedKey)();
return componentRef.__blocInstanceId;

@@ -74,4 +74,4 @@ }

function determineTrackingMode(options) {
const globalConfig$1 = getBlacPreactConfig();
const autoTrackEnabled = options?.autoTrack !== void 0 ? options.autoTrack : globalConfig$1.autoTrack;
const globalConfig = getBlacPreactConfig();
const autoTrackEnabled = options?.autoTrack !== void 0 ? options.autoTrack : globalConfig.autoTrack;
return {

@@ -90,7 +90,4 @@ useManualDeps: options?.dependencies !== void 0,

*
* **Note:** This hook does NOT support stateless containers (StatelessCubit, StatelessVertex).
* Use `useBlocActions()` instead for stateless containers.
*
* @template T - The state container constructor type (inferred from BlocClass)
* @param BlocClass - The state container class to connect to (must not be stateless)
* @param BlocClass - The state container class to connect to
* @param options - Configuration options for tracking mode and instance management

@@ -120,44 +117,29 @@ * @returns Tuple with [state, bloc instance, ref]

const componentRef = (0, preact_hooks.useRef)({});
const initialPropsRef = (0, preact_hooks.useRef)(options?.props);
const isStateless = (0, _blac_core.isStatelessClass)(BlocClass);
const isIsolated = (0, _blac_core.isIsolatedClass)(BlocClass);
const isIsolated = (0, _blac_adapter.isIsolatedClass)(BlocClass);
const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] = (0, preact_hooks.useMemo)(() => {
if (isStateless) {
console.error(`[BlaC] useBloc() does not support stateless containers. "${BlocClass.name}" is a StatelessCubit or StatelessVertex. Use useBlocActions() instead for stateless containers.`);
const instance$1 = (0, _blac_core.acquire)(BlocClass, "default");
return [
instance$1,
() => () => {},
() => ({}),
void 0,
null,
instance$1
];
}
const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
const instance = (0, _blac_core.acquire)(BlocClass, instanceKey$1, { props: initialPropsRef.current });
if (initialPropsRef.current !== void 0) instance.updateProps(initialPropsRef.current);
const instanceKey = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
const instance = (0, _blac_adapter.acquire)(BlocClass, instanceKey);
const { useManualDeps, autoTrackEnabled } = determineTrackingMode(options);
let subscribeFn;
let getSnapshotFn;
let adapterState$1;
let adapterState;
if (useManualDeps && options?.dependencies) {
adapterState$1 = (0, _blac_core.manualDepsInit)(instance);
subscribeFn = (0, _blac_core.manualDepsSubscribe)(instance, adapterState$1, { dependencies: options.dependencies });
getSnapshotFn = (0, _blac_core.manualDepsSnapshot)(instance, adapterState$1, { dependencies: options.dependencies });
adapterState = (0, _blac_adapter.manualDepsInit)(instance);
subscribeFn = (0, _blac_adapter.manualDepsSubscribe)(instance, adapterState, { dependencies: options.dependencies });
getSnapshotFn = (0, _blac_adapter.manualDepsSnapshot)(instance, adapterState, { dependencies: options.dependencies });
} else if (!autoTrackEnabled) {
adapterState$1 = (0, _blac_core.noTrackInit)(instance);
subscribeFn = (0, _blac_core.noTrackSubscribe)(instance);
getSnapshotFn = (0, _blac_core.noTrackSnapshot)(instance);
adapterState = (0, _blac_adapter.noTrackInit)(instance);
subscribeFn = (0, _blac_adapter.noTrackSubscribe)(instance);
getSnapshotFn = (0, _blac_adapter.noTrackSnapshot)(instance);
} else {
adapterState$1 = (0, _blac_core.autoTrackInit)(instance);
subscribeFn = (0, _blac_core.autoTrackSubscribe)(instance, adapterState$1);
getSnapshotFn = (0, _blac_core.autoTrackSnapshot)(instance, adapterState$1);
adapterState = (0, _blac_adapter.autoTrackInit)(instance);
subscribeFn = (0, _blac_adapter.autoTrackSubscribe)(instance, adapterState);
getSnapshotFn = (0, _blac_adapter.autoTrackSnapshot)(instance, adapterState);
}
return [
adapterState$1.proxiedBloc,
adapterState.proxiedBloc,
subscribeFn,
getSnapshotFn,
instanceKey$1,
adapterState$1,
instanceKey,
adapterState,
instance

@@ -167,3 +149,2 @@ ];

BlocClass,
isStateless,
isIsolated,

@@ -174,18 +155,8 @@ options?.instanceId

const [, forceUpdate] = (0, preact_hooks.useReducer)((x) => x + 1, 0);
const externalDepsManager = (0, preact_hooks.useRef)(new _blac_core.ExternalDepsManager());
const externalDepsManager = (0, preact_hooks.useRef)(new _blac_adapter.ExternalDepsManager());
(0, preact_hooks.useEffect)(() => {
if (isStateless) return;
if (options?.props !== initialPropsRef.current) rawInstance.updateProps(options?.props);
}, [
options?.props,
rawInstance,
isStateless
]);
(0, preact_hooks.useEffect)(() => {
if (isStateless || !adapterState) return;
(0, _blac_core.disableGetterTracking)(adapterState, rawInstance);
(0, _blac_adapter.disableGetterTracking)(adapterState, rawInstance);
externalDepsManager.current.updateSubscriptions(adapterState.getterState, rawInstance, () => forceUpdate(0));
});
(0, preact_hooks.useEffect)(() => {
if (isStateless) return;
if (options?.onMount) options.onMount(bloc);

@@ -195,3 +166,3 @@ return () => {

if (options?.onUnmount) options.onUnmount(bloc);
(0, _blac_core.release)(BlocClass, instanceKey);
(0, _blac_adapter.release)(BlocClass, instanceKey);
if (isIsolated && !rawInstance.isDisposed) rawInstance.dispose();

@@ -208,62 +179,5 @@ };

//#endregion
//#region src/useBlocActions.ts
/**
* Preact hook that connects to a state container instance without triggering re-renders.
* Use this when you only need to call actions on the bloc without subscribing to state changes.
*
* **This is the recommended hook for stateless containers** (StatelessCubit, StatelessVertex).
* It also works with regular Cubit/Vertex when you don't need state subscriptions.
*
* @template T - The state container constructor type (inferred from BlocClass)
* @param BlocClass - The state container class to connect to (supports both stateful and stateless)
* @param options - Configuration options for instance management and lifecycle
* @returns The state container instance for calling actions
*
* @example Basic usage with stateless container
* ```ts
* class AnalyticsService extends StatelessCubit {
* trackEvent(name: string) { ... }
* }
*
* const analytics = useBlocActions(AnalyticsService);
* analytics.trackEvent('page_view');
* ```
*
* @example With stateful container (no re-renders)
* ```ts
* const myBloc = useBlocActions(MyBloc);
* myBloc.someMethod(); // Won't cause re-renders
* ```
*
* @example With isolated instance
* ```ts
* const myBloc = useBlocActions(MyBloc, {
* instanceId: 'unique-id'
* });
* ```
*/
function useBlocActions(BlocClass, options) {
const componentRef = (0, preact_hooks.useRef)({});
const initialPropsRef = (0, preact_hooks.useRef)(options?.props);
const [bloc, instanceKey] = (0, preact_hooks.useMemo)(() => {
const isIsolated = (0, _blac_core.isIsolatedClass)(BlocClass);
const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
return [(0, _blac_core.acquire)(BlocClass, instanceKey$1, { props: initialPropsRef.current }), instanceKey$1];
}, [BlocClass]);
(0, preact_hooks.useEffect)(() => {
if (options?.onMount) options.onMount(bloc);
return () => {
if (options?.onUnmount) options.onUnmount(bloc);
(0, _blac_core.release)(BlocClass, instanceKey);
if ((0, _blac_core.isIsolatedClass)(BlocClass) && !bloc.isDisposed) bloc.dispose();
};
}, []);
return bloc;
}
//#endregion
exports.configureBlacPreact = configureBlacPreact;
exports.resetBlacPreactConfig = resetBlacPreactConfig;
exports.useBloc = useBloc;
exports.useBlocActions = useBlocActions;
//# sourceMappingURL=index.cjs.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"index.cjs","names":["globalConfig","instance","instanceKey","adapterState","ExternalDepsManager","instanceKey"],"sources":["../src/utils/instance-keys.ts","../src/config.ts","../src/useBloc.ts","../src/useBlocActions.ts"],"sourcesContent":["/**\n * Instance key generation utilities for Preact 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 - Preact 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","/**\n * Global configuration for @blac/preact\n */\n\nexport interface BlacPreactConfig {\n /** Enable automatic property tracking via Proxy (default: true) */\n autoTrack: boolean;\n}\n\nconst defaultConfig: BlacPreactConfig = {\n autoTrack: true,\n};\n\nlet globalConfig: BlacPreactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/preact hooks.\n *\n * @example\n * ```ts\n * import { configureBlacPreact } from '@blac/preact';\n *\n * // Disable auto-tracking globally\n * configureBlacPreact({\n * autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacPreact(config: Partial<BlacPreactConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacPreactConfig(): BlacPreactConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacPreactConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","import { useMemo, useEffect, useRef, useReducer } from 'preact/hooks';\nimport { useSyncExternalStore } from 'preact/compat';\nimport {\n type ExtractState,\n type AdapterState,\n type IsStatelessContainer,\n ExternalDepsManager,\n autoTrackSubscribe,\n manualDepsSubscribe,\n noTrackSubscribe,\n autoTrackSnapshot,\n manualDepsSnapshot,\n noTrackSnapshot,\n autoTrackInit,\n manualDepsInit,\n noTrackInit,\n disableGetterTracking,\n isIsolatedClass,\n isStatelessClass,\n StateContainerConstructor,\n InstanceState,\n acquire,\n release,\n} from '@blac/core';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\nimport { getBlacPreactConfig } from './config';\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n options?: UseBlocOptions<TBloc>,\n): TrackingMode {\n const globalConfig = getBlacPreactConfig();\n const autoTrackEnabled =\n options?.autoTrack !== undefined\n ? options.autoTrack\n : globalConfig.autoTrack;\n\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled,\n };\n}\n\n/**\n * Type that produces a TypeScript error when a stateless container is used.\n * Evaluates to `never` for stateless containers, causing a type mismatch.\n */\ntype StatefulContainer<T extends StateContainerConstructor> =\n IsStatelessContainer<T> extends true ? never : T;\n\n/**\n * Preact 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 * **Note:** This hook does NOT support stateless containers (StatelessCubit, StatelessVertex).\n * Use `useBlocActions()` instead for stateless containers.\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to (must not be stateless)\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 StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: StatefulContainer<T>,\n options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n type TBloc = InstanceState<T>;\n\n const componentRef = useRef<ComponentRef>({});\n const initialPropsRef = useRef(options?.props);\n const isStateless = isStatelessClass(BlocClass);\n const isIsolated = isIsolatedClass(BlocClass);\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<T>,\n string | undefined,\n AdapterState<T> | null,\n TBloc,\n ]\n >(() => {\n // Runtime check for stateless containers - log error but don't crash\n if (isStateless) {\n console.error(\n `[BlaC] useBloc() does not support stateless containers. ` +\n `\"${BlocClass.name}\" is a StatelessCubit or StatelessVertex. ` +\n `Use useBlocActions() instead for stateless containers.`,\n );\n const instance = acquire(BlocClass, 'default') as TBloc;\n // Return minimal working functions that won't subscribe to anything\n return [\n instance,\n () => () => {},\n () => ({}) as ExtractState<T>,\n undefined,\n null,\n instance,\n ];\n }\n\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey, {\n props: initialPropsRef.current,\n }) as TBloc;\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<T>;\n let adapterState: AdapterState<T>;\n\n if (useManualDeps && options?.dependencies) {\n adapterState = manualDepsInit(instance);\n subscribeFn = manualDepsSubscribe(instance, adapterState, {\n dependencies: options.dependencies,\n });\n getSnapshotFn = manualDepsSnapshot(instance, adapterState, {\n dependencies: options.dependencies,\n });\n } else if (!autoTrackEnabled) {\n adapterState = noTrackInit(instance);\n subscribeFn = noTrackSubscribe(instance);\n getSnapshotFn = noTrackSnapshot(instance);\n } else {\n adapterState = autoTrackInit(instance);\n subscribeFn = autoTrackSubscribe(instance, adapterState);\n getSnapshotFn = autoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc as TBloc,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n }, [BlocClass, isStateless, isIsolated, 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 ExternalDepsManager());\n\n useEffect(() => {\n if (isStateless) return;\n if (options?.props !== initialPropsRef.current) {\n rawInstance.updateProps(options?.props);\n }\n }, [options?.props, rawInstance, isStateless]);\n\n useEffect(() => {\n if (isStateless || !adapterState) return;\n disableGetterTracking(adapterState, rawInstance);\n externalDepsManager.current.updateSubscriptions(\n adapterState.getterState,\n rawInstance,\n () => forceUpdate(0),\n );\n });\n\n useEffect(() => {\n if (isStateless) return;\n\n if (options?.onMount) {\n options.onMount(bloc as InstanceType<T>);\n }\n\n return () => {\n externalDepsManager.current.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc as InstanceType<T>);\n }\n\n release(BlocClass, instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\n}\n","import { useMemo, useEffect, useRef } from 'preact/hooks';\nimport {\n StateContainerConstructor,\n isIsolatedClass,\n acquire,\n release,\n} from '@blac/core';\nimport type { ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\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 * Preact 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 * **This is the recommended hook for stateless containers** (StatelessCubit, StatelessVertex).\n * It also works with regular Cubit/Vertex when you don't need state subscriptions.\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to (supports both stateful and stateless)\n * @param options - Configuration options for instance management and lifecycle\n * @returns The state container instance for calling actions\n *\n * @example Basic usage with stateless container\n * ```ts\n * class AnalyticsService extends StatelessCubit {\n * trackEvent(name: string) { ... }\n * }\n *\n * const analytics = useBlocActions(AnalyticsService);\n * analytics.trackEvent('page_view');\n * ```\n *\n * @example With stateful container (no re-renders)\n * ```ts\n * const myBloc = useBlocActions(MyBloc);\n * myBloc.someMethod(); // Won't cause re-renders\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 StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: T,\n options?: UseBlocActionsOptions<InstanceType<T>>,\n): 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\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey, {\n props: initialPropsRef.current,\n });\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 release(BlocClass, instanceKey);\n\n if (isIsolatedClass(BlocClass) && !bloc.isDisposed) {\n bloc.dispose();\n }\n };\n }, []);\n\n return bloc as InstanceType<T>;\n}\n"],"mappings":"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"}
{"version":3,"file":"index.cjs","names":["ExternalDepsManager"],"sources":["../src/utils/instance-keys.ts","../src/config.ts","../src/useBloc.ts"],"sourcesContent":["/**\n * Instance key generation utilities for Preact integration\n */\n\nimport { generateIsolatedKey } from '@blac/adapter';\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 - Preact 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","/**\n * Global configuration for @blac/preact\n */\n\nexport interface BlacPreactConfig {\n /** Enable automatic property tracking via Proxy (default: true) */\n autoTrack: boolean;\n}\n\nconst defaultConfig: BlacPreactConfig = {\n autoTrack: true,\n};\n\nlet globalConfig: BlacPreactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/preact hooks.\n *\n * @example\n * ```ts\n * import { configureBlacPreact } from '@blac/preact';\n *\n * // Disable auto-tracking globally\n * configureBlacPreact({\n * autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacPreact(config: Partial<BlacPreactConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacPreactConfig(): BlacPreactConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacPreactConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","import { useMemo, useEffect, useRef, useReducer } from 'preact/hooks';\nimport { useSyncExternalStore } from 'preact/compat';\nimport {\n type ExtractState,\n type AdapterState,\n ExternalDepsManager,\n autoTrackSubscribe,\n manualDepsSubscribe,\n noTrackSubscribe,\n autoTrackSnapshot,\n manualDepsSnapshot,\n noTrackSnapshot,\n autoTrackInit,\n manualDepsInit,\n noTrackInit,\n disableGetterTracking,\n isIsolatedClass,\n type StateContainerConstructor,\n type InstanceState,\n acquire,\n release,\n} from '@blac/adapter';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\nimport { getBlacPreactConfig } from './config';\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n options?: UseBlocOptions<TBloc>,\n): TrackingMode {\n const globalConfig = getBlacPreactConfig();\n const autoTrackEnabled =\n options?.autoTrack !== undefined\n ? options.autoTrack\n : globalConfig.autoTrack;\n\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled,\n };\n}\n\n/**\n * Preact 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 (inferred from BlocClass)\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 StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: T,\n options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n type TBloc = InstanceState<T>;\n\n const componentRef = useRef<ComponentRef>({});\n const isIsolated = isIsolatedClass(BlocClass);\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<T>,\n string | undefined,\n AdapterState<T>,\n TBloc,\n ]\n >(() => {\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey) as TBloc;\n\n const { useManualDeps, autoTrackEnabled } =\n determineTrackingMode(options);\n\n let subscribeFn: (callback: () => void) => () => void;\n let getSnapshotFn: () => ExtractState<T>;\n let adapterState: AdapterState<T>;\n\n if (useManualDeps && options?.dependencies) {\n adapterState = manualDepsInit(instance);\n subscribeFn = manualDepsSubscribe(instance, adapterState, {\n dependencies: options.dependencies,\n });\n getSnapshotFn = manualDepsSnapshot(instance, adapterState, {\n dependencies: options.dependencies,\n });\n } else if (!autoTrackEnabled) {\n adapterState = noTrackInit(instance);\n subscribeFn = noTrackSubscribe(instance);\n getSnapshotFn = noTrackSnapshot(instance);\n } else {\n adapterState = autoTrackInit(instance);\n subscribeFn = autoTrackSubscribe(instance, adapterState);\n getSnapshotFn = autoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc as TBloc,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n }, [BlocClass, isIsolated, 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 ExternalDepsManager());\n\n useEffect(() => {\n disableGetterTracking(adapterState, rawInstance);\n externalDepsManager.current.updateSubscriptions(\n adapterState.getterState,\n rawInstance,\n () => forceUpdate(0),\n );\n });\n\n useEffect(() => {\n if (options?.onMount) {\n options.onMount(bloc as InstanceType<T>);\n }\n\n return () => {\n externalDepsManager.current.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc as InstanceType<T>);\n }\n\n release(BlocClass, instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\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,2DAAwC;AAEvD,SAAO,aAAa;;;;;;AC1BxB,MAAM,gBAAkC,EACtC,WAAW,MACZ;AAED,IAAI,eAAiC,EAAE,GAAG,eAAe;;;;;;;;;;;;;;;;AAiBzD,SAAgB,oBAAoB,QAAyC;AAC3E,gBAAe;EAAE,GAAG;EAAc,GAAG;EAAQ;;;;;;AAO/C,SAAgB,sBAAwC;AACtD,QAAO;;;;;;AAOT,SAAgB,wBAA8B;AAC5C,gBAAe,EAAE,GAAG,eAAe;;;;;AChBrC,SAAS,sBACP,SACc;CACd,MAAM,eAAe,qBAAqB;CAC1C,MAAM,mBACJ,SAAS,cAAc,SACnB,QAAQ,YACR,aAAa;AAEnB,QAAO;EACL,eAAe,SAAS,iBAAiB;EACzC;EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCH,SAAgB,QAGd,WACA,SACmC;CAGnC,MAAM,wCAAoC,EAAE,CAAC;CAC7C,MAAM,gDAA6B,UAAU;CAE7C,MAAM,CAAC,MAAM,WAAW,aAAa,aAAa,cAAc,+CAUtD;EACN,MAAM,cAAc,oBAClB,aAAa,SACb,YACA,SAAS,WACV;EAED,MAAM,sCAAmB,WAAW,YAAY;EAEhD,MAAM,EAAE,eAAe,qBACrB,sBAAsB,QAAQ;EAEhC,IAAI;EACJ,IAAI;EACJ,IAAI;AAEJ,MAAI,iBAAiB,SAAS,cAAc;AAC1C,oDAA8B,SAAS;AACvC,wDAAkC,UAAU,cAAc,EACxD,cAAc,QAAQ,cACvB,CAAC;AACF,yDAAmC,UAAU,cAAc,EACzD,cAAc,QAAQ,cACvB,CAAC;aACO,CAAC,kBAAkB;AAC5B,iDAA2B,SAAS;AACpC,qDAA+B,SAAS;AACxC,sDAAgC,SAAS;SACpC;AACL,mDAA6B,SAAS;AACtC,uDAAiC,UAAU,aAAa;AACxD,wDAAkC,UAAU,aAAa;;AAG3D,SAAO;GACL,aAAa;GACb;GACA;GACA;GACA;GACA;GACD;IACA;EAAC;EAAW;EAAY,SAAS;EAAW,CAAC;CAElD,MAAM,gDAA6B,WAAW,YAAY;CAE1D,MAAM,GAAG,6CAA2B,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,+CAA6B,IAAIA,mCAAqB,CAAC;AAE7D,mCAAgB;AACd,2CAAsB,cAAc,YAAY;AAChD,sBAAoB,QAAQ,oBAC1B,aAAa,aACb,mBACM,YAAY,EAAE,CACrB;GACD;AAEF,mCAAgB;AACd,MAAI,SAAS,QACX,SAAQ,QAAQ,KAAwB;AAG1C,eAAa;AACX,uBAAoB,QAAQ,SAAS;AAErC,OAAI,SAAS,UACX,SAAQ,UAAU,KAAwB;AAG5C,8BAAQ,WAAW,YAAY;AAE/B,OAAI,cAAc,CAAC,YAAY,WAC7B,aAAY,SAAS;;IAGxB,EAAE,CAAC;AAEN,QAAO;EAAC;EAAO;EAAM;EAAa"}

@@ -1,7 +0,7 @@

import type { ExtractProps } from '@blac/core';
import { ExtractState } from '@blac/core';
import type { ExtractState } from '@blac/core';
import { ExtractState as ExtractState_2 } from '@blac/adapter';
import { InstanceReadonlyState } from '@blac/core';
import { IsStatelessContainer } from '@blac/core';
import type { RefObject } from 'preact';
import { StateContainerConstructor } from '@blac/core';
import { StateContainerConstructor } from '@blac/adapter';
import type { StateContainerConstructor as StateContainerConstructor_2 } from '@blac/core';

@@ -38,8 +38,2 @@ /**

/**
* Type that produces a TypeScript error when a stateless container is used.
* Evaluates to `never` for stateless containers, causing a type mismatch.
*/
declare type StatefulContainer<T extends StateContainerConstructor> = IsStatelessContainer<T> extends true ? never : T;
/**
* Preact hook that connects a component to a state container with automatic re-render on state changes.

@@ -52,7 +46,4 @@ *

*
* **Note:** This hook does NOT support stateless containers (StatelessCubit, StatelessVertex).
* Use `useBlocActions()` instead for stateless containers.
*
* @template T - The state container constructor type (inferred from BlocClass)
* @param BlocClass - The state container class to connect to (must not be stateless)
* @param BlocClass - The state container class to connect to
* @param options - Configuration options for tracking mode and instance management

@@ -80,65 +71,9 @@ * @returns Tuple with [state, bloc instance, ref]

*/
export declare function useBloc<T extends StateContainerConstructor = StateContainerConstructor>(BlocClass: StatefulContainer<T>, options?: UseBlocOptions<T>): UseBlocReturn<T, ExtractState<T>>;
export declare function useBloc<T extends StateContainerConstructor = StateContainerConstructor>(BlocClass: T, options?: UseBlocOptions<T>): UseBlocReturn<T, ExtractState_2<T>>;
/**
* Preact hook that connects to a state container instance without triggering re-renders.
* Use this when you only need to call actions on the bloc without subscribing to state changes.
*
* **This is the recommended hook for stateless containers** (StatelessCubit, StatelessVertex).
* It also works with regular Cubit/Vertex when you don't need state subscriptions.
*
* @template T - The state container constructor type (inferred from BlocClass)
* @param BlocClass - The state container class to connect to (supports both stateful and stateless)
* @param options - Configuration options for instance management and lifecycle
* @returns The state container instance for calling actions
*
* @example Basic usage with stateless container
* ```ts
* class AnalyticsService extends StatelessCubit {
* trackEvent(name: string) { ... }
* }
*
* const analytics = useBlocActions(AnalyticsService);
* analytics.trackEvent('page_view');
* ```
*
* @example With stateful container (no re-renders)
* ```ts
* const myBloc = useBlocActions(MyBloc);
* myBloc.someMethod(); // Won't cause re-renders
* ```
*
* @example With isolated instance
* ```ts
* const myBloc = useBlocActions(MyBloc, {
* instanceId: 'unique-id'
* });
* ```
*/
export declare function useBlocActions<T extends StateContainerConstructor = StateContainerConstructor>(BlocClass: T, options?: UseBlocActionsOptions<InstanceType<T>>): InstanceType<T>;
/**
* Configuration options for useBlocActions hook
* @template TBloc - The state container type
* @template TProps - Props type passed to the container
*/
export declare interface UseBlocActionsOptions<TBloc, TProps = any> {
/** Props passed to bloc constructor or updateProps */
props?: TProps;
/** Custom instance identifier for shared or isolated instances */
instanceId?: string | number;
/** Callback invoked when bloc instance mounts */
onMount?: (bloc: TBloc) => void;
/** Callback invoked when bloc instance unmounts */
onUnmount?: (bloc: TBloc) => void;
}
/**
* Configuration options for useBloc hook
* @template TBloc - The state container type
* @template TProps - Props type passed to the container
*/
export declare interface UseBlocOptions<TBloc extends StateContainerConstructor, TProps = ExtractProps<TBloc>> {
/** Props passed to bloc constructor or updateProps */
props?: TProps;
export declare interface UseBlocOptions<TBloc extends StateContainerConstructor_2> {
/** Custom instance identifier for shared or isolated instances */

@@ -166,4 +101,4 @@ instanceId?: string | number;

*/
export declare type UseBlocReturn<TBloc extends StateContainerConstructor, S = ExtractState<TBloc>> = [S, InstanceReadonlyState<TBloc>, RefObject<ComponentRef>];
export declare type UseBlocReturn<TBloc extends StateContainerConstructor_2, S = ExtractState<TBloc>> = [S, InstanceReadonlyState<TBloc>, RefObject<ComponentRef>];
export { }

@@ -1,7 +0,7 @@

import type { ExtractProps } from '@blac/core';
import { ExtractState } from '@blac/core';
import type { ExtractState } from '@blac/core';
import { ExtractState as ExtractState_2 } from '@blac/adapter';
import { InstanceReadonlyState } from '@blac/core';
import { IsStatelessContainer } from '@blac/core';
import type { RefObject } from 'preact';
import { StateContainerConstructor } from '@blac/core';
import { StateContainerConstructor } from '@blac/adapter';
import type { StateContainerConstructor as StateContainerConstructor_2 } from '@blac/core';

@@ -38,8 +38,2 @@ /**

/**
* Type that produces a TypeScript error when a stateless container is used.
* Evaluates to `never` for stateless containers, causing a type mismatch.
*/
declare type StatefulContainer<T extends StateContainerConstructor> = IsStatelessContainer<T> extends true ? never : T;
/**
* Preact hook that connects a component to a state container with automatic re-render on state changes.

@@ -52,7 +46,4 @@ *

*
* **Note:** This hook does NOT support stateless containers (StatelessCubit, StatelessVertex).
* Use `useBlocActions()` instead for stateless containers.
*
* @template T - The state container constructor type (inferred from BlocClass)
* @param BlocClass - The state container class to connect to (must not be stateless)
* @param BlocClass - The state container class to connect to
* @param options - Configuration options for tracking mode and instance management

@@ -80,65 +71,9 @@ * @returns Tuple with [state, bloc instance, ref]

*/
export declare function useBloc<T extends StateContainerConstructor = StateContainerConstructor>(BlocClass: StatefulContainer<T>, options?: UseBlocOptions<T>): UseBlocReturn<T, ExtractState<T>>;
export declare function useBloc<T extends StateContainerConstructor = StateContainerConstructor>(BlocClass: T, options?: UseBlocOptions<T>): UseBlocReturn<T, ExtractState_2<T>>;
/**
* Preact hook that connects to a state container instance without triggering re-renders.
* Use this when you only need to call actions on the bloc without subscribing to state changes.
*
* **This is the recommended hook for stateless containers** (StatelessCubit, StatelessVertex).
* It also works with regular Cubit/Vertex when you don't need state subscriptions.
*
* @template T - The state container constructor type (inferred from BlocClass)
* @param BlocClass - The state container class to connect to (supports both stateful and stateless)
* @param options - Configuration options for instance management and lifecycle
* @returns The state container instance for calling actions
*
* @example Basic usage with stateless container
* ```ts
* class AnalyticsService extends StatelessCubit {
* trackEvent(name: string) { ... }
* }
*
* const analytics = useBlocActions(AnalyticsService);
* analytics.trackEvent('page_view');
* ```
*
* @example With stateful container (no re-renders)
* ```ts
* const myBloc = useBlocActions(MyBloc);
* myBloc.someMethod(); // Won't cause re-renders
* ```
*
* @example With isolated instance
* ```ts
* const myBloc = useBlocActions(MyBloc, {
* instanceId: 'unique-id'
* });
* ```
*/
export declare function useBlocActions<T extends StateContainerConstructor = StateContainerConstructor>(BlocClass: T, options?: UseBlocActionsOptions<InstanceType<T>>): InstanceType<T>;
/**
* Configuration options for useBlocActions hook
* @template TBloc - The state container type
* @template TProps - Props type passed to the container
*/
export declare interface UseBlocActionsOptions<TBloc, TProps = any> {
/** Props passed to bloc constructor or updateProps */
props?: TProps;
/** Custom instance identifier for shared or isolated instances */
instanceId?: string | number;
/** Callback invoked when bloc instance mounts */
onMount?: (bloc: TBloc) => void;
/** Callback invoked when bloc instance unmounts */
onUnmount?: (bloc: TBloc) => void;
}
/**
* Configuration options for useBloc hook
* @template TBloc - The state container type
* @template TProps - Props type passed to the container
*/
export declare interface UseBlocOptions<TBloc extends StateContainerConstructor, TProps = ExtractProps<TBloc>> {
/** Props passed to bloc constructor or updateProps */
props?: TProps;
export declare interface UseBlocOptions<TBloc extends StateContainerConstructor_2> {
/** Custom instance identifier for shared or isolated instances */

@@ -166,4 +101,4 @@ instanceId?: string | number;

*/
export declare type UseBlocReturn<TBloc extends StateContainerConstructor, S = ExtractState<TBloc>> = [S, InstanceReadonlyState<TBloc>, RefObject<ComponentRef>];
export declare type UseBlocReturn<TBloc extends StateContainerConstructor_2, S = ExtractState<TBloc>> = [S, InstanceReadonlyState<TBloc>, RefObject<ComponentRef>];
export { }
import { useEffect, useMemo, useReducer, useRef } from "preact/hooks";
import { useSyncExternalStore } from "preact/compat";
import { ExternalDepsManager, acquire, autoTrackInit, autoTrackSnapshot, autoTrackSubscribe, disableGetterTracking, generateIsolatedKey, isIsolatedClass, isStatelessClass, manualDepsInit, manualDepsSnapshot, manualDepsSubscribe, noTrackInit, noTrackSnapshot, noTrackSubscribe, release } from "@blac/core";
import { ExternalDepsManager, acquire, autoTrackInit, autoTrackSnapshot, autoTrackSubscribe, disableGetterTracking, generateIsolatedKey, isIsolatedClass, manualDepsInit, manualDepsSnapshot, manualDepsSubscribe, noTrackInit, noTrackSnapshot, noTrackSubscribe, release } from "@blac/adapter";

@@ -73,4 +73,4 @@ //#region src/utils/instance-keys.ts

function determineTrackingMode(options) {
const globalConfig$1 = getBlacPreactConfig();
const autoTrackEnabled = options?.autoTrack !== void 0 ? options.autoTrack : globalConfig$1.autoTrack;
const globalConfig = getBlacPreactConfig();
const autoTrackEnabled = options?.autoTrack !== void 0 ? options.autoTrack : globalConfig.autoTrack;
return {

@@ -89,7 +89,4 @@ useManualDeps: options?.dependencies !== void 0,

*
* **Note:** This hook does NOT support stateless containers (StatelessCubit, StatelessVertex).
* Use `useBlocActions()` instead for stateless containers.
*
* @template T - The state container constructor type (inferred from BlocClass)
* @param BlocClass - The state container class to connect to (must not be stateless)
* @param BlocClass - The state container class to connect to
* @param options - Configuration options for tracking mode and instance management

@@ -119,44 +116,29 @@ * @returns Tuple with [state, bloc instance, ref]

const componentRef = useRef({});
const initialPropsRef = useRef(options?.props);
const isStateless = isStatelessClass(BlocClass);
const isIsolated = isIsolatedClass(BlocClass);
const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] = useMemo(() => {
if (isStateless) {
console.error(`[BlaC] useBloc() does not support stateless containers. "${BlocClass.name}" is a StatelessCubit or StatelessVertex. Use useBlocActions() instead for stateless containers.`);
const instance$1 = acquire(BlocClass, "default");
return [
instance$1,
() => () => {},
() => ({}),
void 0,
null,
instance$1
];
}
const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
const instance = acquire(BlocClass, instanceKey$1, { props: initialPropsRef.current });
if (initialPropsRef.current !== void 0) instance.updateProps(initialPropsRef.current);
const instanceKey = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
const instance = acquire(BlocClass, instanceKey);
const { useManualDeps, autoTrackEnabled } = determineTrackingMode(options);
let subscribeFn;
let getSnapshotFn;
let adapterState$1;
let adapterState;
if (useManualDeps && options?.dependencies) {
adapterState$1 = manualDepsInit(instance);
subscribeFn = manualDepsSubscribe(instance, adapterState$1, { dependencies: options.dependencies });
getSnapshotFn = manualDepsSnapshot(instance, adapterState$1, { dependencies: options.dependencies });
adapterState = manualDepsInit(instance);
subscribeFn = manualDepsSubscribe(instance, adapterState, { dependencies: options.dependencies });
getSnapshotFn = manualDepsSnapshot(instance, adapterState, { dependencies: options.dependencies });
} else if (!autoTrackEnabled) {
adapterState$1 = noTrackInit(instance);
adapterState = noTrackInit(instance);
subscribeFn = noTrackSubscribe(instance);
getSnapshotFn = noTrackSnapshot(instance);
} else {
adapterState$1 = autoTrackInit(instance);
subscribeFn = autoTrackSubscribe(instance, adapterState$1);
getSnapshotFn = autoTrackSnapshot(instance, adapterState$1);
adapterState = autoTrackInit(instance);
subscribeFn = autoTrackSubscribe(instance, adapterState);
getSnapshotFn = autoTrackSnapshot(instance, adapterState);
}
return [
adapterState$1.proxiedBloc,
adapterState.proxiedBloc,
subscribeFn,
getSnapshotFn,
instanceKey$1,
adapterState$1,
instanceKey,
adapterState,
instance

@@ -166,3 +148,2 @@ ];

BlocClass,
isStateless,
isIsolated,

@@ -175,11 +156,2 @@ options?.instanceId

useEffect(() => {
if (isStateless) return;
if (options?.props !== initialPropsRef.current) rawInstance.updateProps(options?.props);
}, [
options?.props,
rawInstance,
isStateless
]);
useEffect(() => {
if (isStateless || !adapterState) return;
disableGetterTracking(adapterState, rawInstance);

@@ -189,3 +161,2 @@ externalDepsManager.current.updateSubscriptions(adapterState.getterState, rawInstance, () => forceUpdate(0));

useEffect(() => {
if (isStateless) return;
if (options?.onMount) options.onMount(bloc);

@@ -207,59 +178,3 @@ return () => {

//#endregion
//#region src/useBlocActions.ts
/**
* Preact hook that connects to a state container instance without triggering re-renders.
* Use this when you only need to call actions on the bloc without subscribing to state changes.
*
* **This is the recommended hook for stateless containers** (StatelessCubit, StatelessVertex).
* It also works with regular Cubit/Vertex when you don't need state subscriptions.
*
* @template T - The state container constructor type (inferred from BlocClass)
* @param BlocClass - The state container class to connect to (supports both stateful and stateless)
* @param options - Configuration options for instance management and lifecycle
* @returns The state container instance for calling actions
*
* @example Basic usage with stateless container
* ```ts
* class AnalyticsService extends StatelessCubit {
* trackEvent(name: string) { ... }
* }
*
* const analytics = useBlocActions(AnalyticsService);
* analytics.trackEvent('page_view');
* ```
*
* @example With stateful container (no re-renders)
* ```ts
* const myBloc = useBlocActions(MyBloc);
* myBloc.someMethod(); // Won't cause re-renders
* ```
*
* @example With isolated instance
* ```ts
* const myBloc = useBlocActions(MyBloc, {
* instanceId: 'unique-id'
* });
* ```
*/
function useBlocActions(BlocClass, options) {
const componentRef = useRef({});
const initialPropsRef = useRef(options?.props);
const [bloc, instanceKey] = useMemo(() => {
const isIsolated = isIsolatedClass(BlocClass);
const instanceKey$1 = generateInstanceKey(componentRef.current, isIsolated, options?.instanceId);
return [acquire(BlocClass, instanceKey$1, { props: initialPropsRef.current }), instanceKey$1];
}, [BlocClass]);
useEffect(() => {
if (options?.onMount) options.onMount(bloc);
return () => {
if (options?.onUnmount) options.onUnmount(bloc);
release(BlocClass, instanceKey);
if (isIsolatedClass(BlocClass) && !bloc.isDisposed) bloc.dispose();
};
}, []);
return bloc;
}
//#endregion
export { configureBlacPreact, resetBlacPreactConfig, useBloc, useBlocActions };
export { configureBlacPreact, resetBlacPreactConfig, useBloc };
//# sourceMappingURL=index.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","names":["globalConfig","instance","instanceKey","adapterState","instanceKey"],"sources":["../src/utils/instance-keys.ts","../src/config.ts","../src/useBloc.ts","../src/useBlocActions.ts"],"sourcesContent":["/**\n * Instance key generation utilities for Preact 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 - Preact 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","/**\n * Global configuration for @blac/preact\n */\n\nexport interface BlacPreactConfig {\n /** Enable automatic property tracking via Proxy (default: true) */\n autoTrack: boolean;\n}\n\nconst defaultConfig: BlacPreactConfig = {\n autoTrack: true,\n};\n\nlet globalConfig: BlacPreactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/preact hooks.\n *\n * @example\n * ```ts\n * import { configureBlacPreact } from '@blac/preact';\n *\n * // Disable auto-tracking globally\n * configureBlacPreact({\n * autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacPreact(config: Partial<BlacPreactConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacPreactConfig(): BlacPreactConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacPreactConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","import { useMemo, useEffect, useRef, useReducer } from 'preact/hooks';\nimport { useSyncExternalStore } from 'preact/compat';\nimport {\n type ExtractState,\n type AdapterState,\n type IsStatelessContainer,\n ExternalDepsManager,\n autoTrackSubscribe,\n manualDepsSubscribe,\n noTrackSubscribe,\n autoTrackSnapshot,\n manualDepsSnapshot,\n noTrackSnapshot,\n autoTrackInit,\n manualDepsInit,\n noTrackInit,\n disableGetterTracking,\n isIsolatedClass,\n isStatelessClass,\n StateContainerConstructor,\n InstanceState,\n acquire,\n release,\n} from '@blac/core';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\nimport { getBlacPreactConfig } from './config';\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n options?: UseBlocOptions<TBloc>,\n): TrackingMode {\n const globalConfig = getBlacPreactConfig();\n const autoTrackEnabled =\n options?.autoTrack !== undefined\n ? options.autoTrack\n : globalConfig.autoTrack;\n\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled,\n };\n}\n\n/**\n * Type that produces a TypeScript error when a stateless container is used.\n * Evaluates to `never` for stateless containers, causing a type mismatch.\n */\ntype StatefulContainer<T extends StateContainerConstructor> =\n IsStatelessContainer<T> extends true ? never : T;\n\n/**\n * Preact 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 * **Note:** This hook does NOT support stateless containers (StatelessCubit, StatelessVertex).\n * Use `useBlocActions()` instead for stateless containers.\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to (must not be stateless)\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 StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: StatefulContainer<T>,\n options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n type TBloc = InstanceState<T>;\n\n const componentRef = useRef<ComponentRef>({});\n const initialPropsRef = useRef(options?.props);\n const isStateless = isStatelessClass(BlocClass);\n const isIsolated = isIsolatedClass(BlocClass);\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<T>,\n string | undefined,\n AdapterState<T> | null,\n TBloc,\n ]\n >(() => {\n // Runtime check for stateless containers - log error but don't crash\n if (isStateless) {\n console.error(\n `[BlaC] useBloc() does not support stateless containers. ` +\n `\"${BlocClass.name}\" is a StatelessCubit or StatelessVertex. ` +\n `Use useBlocActions() instead for stateless containers.`,\n );\n const instance = acquire(BlocClass, 'default') as TBloc;\n // Return minimal working functions that won't subscribe to anything\n return [\n instance,\n () => () => {},\n () => ({}) as ExtractState<T>,\n undefined,\n null,\n instance,\n ];\n }\n\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey, {\n props: initialPropsRef.current,\n }) as TBloc;\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<T>;\n let adapterState: AdapterState<T>;\n\n if (useManualDeps && options?.dependencies) {\n adapterState = manualDepsInit(instance);\n subscribeFn = manualDepsSubscribe(instance, adapterState, {\n dependencies: options.dependencies,\n });\n getSnapshotFn = manualDepsSnapshot(instance, adapterState, {\n dependencies: options.dependencies,\n });\n } else if (!autoTrackEnabled) {\n adapterState = noTrackInit(instance);\n subscribeFn = noTrackSubscribe(instance);\n getSnapshotFn = noTrackSnapshot(instance);\n } else {\n adapterState = autoTrackInit(instance);\n subscribeFn = autoTrackSubscribe(instance, adapterState);\n getSnapshotFn = autoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc as TBloc,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n }, [BlocClass, isStateless, isIsolated, 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 ExternalDepsManager());\n\n useEffect(() => {\n if (isStateless) return;\n if (options?.props !== initialPropsRef.current) {\n rawInstance.updateProps(options?.props);\n }\n }, [options?.props, rawInstance, isStateless]);\n\n useEffect(() => {\n if (isStateless || !adapterState) return;\n disableGetterTracking(adapterState, rawInstance);\n externalDepsManager.current.updateSubscriptions(\n adapterState.getterState,\n rawInstance,\n () => forceUpdate(0),\n );\n });\n\n useEffect(() => {\n if (isStateless) return;\n\n if (options?.onMount) {\n options.onMount(bloc as InstanceType<T>);\n }\n\n return () => {\n externalDepsManager.current.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc as InstanceType<T>);\n }\n\n release(BlocClass, instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\n}\n","import { useMemo, useEffect, useRef } from 'preact/hooks';\nimport {\n StateContainerConstructor,\n isIsolatedClass,\n acquire,\n release,\n} from '@blac/core';\nimport type { ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\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 * Preact 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 * **This is the recommended hook for stateless containers** (StatelessCubit, StatelessVertex).\n * It also works with regular Cubit/Vertex when you don't need state subscriptions.\n *\n * @template T - The state container constructor type (inferred from BlocClass)\n * @param BlocClass - The state container class to connect to (supports both stateful and stateless)\n * @param options - Configuration options for instance management and lifecycle\n * @returns The state container instance for calling actions\n *\n * @example Basic usage with stateless container\n * ```ts\n * class AnalyticsService extends StatelessCubit {\n * trackEvent(name: string) { ... }\n * }\n *\n * const analytics = useBlocActions(AnalyticsService);\n * analytics.trackEvent('page_view');\n * ```\n *\n * @example With stateful container (no re-renders)\n * ```ts\n * const myBloc = useBlocActions(MyBloc);\n * myBloc.someMethod(); // Won't cause re-renders\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 StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: T,\n options?: UseBlocActionsOptions<InstanceType<T>>,\n): 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\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey, {\n props: initialPropsRef.current,\n });\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 release(BlocClass, instanceKey);\n\n if (isIsolatedClass(BlocClass) && !bloc.isDisposed) {\n bloc.dispose();\n }\n };\n }, []);\n\n return bloc as InstanceType<T>;\n}\n"],"mappings":"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"}
{"version":3,"file":"index.js","names":[],"sources":["../src/utils/instance-keys.ts","../src/config.ts","../src/useBloc.ts"],"sourcesContent":["/**\n * Instance key generation utilities for Preact integration\n */\n\nimport { generateIsolatedKey } from '@blac/adapter';\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 - Preact 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","/**\n * Global configuration for @blac/preact\n */\n\nexport interface BlacPreactConfig {\n /** Enable automatic property tracking via Proxy (default: true) */\n autoTrack: boolean;\n}\n\nconst defaultConfig: BlacPreactConfig = {\n autoTrack: true,\n};\n\nlet globalConfig: BlacPreactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/preact hooks.\n *\n * @example\n * ```ts\n * import { configureBlacPreact } from '@blac/preact';\n *\n * // Disable auto-tracking globally\n * configureBlacPreact({\n * autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacPreact(config: Partial<BlacPreactConfig>): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacPreactConfig(): BlacPreactConfig {\n return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacPreactConfig(): void {\n globalConfig = { ...defaultConfig };\n}\n","import { useMemo, useEffect, useRef, useReducer } from 'preact/hooks';\nimport { useSyncExternalStore } from 'preact/compat';\nimport {\n type ExtractState,\n type AdapterState,\n ExternalDepsManager,\n autoTrackSubscribe,\n manualDepsSubscribe,\n noTrackSubscribe,\n autoTrackSnapshot,\n manualDepsSnapshot,\n noTrackSnapshot,\n autoTrackInit,\n manualDepsInit,\n noTrackInit,\n disableGetterTracking,\n isIsolatedClass,\n type StateContainerConstructor,\n type InstanceState,\n acquire,\n release,\n} from '@blac/adapter';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { generateInstanceKey } from './utils/instance-keys';\nimport { getBlacPreactConfig } from './config';\n\ninterface TrackingMode {\n useManualDeps: boolean;\n autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n options?: UseBlocOptions<TBloc>,\n): TrackingMode {\n const globalConfig = getBlacPreactConfig();\n const autoTrackEnabled =\n options?.autoTrack !== undefined\n ? options.autoTrack\n : globalConfig.autoTrack;\n\n return {\n useManualDeps: options?.dependencies !== undefined,\n autoTrackEnabled,\n };\n}\n\n/**\n * Preact 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 (inferred from BlocClass)\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 StateContainerConstructor = StateContainerConstructor,\n>(\n BlocClass: T,\n options?: UseBlocOptions<T>,\n): UseBlocReturn<T, ExtractState<T>> {\n type TBloc = InstanceState<T>;\n\n const componentRef = useRef<ComponentRef>({});\n const isIsolated = isIsolatedClass(BlocClass);\n\n const [bloc, subscribe, getSnapshot, instanceKey, adapterState, rawInstance] =\n useMemo<\n readonly [\n TBloc,\n (callback: () => void) => () => void,\n () => ExtractState<T>,\n string | undefined,\n AdapterState<T>,\n TBloc,\n ]\n >(() => {\n const instanceKey = generateInstanceKey(\n componentRef.current,\n isIsolated,\n options?.instanceId,\n );\n\n const instance = acquire(BlocClass, instanceKey) as TBloc;\n\n const { useManualDeps, autoTrackEnabled } =\n determineTrackingMode(options);\n\n let subscribeFn: (callback: () => void) => () => void;\n let getSnapshotFn: () => ExtractState<T>;\n let adapterState: AdapterState<T>;\n\n if (useManualDeps && options?.dependencies) {\n adapterState = manualDepsInit(instance);\n subscribeFn = manualDepsSubscribe(instance, adapterState, {\n dependencies: options.dependencies,\n });\n getSnapshotFn = manualDepsSnapshot(instance, adapterState, {\n dependencies: options.dependencies,\n });\n } else if (!autoTrackEnabled) {\n adapterState = noTrackInit(instance);\n subscribeFn = noTrackSubscribe(instance);\n getSnapshotFn = noTrackSnapshot(instance);\n } else {\n adapterState = autoTrackInit(instance);\n subscribeFn = autoTrackSubscribe(instance, adapterState);\n getSnapshotFn = autoTrackSnapshot(instance, adapterState);\n }\n\n return [\n adapterState.proxiedBloc as TBloc,\n subscribeFn,\n getSnapshotFn,\n instanceKey,\n adapterState,\n instance,\n ];\n }, [BlocClass, isIsolated, 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 ExternalDepsManager());\n\n useEffect(() => {\n disableGetterTracking(adapterState, rawInstance);\n externalDepsManager.current.updateSubscriptions(\n adapterState.getterState,\n rawInstance,\n () => forceUpdate(0),\n );\n });\n\n useEffect(() => {\n if (options?.onMount) {\n options.onMount(bloc as InstanceType<T>);\n }\n\n return () => {\n externalDepsManager.current.cleanup();\n\n if (options?.onUnmount) {\n options.onUnmount(bloc as InstanceType<T>);\n }\n\n release(BlocClass, instanceKey);\n\n if (isIsolated && !rawInstance.isDisposed) {\n rawInstance.dispose();\n }\n };\n }, []);\n\n return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\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;;;;;;AC1BxB,MAAM,gBAAkC,EACtC,WAAW,MACZ;AAED,IAAI,eAAiC,EAAE,GAAG,eAAe;;;;;;;;;;;;;;;;AAiBzD,SAAgB,oBAAoB,QAAyC;AAC3E,gBAAe;EAAE,GAAG;EAAc,GAAG;EAAQ;;;;;;AAO/C,SAAgB,sBAAwC;AACtD,QAAO;;;;;;AAOT,SAAgB,wBAA8B;AAC5C,gBAAe,EAAE,GAAG,eAAe;;;;;AChBrC,SAAS,sBACP,SACc;CACd,MAAM,eAAe,qBAAqB;CAC1C,MAAM,mBACJ,SAAS,cAAc,SACnB,QAAQ,YACR,aAAa;AAEnB,QAAO;EACL,eAAe,SAAS,iBAAiB;EACzC;EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCH,SAAgB,QAGd,WACA,SACmC;CAGnC,MAAM,eAAe,OAAqB,EAAE,CAAC;CAC7C,MAAM,aAAa,gBAAgB,UAAU;CAE7C,MAAM,CAAC,MAAM,WAAW,aAAa,aAAa,cAAc,eAC9D,cASQ;EACN,MAAM,cAAc,oBAClB,aAAa,SACb,YACA,SAAS,WACV;EAED,MAAM,WAAW,QAAQ,WAAW,YAAY;EAEhD,MAAM,EAAE,eAAe,qBACrB,sBAAsB,QAAQ;EAEhC,IAAI;EACJ,IAAI;EACJ,IAAI;AAEJ,MAAI,iBAAiB,SAAS,cAAc;AAC1C,kBAAe,eAAe,SAAS;AACvC,iBAAc,oBAAoB,UAAU,cAAc,EACxD,cAAc,QAAQ,cACvB,CAAC;AACF,mBAAgB,mBAAmB,UAAU,cAAc,EACzD,cAAc,QAAQ,cACvB,CAAC;aACO,CAAC,kBAAkB;AAC5B,kBAAe,YAAY,SAAS;AACpC,iBAAc,iBAAiB,SAAS;AACxC,mBAAgB,gBAAgB,SAAS;SACpC;AACL,kBAAe,cAAc,SAAS;AACtC,iBAAc,mBAAmB,UAAU,aAAa;AACxD,mBAAgB,kBAAkB,UAAU,aAAa;;AAG3D,SAAO;GACL,aAAa;GACb;GACA;GACA;GACA;GACA;GACD;IACA;EAAC;EAAW;EAAY,SAAS;EAAW,CAAC;CAElD,MAAM,QAAQ,qBAAqB,WAAW,YAAY;CAE1D,MAAM,GAAG,eAAe,YAAY,MAAc,IAAI,GAAG,EAAE;CAE3D,MAAM,sBAAsB,OAAO,IAAI,qBAAqB,CAAC;AAE7D,iBAAgB;AACd,wBAAsB,cAAc,YAAY;AAChD,sBAAoB,QAAQ,oBAC1B,aAAa,aACb,mBACM,YAAY,EAAE,CACrB;GACD;AAEF,iBAAgB;AACd,MAAI,SAAS,QACX,SAAQ,QAAQ,KAAwB;AAG1C,eAAa;AACX,uBAAoB,QAAQ,SAAS;AAErC,OAAI,SAAS,UACX,SAAQ,UAAU,KAAwB;AAG5C,WAAQ,WAAW,YAAY;AAE/B,OAAI,cAAc,CAAC,YAAY,WAC7B,aAAY,SAAS;;IAGxB,EAAE,CAAC;AAEN,QAAO;EAAC;EAAO;EAAM;EAAa"}
{
"name": "@blac/preact",
"version": "2.0.2",
"version": "2.0.3",
"license": "MIT",

@@ -49,5 +49,7 @@ "author": "Brendan Mullins <jsnanigans@gmail.com>",

],
"dependencies": {
"@blac/adapter": "2.0.3"
},
"peerDependencies": {
"preact": "^10.17.0",
"@blac/core": "2.0.1"
"preact": "^10.17.0"
},

@@ -68,3 +70,3 @@ "devDependencies": {

"vitest": "3.2.4",
"@blac/core": "2.0.1"
"@blac/core": "2.0.3"
},

@@ -71,0 +73,0 @@ "scripts": {