{"version":3,"file":"tracking.cjs","sources":["../../../src/lib/tracking.ts"],"sourcesContent":["\"use client\";\n\nimport { effect, Signal } from \"@preact/signals-core\";\nimport { useRef, version } from \"react\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\n\nconst ReactElemType = Symbol.for(\n  parseInt(version) >= 19 ? \"react.transitional.element\" : \"react.element\",\n); // https://github.com/facebook/react/blob/346c7d4c43a0717302d446da9e7423a8e28d8996/packages/shared/ReactSymbols.js#L15\n\nconst symDispose: unique symbol =\n  (Symbol as any).dispose || Symbol.for(\"Symbol.dispose\");\n\n// this is effect before mangling, since we are not in preact signals repo, we should use mangled props\n// interface Effect {\n//   _sources: object | undefined;\n//   _start(): () => void;\n//   _callback(): void;\n//   _dispose(): void;\n// }\nconst enum EffectFields {\n  startTracking = \"S\",\n  onDepsChange = \"c\",\n  dispose = \"d\",\n}\ninterface Effect {\n  [EffectFields.startTracking](): () => void;\n  [EffectFields.onDepsChange](): void;\n  [EffectFields.dispose](): void;\n}\n\nconst enum EffectStoreFields {\n  startTracking = \"s\",\n  finishTracking = \"f\",\n  resetSyncRerenders = \"r\",\n}\n\nexport interface EffectStore {\n  effect: Effect;\n  subscribe(onStoreChange: () => void): () => void;\n  getSnapshot(): number;\n  /** finishEffect - stop tracking the signals used in this component */\n  [EffectStoreFields.finishTracking](): void;\n  [EffectStoreFields.startTracking](): void;\n  [EffectStoreFields.resetSyncRerenders](): void;\n\n  [symDispose](): void;\n}\n\nconst _queueMicrotask = Promise.prototype.then.bind(Promise.resolve());\nconst resetSyncRerendersSet = new Set<EffectStore>();\nlet isResetSyncRerendersScheduled = false;\nconst resetSyncRerenders = () => {\n  isResetSyncRerendersScheduled = false;\n  resetSyncRerendersSet.forEach((store) => {\n    store[EffectStoreFields.resetSyncRerenders]();\n  });\n  resetSyncRerendersSet.clear();\n};\nconst scheduleResetSyncRerenders = (store: EffectStore) => {\n  if (!isResetSyncRerendersScheduled) {\n    isResetSyncRerendersScheduled = true;\n    void _queueMicrotask(resetSyncRerenders);\n  }\n  if (!resetSyncRerendersSet.has(store)) {\n    resetSyncRerendersSet.add(store);\n  }\n};\n\nlet useSignalsDepth = 0;\nlet cleanUpFn: (() => void) | undefined = undefined;\nconst maxSyncRerenders = 25;\n/**\n * A redux-like store whose store value is a positive 32bit integer (a 'version').\n *\n * React subscribes to this store and gets a snapshot of the current 'version',\n * whenever the 'version' changes, we tell React it's time to update the component (call 'onStoreChange').\n *\n * How we achieve this is by creating a binding with an 'effect', when the `effect._callback' is called,\n * we update our store version and tell React to re-render the component ([1] We don't really care when/how React does it).\n *\n * [1]\n * @see https://react.dev/reference/react/useSyncExternalStore\n * @see https://github.com/reactjs/rfcs/blob/main/text/0214-use-sync-external-store.md\n */\nfunction createEffectStore(): EffectStore {\n  let effectInstance!: Effect;\n  let version = 0;\n  let onChangeNotifyReact: (() => void) | undefined;\n\n  let unsubscribe = effect(function (this: Effect) {\n    effectInstance = this;\n  });\n  let inRender = false;\n  let syncRerendersCount = 0;\n  effectInstance[EffectFields.onDepsChange] = function () {\n    if (inRender) {\n      return;\n    }\n    if (syncRerendersCount > maxSyncRerenders) {\n      throw new Error(\n        `preact-signals: Too many sync rerenders (${syncRerendersCount}), you might change parent component signal dependencies in render of child component.`,\n      );\n    }\n    version = (version + 1) | 0;\n    if (!onChangeNotifyReact) {\n      return;\n    }\n\n    // react throws here sometimes\n    onChangeNotifyReact();\n  };\n\n  return {\n    effect: effectInstance,\n    subscribe(onStoreChange) {\n      onChangeNotifyReact = onStoreChange;\n\n      return function () {\n        /**\n         * Rotate to next version when unsubscribing to ensure that components are re-run\n         * when subscribing again.\n         *\n         * In StrictMode, 'memo'-ed components seem to keep a stale snapshot version, so\n         * don't re-run after subscribing again if the version is the same as last time.\n         *\n         * Because we unsubscribe from the effect, the version may not change. We simply\n         * set a new initial version in case of stale snapshots here.\n         */\n        version = (version + 1) | 0;\n        onChangeNotifyReact = undefined;\n        unsubscribe();\n      };\n    },\n    [EffectStoreFields.resetSyncRerenders]() {\n      syncRerendersCount = 0;\n    },\n    [EffectStoreFields.startTracking]() {\n      inRender = true;\n      syncRerendersCount++;\n      scheduleResetSyncRerenders(this);\n      if (!useSignalsDepth && cleanUpFn) {\n        throw new Error(\"cleanUpFn should be undefined\");\n      }\n      if (useSignalsDepth && !cleanUpFn) {\n        throw new Error(\"cleanUpFn should be defined with depth\");\n      }\n      if (!useSignalsDepth) {\n        cleanUpFn = effectInstance[EffectFields.startTracking]();\n      }\n      useSignalsDepth++;\n    },\n    getSnapshot() {\n      return version;\n    },\n    [EffectStoreFields.finishTracking]() {\n      if (useSignalsDepth < 1) {\n        throw new Error(\"useSignalsDepth should be non-negative\");\n      }\n      try {\n        if (useSignalsDepth === 1 && !cleanUpFn) {\n          throw new Error(\"cleanUpFn should be defined with depth\");\n        }\n        if (useSignalsDepth === 1 && cleanUpFn) {\n          try {\n            cleanUpFn();\n          } finally {\n            inRender = false;\n            cleanUpFn = undefined;\n          }\n        }\n      } finally {\n        useSignalsDepth--;\n      }\n    },\n    [symDispose]() {\n      this[EffectStoreFields.finishTracking]();\n    },\n  };\n}\n\n/**\n * @description this hook is for `@preact/signals-react-transform`. You should not use it until you know what you do. If s.f() is not called - reactivity will break\n * @example\n * ```tsx\n * const Component = () => {\n *  const s = useSignals()\n *  try {\n *    // reading signals and using hooks here\n *    const counter = useSignal(0)\n *\n *    return (\n *      <button onClick={() => counter.value++}>Click here: {counter.value * 2}</button>\n *    )\n *  } finally {\n *    s.f()\n *  }\n * }\n * ```\n * Custom hook to create the effect to track signals used during render and\n * subscribe to changes to rerender the component when the signals change.\n */\nexport function useSignals(): EffectStore {\n  // console.log('useSignals')\n  const storeRef = useRef<EffectStore>();\n  if (storeRef.current == null) {\n    storeRef.current = createEffectStore();\n  }\n  const store = storeRef.current;\n  useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n\n  store[EffectStoreFields.startTracking]();\n  return store;\n}\n\n/**\n * A wrapper component that renders a Signal's value directly as a Text node or JSX.\n */\nfunction SignalValue(props: { data: Signal }) {\n  const effectStore = useSignals();\n  try {\n    return props.data.value;\n  } finally {\n    effectStore[EffectStoreFields.finishTracking]();\n  }\n}\n\n// Decorate Signals so React renders them as <SignalValue> components.\nObject.defineProperties(Signal.prototype, {\n  $$typeof: { configurable: true, value: ReactElemType },\n  type: { configurable: true, value: SignalValue },\n  props: {\n    configurable: true,\n    get() {\n      return { data: this };\n    },\n  },\n  ref: { configurable: true, value: null },\n});\n"],"names":["version","effect","useRef","useSyncExternalStore","Signal"],"mappings":"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"}