{
  "version": 3,
  "sources": ["../../../src/use-binding-effect/use-binding-effect.ts"],
  "sourcesContent": ["import { useEffect, useRef } from 'react';\n\nimport type { BindingArrayDependencies, BindingDependencies, NamedBindingDependencies } from '../binding/types/binding-dependencies';\nimport type { ChangeListenerRemover } from '../binding/types/change-listener';\nimport type { InferBindingValueTypes } from '../binding/types/infer-binding-value-types';\nimport type { ReadonlyBinding } from '../binding/types/readonly-binding';\nimport { isBinding } from '../binding-utils/type-utils.mjs';\nimport { areEqual } from '../config/are-equal.mjs';\nimport { normalizeAsArray } from '../internal-utils/array-like.mjs';\nimport { extractBindingDependencyValues } from '../internal-utils/extract-binding-dependency-values.mjs';\nimport { getTypedKeys } from '../internal-utils/get-typed-keys.mjs';\nimport { pickLimiterOptions } from '../limiter/pick-limiter-options.mjs';\nimport { useLimiter } from '../limiter/use-limiter.mjs';\nimport type { EmptyObject } from '../types/empty';\nimport { useCallbackRef } from '../utility-hooks/use-callback-ref.mjs';\nimport { useStableValue } from '../utility-hooks/use-stable-value.mjs';\nimport type { UseBindingEffectOptions } from './types/options';\n\nconst emptyDependencies = Object.freeze({} as EmptyObject);\n\n/**\n * Called when the associated bindings change, depending on the options provided to `useBindingEffect`.\n *\n * @param bindingValues - The extracted values of the associated named bindings.  If named bindings aren't used, this will be an empty\n * object.\n * @param bindings - The original named bindings if named bindings are used or an empty object otherwise.\n */\nexport type UseBindingEffectCallback<DependenciesT extends BindingDependencies> = (\n  bindingValues: InferBindingValueTypes<DependenciesT>,\n  bindings: DependenciesT\n) => void;\n\n/**\n * Calls the specified callback function any time any of the specified bindings are changed.\n *\n * Most of the time you should use this hook rather than addChangeListener.\n *\n * @returns a function that can be called anytime to cancel the most recent limited callback.  This is useful, for example, if the the\n * callback would have triggered a re-render that we, by other means, know to be unnecessary.\n */\nexport const useBindingEffect = <DependenciesT extends BindingDependencies>(\n  bindings: DependenciesT | undefined,\n  callback: UseBindingEffectCallback<DependenciesT>,\n  options: UseBindingEffectOptions = {}\n): (() => void) => {\n  const {\n    id,\n    deps,\n    areInputValuesEqual = areEqual,\n    detectInputChanges = false,\n    makeComparableInputValue,\n    triggerOnMount = 'if-input-changed'\n  } = options;\n\n  const limiterOptions = pickLimiterOptions(options);\n\n  const isNonNamedBindings = Array.isArray(bindings) || isBinding(bindings);\n  const nonNamedBindings = isNonNamedBindings ? (bindings as ReadonlyBinding | BindingArrayDependencies) : undefined;\n  const namedBindings = isNonNamedBindings ? undefined : (bindings as NamedBindingDependencies);\n  const namedBindingsKeys = namedBindings !== undefined ? getTypedKeys(namedBindings) : undefined;\n  const stableAllBindings = useStableValue(\n    isNonNamedBindings ? normalizeAsArray(nonNamedBindings) : Object.values(namedBindings ?? emptyDependencies)\n  );\n\n  // Doesn't need to be stable since always used in a callback ref\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n  const getDependencyValues = () => extractBindingDependencyValues<DependenciesT>({ bindings, namedBindingsKeys });\n\n  const comparableInputValueMaker = makeComparableInputValue ?? getDependencyValues;\n  const lastComparableInputValue = useRef(\n    detectInputChanges && (triggerOnMount === false || triggerOnMount === 'if-input-changed') ? comparableInputValueMaker() : undefined\n  );\n\n  /** Only used when `detectInputChanges` is `false` and `triggerOnMount` is `'if-input-changed'` */\n  const lastChangeUids = useRef<string | undefined>(undefined);\n\n  const limiter = useLimiter({\n    id: id ?? 'use-binding-effect',\n    cancelOnUnmount: true,\n    ...limiterOptions\n  });\n\n  const checkAndUpdateIfInputChanged = useCallbackRef(() => {\n    if (detectInputChanges) {\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      const nextComparableInputValue = comparableInputValueMaker!();\n      if (areInputValuesEqual(lastComparableInputValue.current, nextComparableInputValue)) {\n        return false;\n      }\n\n      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n      lastComparableInputValue.current = nextComparableInputValue;\n      return true;\n    } else if (triggerOnMount === 'if-input-changed') {\n      const newChangeUids = makeChangeUidsString(stableAllBindings);\n      if (newChangeUids === lastChangeUids.current) {\n        return false;\n      }\n\n      lastChangeUids.current = newChangeUids;\n      return true;\n    } else {\n      return true;\n    }\n  });\n\n  const isFirstRender = useRef(true);\n  const needsTrigger = useRef(false);\n\n  const triggerCallback = useCallbackRef((needsInputChangeTrackingUpdate: boolean) => {\n    needsTrigger.current = false;\n\n    if (needsInputChangeTrackingUpdate) {\n      // We don't care about the result here -- just want to update the tracking\n      checkAndUpdateIfInputChanged();\n    }\n\n    callback(getDependencyValues(), bindings ?? (emptyDependencies as DependenciesT));\n  });\n\n  const performChecksAndTriggerCallbackIfNeeded = useCallbackRef(() => {\n    if (needsTrigger.current) {\n      triggerCallback(true);\n    } else {\n      const didChange = checkAndUpdateIfInputChanged();\n      if (detectInputChanges && !didChange) {\n        return; // No change\n      }\n\n      triggerCallback(false);\n    }\n  });\n\n  if (isFirstRender.current) {\n    isFirstRender.current = false;\n\n    if (!detectInputChanges && triggerOnMount === 'if-input-changed') {\n      lastChangeUids.current = makeChangeUidsString(stableAllBindings);\n    }\n  }\n\n  useEffect(() => {\n    const addedBindingUids = new Set<string>();\n    const removers: ChangeListenerRemover[] = [];\n    for (const b of stableAllBindings) {\n      if (b !== undefined && !addedBindingUids.has(b.uid)) {\n        // Making sure we only listen for changes once per binding, even if the same binding is listed multiple times\n        addedBindingUids.add(b.uid);\n\n        removers.push(b.addChangeListener(() => limiter.limit(performChecksAndTriggerCallbackIfNeeded)));\n      }\n    }\n\n    return () => {\n      for (const remover of removers) {\n        remover();\n      }\n      removers.length = 0;\n    };\n  }, [limiter, performChecksAndTriggerCallbackIfNeeded, stableAllBindings]);\n\n  const isFirstMount = useRef(true);\n  useEffect(() => {\n    if (\n      needsTrigger.current ||\n      triggerOnMount === true ||\n      (isFirstMount.current && triggerOnMount === 'first') ||\n      (triggerOnMount === 'if-input-changed' && checkAndUpdateIfInputChanged())\n    ) {\n      needsTrigger.current = true;\n      limiter.limit(() => triggerCallback(true));\n    }\n    isFirstMount.current = false;\n  });\n\n  // If the deps changed,\n  const lastDepsValue = useRef(deps);\n  if (!areEqual(lastDepsValue.current, deps)) {\n    lastDepsValue.current = deps;\n\n    needsTrigger.current = true;\n    limiter.limit(() => triggerCallback(true));\n  }\n\n  // If the upcoming callback is canceled, it's assumed we have already dealt with the input in a different way, so we need to update the\n  // tracking info to make sure we don't reprocess the same thing later\n  return () => {\n    limiter.cancel();\n    needsTrigger.current = false;\n    // We don't care about the result here -- just want to update the tracking\n    checkAndUpdateIfInputChanged();\n  };\n};\n\n// Helpers\n\nconst makeChangeUidsString = (bindings: Array<ReadonlyBinding | undefined>) => {\n  const array: string[] = [];\n  for (const b of bindings) {\n    array.push(b?.getChangeUid() ?? '');\n  }\n  return array.join(',');\n};\n"],
  "mappings": "AAAA,SAAS,WAAW,cAAc;AAMlC,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AACzB,SAAS,wBAAwB;AACjC,SAAS,sCAAsC;AAC/C,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAE3B,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAG/B,MAAM,oBAAoB,OAAO,OAAO,CAAC,CAAgB;AAsBlD,MAAM,mBAAmB,CAC9B,UACA,UACA,UAAmC,CAAC,MACnB;AACjB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB;AAAA,IACA,iBAAiB;AAAA,EACnB,IAAI;AAEJ,QAAM,iBAAiB,mBAAmB,OAAO;AAEjD,QAAM,qBAAqB,MAAM,QAAQ,QAAQ,KAAK,UAAU,QAAQ;AACxE,QAAM,mBAAmB,qBAAsB,WAA0D;AACzG,QAAM,gBAAgB,qBAAqB,SAAa;AACxD,QAAM,oBAAoB,kBAAkB,SAAY,aAAa,aAAa,IAAI;AACtF,QAAM,oBAAoB;AAAA,IACxB,qBAAqB,iBAAiB,gBAAgB,IAAI,OAAO,OAAO,iBAAiB,iBAAiB;AAAA,EAC5G;AAIA,QAAM,sBAAsB,MAAM,+BAA8C,EAAE,UAAU,kBAAkB,CAAC;AAE/G,QAAM,4BAA4B,4BAA4B;AAC9D,QAAM,2BAA2B;AAAA,IAC/B,uBAAuB,mBAAmB,SAAS,mBAAmB,sBAAsB,0BAA0B,IAAI;AAAA,EAC5H;AAGA,QAAM,iBAAiB,OAA2B,MAAS;AAE3D,QAAM,UAAU,WAAW;AAAA,IACzB,IAAI,MAAM;AAAA,IACV,iBAAiB;AAAA,IACjB,GAAG;AAAA,EACL,CAAC;AAED,QAAM,+BAA+B,eAAe,MAAM;AACxD,QAAI,oBAAoB;AAEtB,YAAM,2BAA2B,0BAA2B;AAC5D,UAAI,oBAAoB,yBAAyB,SAAS,wBAAwB,GAAG;AACnF,eAAO;AAAA,MACT;AAGA,+BAAyB,UAAU;AACnC,aAAO;AAAA,IACT,WAAW,mBAAmB,oBAAoB;AAChD,YAAM,gBAAgB,qBAAqB,iBAAiB;AAC5D,UAAI,kBAAkB,eAAe,SAAS;AAC5C,eAAO;AAAA,MACT;AAEA,qBAAe,UAAU;AACzB,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,QAAM,gBAAgB,OAAO,IAAI;AACjC,QAAM,eAAe,OAAO,KAAK;AAEjC,QAAM,kBAAkB,eAAe,CAAC,mCAA4C;AAClF,iBAAa,UAAU;AAEvB,QAAI,gCAAgC;AAElC,mCAA6B;AAAA,IAC/B;AAEA,aAAS,oBAAoB,GAAG,YAAa,iBAAmC;AAAA,EAClF,CAAC;AAED,QAAM,0CAA0C,eAAe,MAAM;AACnE,QAAI,aAAa,SAAS;AACxB,sBAAgB,IAAI;AAAA,IACtB,OAAO;AACL,YAAM,YAAY,6BAA6B;AAC/C,UAAI,sBAAsB,CAAC,WAAW;AACpC;AAAA,MACF;AAEA,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF,CAAC;AAED,MAAI,cAAc,SAAS;AACzB,kBAAc,UAAU;AAExB,QAAI,CAAC,sBAAsB,mBAAmB,oBAAoB;AAChE,qBAAe,UAAU,qBAAqB,iBAAiB;AAAA,IACjE;AAAA,EACF;AAEA,YAAU,MAAM;AACd,UAAM,mBAAmB,oBAAI,IAAY;AACzC,UAAM,WAAoC,CAAC;AAC3C,eAAW,KAAK,mBAAmB;AACjC,UAAI,MAAM,UAAa,CAAC,iBAAiB,IAAI,EAAE,GAAG,GAAG;AAEnD,yBAAiB,IAAI,EAAE,GAAG;AAE1B,iBAAS,KAAK,EAAE,kBAAkB,MAAM,QAAQ,MAAM,uCAAuC,CAAC,CAAC;AAAA,MACjG;AAAA,IACF;AAEA,WAAO,MAAM;AACX,iBAAW,WAAW,UAAU;AAC9B,gBAAQ;AAAA,MACV;AACA,eAAS,SAAS;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,SAAS,yCAAyC,iBAAiB,CAAC;AAExE,QAAM,eAAe,OAAO,IAAI;AAChC,YAAU,MAAM;AACd,QACE,aAAa,WACb,mBAAmB,QAClB,aAAa,WAAW,mBAAmB,WAC3C,mBAAmB,sBAAsB,6BAA6B,GACvE;AACA,mBAAa,UAAU;AACvB,cAAQ,MAAM,MAAM,gBAAgB,IAAI,CAAC;AAAA,IAC3C;AACA,iBAAa,UAAU;AAAA,EACzB,CAAC;AAGD,QAAM,gBAAgB,OAAO,IAAI;AACjC,MAAI,CAAC,SAAS,cAAc,SAAS,IAAI,GAAG;AAC1C,kBAAc,UAAU;AAExB,iBAAa,UAAU;AACvB,YAAQ,MAAM,MAAM,gBAAgB,IAAI,CAAC;AAAA,EAC3C;AAIA,SAAO,MAAM;AACX,YAAQ,OAAO;AACf,iBAAa,UAAU;AAEvB,iCAA6B;AAAA,EAC/B;AACF;AAIA,MAAM,uBAAuB,CAAC,aAAiD;AAC7E,QAAM,QAAkB,CAAC;AACzB,aAAW,KAAK,UAAU;AACxB,UAAM,KAAK,GAAG,aAAa,KAAK,EAAE;AAAA,EACpC;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;",
  "names": []
}
