{"version":3,"file":"index.cjs","names":["React","ExternalDepsManager"],"sources":["../src/BlocProvider.tsx","../src/config.ts","../src/useBloc.ts"],"sourcesContent":["import {\n  createContext,\n  useContext,\n  type ReactElement,\n  type ReactNode,\n} from 'react';\n\nconst InstanceIdContext = createContext<string | undefined>(undefined);\n\n/**\n * Props for {@link BlocProvider}.\n */\nexport interface BlocProviderProps {\n  /**\n   * Instance id that descendants' `useBloc(C)` calls will resolve to when no\n   * explicit `instanceId` is given.\n   */\n  instanceId: string | number;\n  children: ReactNode;\n}\n\n/**\n * Provides an `instanceId` to descendant `useBloc` calls via React context.\n *\n * Descendants calling `useBloc(C)` without an `instanceId` resolve to the id\n * supplied here. An explicit `instanceId` on the `useBloc` call still wins.\n * `autoInstance` / `static isolated = true` also override the context, because\n * those force a per-mount auto-key.\n *\n * @example\n * ```tsx\n * <BlocProvider instanceId=\"customer-42\">\n *   <CustomerView />\n * </BlocProvider>\n * ```\n */\nexport function BlocProvider({\n  instanceId,\n  children,\n}: BlocProviderProps): ReactElement {\n  return (\n    <InstanceIdContext.Provider value={String(instanceId)}>\n      {children}\n    </InstanceIdContext.Provider>\n  );\n}\n\n/**\n * Reads the nearest {@link BlocProvider} instance id, or `undefined` when\n * called outside a provider.\n */\nexport function useInstanceIdFromContext(): string | undefined {\n  return useContext(InstanceIdContext);\n}\n","/**\n * Global configuration for @blac/react\n */\n\nexport interface BlacReactConfig {\n  /** Enable automatic property tracking via Proxy (default: true) */\n  autoTrack: boolean;\n}\n\nconst defaultConfig: BlacReactConfig = {\n  autoTrack: true,\n};\n\nlet globalConfig: BlacReactConfig = { ...defaultConfig };\n\n/**\n * Configure global defaults for @blac/react hooks.\n *\n * @example\n * ```ts\n * import { configureBlacReact } from '@blac/react';\n *\n * // Disable auto-tracking globally\n * configureBlacReact({\n *   autoTrack: false\n * });\n * ```\n *\n * @param config - Partial configuration to merge with defaults\n */\nexport function configureBlacReact(config: Partial<BlacReactConfig>): void {\n  globalConfig = { ...globalConfig, ...config };\n}\n\n/**\n * Get the current global configuration.\n * @internal\n */\nexport function getBlacReactConfig(): BlacReactConfig {\n  return globalConfig;\n}\n\n/**\n * Reset configuration to defaults (useful for testing).\n * @internal\n */\nexport function resetBlacReactConfig(): void {\n  globalConfig = { ...defaultConfig };\n}\n","import React, {\n  useMemo,\n  useSyncExternalStore,\n  useEffect,\n  useRef,\n  useReducer,\n} from 'react';\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  type StateContainerConstructor,\n  type InstanceState,\n  acquire,\n  release,\n} from '@blac/adapter';\nimport { isIsolatedClass } from '@blac/core';\nimport { useInstanceIdFromContext } from './BlocProvider';\nimport type { UseBlocOptions, UseBlocReturn, ComponentRef } from './types';\nimport { getBlacReactConfig } from './config';\n\nlet nextConsumerId = 0;\n\nfunction getComponentName(): string | undefined {\n  try {\n    const internals =\n      (React as any)\n        .__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE ??\n      (React as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;\n    const owner = internals?.ReactCurrentOwner?.current;\n    if (owner?.type) {\n      return owner.type.displayName || owner.type.name || undefined;\n    }\n  } catch {\n    // ignore — React internals may not be available\n  }\n  return undefined;\n}\n\ninterface TrackingMode {\n  useManualDeps: boolean;\n  autoTrackEnabled: boolean;\n}\n\nfunction determineTrackingMode<TBloc extends StateContainerConstructor>(\n  options?: Pick<UseBlocOptions<TBloc>, 'autoTrack' | 'dependencies'>,\n): TrackingMode {\n  const globalConfig = getBlacReactConfig();\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 * 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 (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 named 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\n  // Capture component name from React fiber during render (for devtools consumer tracking)\n  const consumerIdRef = useRef<string | null>(null);\n  if (consumerIdRef.current === null) {\n    consumerIdRef.current = String(nextConsumerId++);\n  }\n  const componentNameRef = useRef<string | null>(null);\n  if (componentNameRef.current === null) {\n    componentNameRef.current = getComponentName() || null;\n  }\n\n  const depsRef = useRef(options?.dependencies);\n  depsRef.current = options?.dependencies;\n  const onMountRef = useRef(options?.onMount);\n  onMountRef.current = options?.onMount;\n  const onUnmountRef = useRef(options?.onUnmount);\n  onUnmountRef.current = options?.onUnmount;\n  const instanceId = options?.instanceId;\n  const autoTrack = options?.autoTrack;\n  const dependencies = options?.dependencies;\n\n  // Auto-keyed per-mount instance: either declared on the class\n  // (`static isolated = true`) or opted into per call (`autoInstance: true`).\n  // `useId()` is always called to satisfy the rules of hooks.\n  const autoInstanceId = React.useId();\n  const autoInstance =\n    options?.autoInstance === true || isIsolatedClass(BlocClass);\n  // Resolve `instanceId` from a surrounding <BlocProvider> when not given\n  // explicitly and not auto-keyed.\n  const ctxInstanceId = useInstanceIdFromContext();\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 =\n        instanceId !== undefined\n          ? String(instanceId)\n          : autoInstance\n            ? autoInstanceId\n            : ctxInstanceId;\n\n      const refId = `useBloc@${componentNameRef.current ?? 'Unknown'}-${consumerIdRef.current}`;\n      const instance = acquire(BlocClass, instanceKey, refId) as TBloc;\n\n      const { useManualDeps, autoTrackEnabled } = determineTrackingMode({\n        autoTrack,\n        dependencies,\n      });\n\n      let subscribeFn: (callback: () => void) => () => void;\n      let getSnapshotFn: () => ExtractState<T>;\n      let adapterState: AdapterState<T>;\n\n      if (useManualDeps && dependencies) {\n        adapterState = manualDepsInit(instance);\n        const stableConfig = {\n          dependencies: (state: ExtractState<T>, bloc: InstanceState<T>) => {\n            const deps = depsRef.current;\n            return deps ? deps(state, bloc) : [];\n          },\n        };\n        subscribeFn = manualDepsSubscribe(instance, adapterState, stableConfig);\n        getSnapshotFn = manualDepsSnapshot(\n          instance,\n          adapterState,\n          stableConfig,\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      // oxlint-disable-next-line react-hooks/exhaustive-deps\n    }, [BlocClass, instanceId, autoInstance, autoInstanceId, ctxInstanceId]);\n\n  const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n  const [, forceUpdate] = useReducer((x: number) => x + 1, 0);\n\n  const externalDepsManager = useRef<ExternalDepsManager>(null);\n  if (externalDepsManager.current === null) {\n    (\n      externalDepsManager as React.MutableRefObject<ExternalDepsManager>\n    ).current = new ExternalDepsManager();\n  }\n\n  useEffect(() => {\n    const manager = externalDepsManager.current!;\n    disableGetterTracking(adapterState, rawInstance);\n    manager.updateSubscriptions(\n      adapterState.getterState,\n      rawInstance,\n      forceUpdate,\n    );\n  }, [adapterState, rawInstance, forceUpdate]);\n\n  useEffect(() => {\n    const manager = externalDepsManager.current!;\n    const currentInstanceKey = instanceKey;\n    const currentRawInstance = rawInstance;\n    const currentBloc = bloc;\n\n    // Register as consumer in devtools (if available)\n    const devtools =\n      typeof window !== 'undefined'\n        ? (window as any).__BLAC_DEVTOOLS__\n        : undefined;\n    if (devtools?.registerConsumer && currentRawInstance) {\n      devtools.registerConsumer(\n        (currentRawInstance as any).instanceId,\n        consumerIdRef.current,\n        componentNameRef.current || 'Unknown',\n      );\n    }\n\n    onMountRef.current?.(currentBloc as InstanceType<T>);\n\n    return () => {\n      if (devtools?.unregisterConsumer && currentRawInstance) {\n        devtools.unregisterConsumer(\n          (currentRawInstance as any).instanceId,\n          consumerIdRef.current,\n        );\n      }\n\n      manager.cleanup();\n\n      onUnmountRef.current?.(currentBloc as InstanceType<T>);\n\n      const refId = `useBloc@${componentNameRef.current ?? 'Unknown'}-${consumerIdRef.current}`;\n      release(BlocClass, currentInstanceKey, false, refId);\n    };\n    // oxlint-disable-next-line react-hooks/exhaustive-deps\n  }, [bloc, instanceKey, rawInstance]);\n\n  return [state, bloc, componentRef] as UseBlocReturn<T, ExtractState<T>>;\n}\n"],"mappings":"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"}