{"version":3,"file":"mobx.cjs","names":[],"sources":["../src/mobx/annotation.ts","../src/mobx/apply-observable.ts","../src/mobx/create-enhanced-atom.ts","../src/mobx/create-ref.ts","../src/mobx/deep-observable-struct.ts","../src/mobx/flush-pending-reactions.ts","../src/mobx/get-mobx-administration.ts","../src/mobx/lazy-observe.ts"],"sourcesContent":["/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **`annotation`** — factories for `makeObservable` maps and {@link applyObservable} tuples:\n * `observable.*` flavours, `computed` with shorthand `equals` (`struct`, `shallow`, reference), custom\n * comparators, and `false` to skip a field.\n *\n * ## Usage\n *\n * ```ts\n * import { annotation } from \"yummies/mobx\";\n * ```\n */\n\nimport {\n  comparer,\n  computed,\n  type IComputedValueOptions,\n  type IEqualsComparer,\n  observable,\n} from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\n/**\n * How MobX should compare the previous and next computed value before notifying observers.\n *\n * - `'struct'` — structural comparison (`comparer.structural`).\n * - `'shallow'` — shallow comparison (`comparer.shallow`).\n * - `true` — reference equality (`comparer.default`).\n * - `false` — skip the annotation (handled by the `annotation.computed` / `annotation.observable` helpers).\n * - A custom `(a, b) => boolean` is allowed by the type for parity with `IComputedValueOptions.equals`.\n */\nexport type ComputedEqualsValue =\n  | 'struct'\n  | 'shallow'\n  | boolean\n  | IEqualsComparer<any>;\n\nconst computedEqualsResolvers: AnyObject = {\n  true: comparer.default,\n  shallow: comparer.shallow,\n  struct: comparer.structural,\n} satisfies Record<\n  Exclude<ComputedEqualsValue, Function | boolean> | 'true',\n  any\n>;\n\n/**\n * Options forwarded to {@link computed}, except `equals` (that argument is passed separately).\n */\nexport type ComputedOtherOptions = Omit<IComputedValueOptions<any>, 'equals'>;\n\n/**\n * Observable flavour keys returned by {@link annotation.observable}: `ref`, `deep`, `shallow`, `struct`.\n * Also supported: `true` (base `observable`) and `false` (no annotation).\n */\nexport type ObservableTypes =\n  | keyof Pick<typeof observable, 'ref' | 'deep' | 'shallow' | 'struct'>\n  | boolean;\n\n/**\n * MobX annotation factories for `makeObservable` and tuple-style wiring ({@link applyObservable}).\n *\n * - **`annotation.observable(value?)`** — `observable.ref` / `deep` / `shallow` / `struct`; `true` or\n *   omitted → base `observable` (deep by default); `false` → `false` (field omitted from the map).\n * - **`annotation.computed(value?, options?)`** — `computed({ ...options, equals })` with `equals` from\n *   {@link ComputedEqualsValue} or a custom `(a, b) => boolean`. Omitted `value`, unknown literals, and\n *   `true` resolve to `comparer.default`; `value === false` returns `false`.\n *\n * Other `computed` options (except `equals`) go in the second argument; see {@link ComputedOtherOptions}.\n *\n * @example Observable variants\n * ```ts\n * import { makeObservable } from 'mobx';\n * import { annotation } from 'yummies/mobx';\n *\n * class Store {\n *   shallowMap = new Map();\n *   deep = { nested: { count: 0 } };\n *\n *   constructor() {\n *     makeObservable(this, {\n *       shallowMap: annotation.observable('shallow'),\n *       deep: annotation.observable('deep'),\n *     });\n *   }\n * }\n * ```\n *\n * @example Skip a field\n * ```ts\n * makeObservable(this, {\n *   plain: annotation.observable(false), // not decorated\n * });\n * ```\n *\n * @example Computed with structural equality\n * ```ts\n * makeObservable(this, {\n *   fullName: annotation.computed('struct', { name: 'fullName' }),\n * });\n * ```\n *\n * @example Computed with default reference equality\n * ```ts\n * makeObservable(this, {\n *   total: annotation.computed(true),\n * });\n * ```\n *\n * @example Omitted first argument or `true` — reference equality (`comparer.default`)\n * ```ts\n * makeObservable(this, {\n *   n: annotation.computed(undefined, { name: 'n' }),\n *   m: annotation.computed(true, { name: 'm' }), // same `equals` as omitted\n * });\n * ```\n *\n * @example Custom `equals`\n * ```ts\n * makeObservable(this, {\n *   row: annotation.computed((a, b) => a.id === b.id),\n * });\n * ```\n *\n * @example With {@link applyObservable}\n * ```ts\n * applyObservable(store, [\n *   [annotation.observable('shallow'), 'cache', 'index'],\n *   [annotation.computed('struct'), 'viewModel'],\n * ]);\n * ```\n *\n * @example `observable.ref` and skipping `computed`\n * ```ts\n * makeObservable(this, {\n *   handle: annotation.observable('ref'),\n *   skipMe: annotation.computed(false),\n * });\n * ```\n */\n\ntype AnnotationObject = {\n  computed(value: false): false;\n  computed(\n    value?: Exclude<ComputedEqualsValue, false>,\n    options?: ComputedOtherOptions,\n  ): typeof computed.struct;\n  computed(value?: ComputedEqualsValue): false | typeof computed.struct;\n  observable(value: Extract<ObservableTypes, false>): false;\n  observable(value?: Extract<ObservableTypes, true>): typeof observable;\n  observable<TValue extends Exclude<ObservableTypes, boolean>>(\n    value: TValue,\n  ): (typeof observable)[TValue];\n  observable(\n    value?: ObservableTypes,\n  ): false | (typeof observable)[Exclude<ObservableTypes, boolean>];\n};\n\nexport const annotation = {\n  computed: (value?: ComputedEqualsValue, options?: ComputedOtherOptions) => {\n    if (value === false) return false;\n\n    return computed({\n      ...options,\n      equals:\n        typeof value === 'function'\n          ? value\n          : (computedEqualsResolvers[\n              value as keyof typeof computedEqualsResolvers\n            ] ?? comparer.default),\n    });\n  },\n  observable: (value?: ObservableTypes | boolean) => {\n    if (value === false) return false;\n    if (value === undefined || value === true) return observable;\n    return observable[value];\n  },\n} as AnnotationObject;\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * Compact **MobX `makeObservable`** wiring from tuple lists of annotations and keys. Reduces boilerplate\n * when many fields share `observable`, `action`, or `computed` decorators and you want one call site\n * instead of sprawling annotation maps across large stores.\n *\n * ## Usage\n *\n * ```ts\n * import { applyObservable } from \"yummies/mobx\";\n * ```\n */\n\nimport { type AnnotationMapEntry, makeObservable } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\nexport type ObservableAnnotationsArray<T extends AnyObject = AnyObject> = [\n  AnnotationMapEntry,\n  ...(keyof T | (string & {}))[],\n][];\n\n/**\n * Applies a compact list of MobX annotations to an object using either\n * decorator-style invocation or the annotation map form accepted by `makeObservable`.\n *\n * @template T Target object type.\n * @param context Object that should become observable.\n * @param annotationsArray Tuples of annotation followed by annotated field names.\n * @param useDecorators Enables decorator-style application before calling `makeObservable`.\n *\n * @example\n * ```ts\n * applyObservable(store, [[observable, 'items'], [action, 'setItems']]);\n * ```\n *\n * @example\n * ```ts\n * applyObservable(viewModel, [[computed, 'fullName']], true);\n * ```\n */\nexport const applyObservable = <T extends AnyObject>(\n  context: T,\n  annotationsArray: ObservableAnnotationsArray<T>,\n  useDecorators?: boolean,\n) => {\n  if (useDecorators) {\n    annotationsArray.forEach(([annotation, ...fields]) => {\n      fields.forEach((field) => {\n        // @ts-expect-error\n        annotation(context, field);\n      });\n    });\n\n    makeObservable(context);\n  } else {\n    const annotationsObject: AnyObject = {};\n\n    annotationsArray.forEach(([annotation, ...fields]) => {\n      fields.forEach((field) => {\n        annotationsObject[field] = annotation;\n      });\n    });\n\n    makeObservable(context, annotationsObject);\n  }\n};\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **`createAtom` wrapper** that attaches arbitrary metadata and keeps MobX’s observed/unobserved\n * hooks in one place. Useful for custom reactive primitives, async resources, or debugging atoms\n * where the stock API is too bare.\n *\n * ## Usage\n *\n * ```ts\n * import { createEnhancedAtom } from \"yummies/mobx\";\n * ```\n */\n\nimport { createAtom, type IAtom } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\nexport interface IEnhancedAtom<TMeta extends AnyObject = AnyObject>\n  extends IAtom {\n  meta: TMeta;\n}\n\n/**\n * Creates a MobX atom extended with metadata and bound reporting methods.\n *\n * @template TMeta Metadata object stored on the atom.\n * @param name Atom name used by MobX for debugging.\n * @param onBecomeObservedHandler Callback fired when the atom becomes observed.\n * @param onBecomeUnobservedHandler Callback fired when the atom is no longer observed.\n * @param meta Optional metadata attached to the atom.\n * @returns Atom instance with `meta`, `reportChanged` and `reportObserved`.\n *\n * @example\n * ```ts\n * const atom = createEnhancedAtom('user-status');\n * atom.reportChanged();\n * ```\n *\n * @example\n * ```ts\n * const atom = createEnhancedAtom('cache', undefined, undefined, { scope: 'users' });\n * atom.meta.scope;\n * ```\n */\nexport const createEnhancedAtom = <TMeta extends AnyObject>(\n  name: string,\n  onBecomeObservedHandler?: (atom: IEnhancedAtom<TMeta>) => void,\n  onBecomeUnobservedHandler?: (atom: IEnhancedAtom<TMeta>) => void,\n  meta?: TMeta,\n): IEnhancedAtom<TMeta> => {\n  const atom = createAtom(\n    name,\n    onBecomeObservedHandler && (() => onBecomeObservedHandler(atom)),\n    onBecomeUnobservedHandler && (() => onBecomeUnobservedHandler(atom)),\n  ) as IEnhancedAtom<TMeta>;\n  atom.meta = meta ?? ({} as TMeta);\n  atom.reportChanged = atom.reportChanged.bind(atom);\n  atom.reportObserved = atom.reportObserved.bind(atom);\n  return atom;\n};\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **Observable ref** pattern for MobX: boxed mutable references with change listeners, metadata,\n * and optional custom equality. Bridges React-style ref holders and MobX reactivity when a single\n * mutable cell must notify dependents without replacing the whole parent object graph.\n *\n * ## Usage\n *\n * ```ts\n * import { createRef } from \"yummies/mobx\";\n * ```\n */\n\nimport {\n  type IEqualsComparer,\n  makeObservable,\n  comparer as mobxComparer,\n  observable,\n  runInAction,\n} from 'mobx';\nimport type { AnyObject, Maybe } from 'yummies/types';\n\n/**\n * You can return `false` if you don't want to change the value in this ref\n */\nexport type RefChangeListener<T> = (\n  value: T | null,\n  prevValue: T | undefined,\n) => void | false;\n\n/**\n * Alternative to React.createRef but works in MobX world.\n * Typically it the should be the same React.LegacyRef (fn style)\n */\nexport interface Ref<T = any, TMeta = AnyObject> {\n  /**\n   * Setter function\n   */\n  (value: Maybe<T>): void;\n\n  set(value: Maybe<T>): void;\n  listeners: Set<RefChangeListener<NoInfer<T>>>;\n  current: NoInfer<T> | null;\n  meta: TMeta;\n}\n\nexport interface CreateRefConfig<T = any, TMeta = AnyObject> {\n  onSet?: (node: T, prevValue: T | undefined) => void;\n  onUnset?: (lastValue: T | undefined) => void;\n  onChange?: RefChangeListener<T>;\n  meta?: TMeta;\n  initial?: Maybe<T>;\n  comparer?: IEqualsComparer<T | null>;\n}\n\n/**\n * Creates a MobX-aware ref that behaves like a callback ref and exposes\n * observable `current` and `meta` fields.\n *\n * @template T Referenced value type.\n * @template TMeta Additional observable metadata stored on the ref.\n * @param cfg Optional callbacks, initial value and comparer configuration.\n * @returns Observable ref function object.\n *\n * @example\n * ```ts\n * const inputRef = createRef<HTMLInputElement>();\n * inputRef.set(document.createElement('input'));\n * ```\n *\n * @example\n * ```ts\n * const ref = createRef<number>();\n * ref(3);\n * ref.current; // 3\n * ```\n *\n * @example\n * ```ts\n * const nodeRef = createRef({\n *   onUnset: () => console.log('detached'),\n *   meta: { mounted: false },\n * });\n * ```\n */\nexport const createRef = <T = any, TMeta = AnyObject>(\n  cfg?: CreateRefConfig<T, TMeta>,\n): Ref<T, TMeta> => {\n  let lastValue: T | undefined;\n  const comparer = cfg?.comparer ?? mobxComparer.default;\n\n  const setValue: Ref<T, TMeta>['set'] = (value) => {\n    const nextValue = value ?? null;\n\n    if (comparer(ref.current, nextValue)) {\n      return;\n    }\n\n    runInAction(() => {\n      const prevLastValue = lastValue;\n      lastValue = ref.current ?? undefined;\n      ref.current = nextValue;\n\n      let isNextValueIgnored = false;\n\n      ref.listeners.forEach((listener) => {\n        const listenerResult = listener(ref.current, lastValue);\n\n        if (listenerResult === false) {\n          isNextValueIgnored = true;\n        }\n      });\n\n      if (isNextValueIgnored) {\n        lastValue = prevLastValue;\n        ref.current = lastValue ?? null;\n      } else if (ref.current === null && lastValue !== undefined) {\n        lastValue = undefined;\n      }\n    });\n  };\n\n  const ref = setValue as Ref<T, TMeta>;\n\n  ref.set = setValue;\n\n  ref.listeners = new Set(cfg?.onChange ? [cfg.onChange] : []);\n\n  if (cfg?.onSet || cfg?.onUnset) {\n    ref.listeners.add((value, prevValue) => {\n      if (value) {\n        cfg.onSet?.(value, prevValue);\n      } else {\n        cfg.onUnset?.(prevValue);\n      }\n    });\n  }\n\n  ref.current = cfg?.initial ?? null;\n  ref.meta = cfg?.meta ?? ({} as TMeta);\n\n  makeObservable(ref, {\n    current: observable.ref,\n    meta: observable,\n  });\n\n  return ref;\n};\n\n/**\n * Checks whether the provided value is a ref created by `createRef`.\n *\n * @template T Referenced value type.\n * @template TMeta Ref metadata type.\n * @param value Value to inspect.\n * @returns `true` when the value is a ref-like function with `current`.\n *\n * @example\n * ```ts\n * const ref = createRef<number>();\n * isRef(ref); // true\n * ```\n *\n * @example\n * ```ts\n * isRef({ current: 1 }); // false\n * ```\n */\nexport const isRef = <T, TMeta = any>(\n  value: T | Ref<T, TMeta>,\n): value is Ref<T, TMeta> => {\n  return typeof value === 'function' && 'current' in value;\n};\n\n/**\n * Normalizes a plain value or an existing ref into a `Ref` instance.\n *\n * @template T Referenced value type.\n * @template TMeta Ref metadata type.\n * @param value Existing ref or initial plain value.\n * @param cfg Optional ref configuration applied when a new ref is created.\n * @returns Existing ref or a newly created ref initialized with `value`.\n *\n * @example\n * ```ts\n * const ref = toRef(document.body);\n * ref.current === document.body;\n * ```\n *\n * @example\n * ```ts\n * const existingRef = createRef<number>();\n * const sameRef = toRef(existingRef);\n * ```\n */\nexport const toRef = <T, TMeta = any>(\n  value: T | Ref<T, TMeta>,\n  cfg?: Omit<CreateRefConfig<T, TMeta>, 'initial'>,\n): Ref<T, TMeta> => {\n  return isRef(value) ? value : createRef({ initial: value, ...cfg });\n};\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **Deep observable object** with structural `set` patches that reuse nested observables when keys\n * overlap. Helps store trees (forms, filters, entities) under MobX without wholesale replacement\n * and without manual `observable.map` wiring for every level.\n *\n * ## Usage\n *\n * ```ts\n * import { DeepObservableStruct } from \"yummies/mobx\";\n * ```\n */\n\nimport { action, makeObservable, observable } from 'mobx';\nimport { typeGuard } from 'yummies/type-guard';\nimport type { AnyObject } from 'yummies/types';\n\n/**\n * Wraps a plain object into a deeply observable structure and allows\n * patch-like updates while preserving nested observable references where possible.\n *\n * @template TData Observable object shape.\n *\n * @example\n * ```ts\n * const state = new DeepObservableStruct({ user: { name: 'Ann' } });\n * state.set({ user: { name: 'Bob' } });\n * ```\n *\n * @example\n * ```ts\n * const state = new DeepObservableStruct({ filters: { active: true } });\n * state.set({ filters: { active: false, archived: true } });\n * ```\n */\nexport class DeepObservableStruct<TData extends AnyObject> {\n  data: TData;\n\n  constructor(data: TData) {\n    this.data = data;\n\n    makeObservable(this, {\n      data: observable.deep,\n      set: action,\n    });\n  }\n\n  set(newData: Partial<TData>) {\n    type StackItem = [key: string, currObservable: AnyObject, new: AnyObject];\n\n    const stack: StackItem[] = Object.keys(this.data).map((key) => [\n      key,\n      this.data,\n      newData,\n    ]);\n\n    let currentIndex = 0;\n    let stackLength = stack.length;\n\n    while (currentIndex < stackLength) {\n      const [key, currObservableData, newData] = stack[currentIndex];\n      const newValue = newData[key];\n      const currValue = currObservableData[key];\n\n      currentIndex++;\n\n      if (key in newData) {\n        if (typeGuard.isObject(newValue) && typeGuard.isObject(currValue)) {\n          const newValueKeys = Object.keys(newValue);\n\n          Object.keys(currValue).forEach((childKey) => {\n            if (!(childKey in newValue)) {\n              delete currObservableData[key][childKey];\n            }\n          });\n\n          newValueKeys.forEach((childKey) => {\n            const length = stack.push([\n              childKey,\n              currObservableData[key],\n              newValue,\n            ]);\n            stackLength = length;\n          });\n        } else if (newValue !== currValue) {\n          currObservableData[key] = newValue;\n        }\n      } else {\n        delete currObservableData[key];\n      }\n    }\n\n    Object.keys(newData).forEach((newDataKey) => {\n      if (!this.data[newDataKey]) {\n        // @ts-expect-error\n        this.data[newDataKey] = newData[newDataKey];\n      }\n    });\n  }\n}\n","import { _getGlobalState } from 'mobx';\nimport type { MobXGlobals } from 'mobx/dist/internal.js';\n\n/** Same cap as MobX's internal `MAX_REACTION_ITERATIONS` (not exported from the package). */\nconst DEFAULT_MAX_REACTION_ITERATIONS = 100;\n\n/**\n * Synchronously runs MobX reactions from the internal `pendingReactions` queue when they piled up\n * during a batch (`inBatch > 0`, e.g. inside `runInAction`).\n *\n * While a batch is open, MobX only enqueues reactions; this call temporarily resets the batch\n * counter, drains the queue, and restores state—useful in tests and when you need side effects\n * before leaving the action.\n *\n * If there are no pending reactions, a reaction run is already in progress (`isRunningReactions`),\n * or the iteration cap is hit (cycle guard), there is no extra work; when the cap is exceeded the\n * queue is cleared, matching MobX's internal safety behavior.\n *\n * @param maxCount - Maximum iterations of the outer drain loop (default 100, same idea as MobX's internal limit).\n *   Pass `Number.POSITIVE_INFINITY` to disable this cap only when you trust the reaction graph to settle;\n *   a non-converging cycle will then keep looping until the queue empties (or effectively hang).\n *\n * @example\n * ```ts\n * import { observable, reaction, runInAction } from \"mobx\";\n * import { flushPendingReactions } from \"yummies/mobx\";\n *\n * const state = observable({ count: 0 });\n * const log: number[] = [];\n * reaction(() => state.count, (n) => log.push(n));\n *\n * runInAction(() => {\n *   state.count = 1;\n *   flushPendingReactions();\n * });\n *\n * // log === [1] — the reaction ran before the action finished\n * ```\n */\nexport function flushPendingReactions(\n  maxCount = DEFAULT_MAX_REACTION_ITERATIONS,\n): void {\n  const gs: MobXGlobals = _getGlobalState();\n\n  if (!maxCount || gs.isRunningReactions || gs.pendingReactions.length === 0) {\n    return;\n  }\n\n  const savedInBatch = gs.inBatch;\n  gs.inBatch = 0;\n\n  try {\n    gs.isRunningReactions = true;\n    const queue = gs.pendingReactions;\n    let iterations = 0;\n\n    while (queue.length > 0) {\n      if (++iterations === maxCount) {\n        queue.splice(0);\n        break;\n      }\n\n      const batch = queue.splice(0);\n      for (let i = 0; i < batch.length; i++) {\n        batch[i].runReaction_();\n      }\n    }\n  } finally {\n    gs.isRunningReactions = false;\n    gs.inBatch = savedInBatch;\n  }\n}\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * Typed access to MobX **internal administration** (`$mobx`) for advanced tooling, migration scripts,\n * or introspection. Prefer public MobX APIs in application code; reach for this when you must align\n * with library internals or patch behavior at the administration layer.\n *\n * ## Usage\n *\n * ```ts\n * import { getMobxAdministration } from \"yummies/mobx\";\n * ```\n */\n\nimport { $mobx, type AnnotationMapEntry } from 'mobx';\nimport type { AnyObject } from 'yummies/types';\n\ntype ObservableObjectAdministration = Parameters<\n  Exclude<AnnotationMapEntry, boolean>['make_']\n>[0];\n\n/**\n * Returns the internal MobX administration object associated with an observable target.\n *\n * @param context Observable object instance.\n * @returns MobX administration internals stored under `$mobx`.\n *\n * @example\n * ```ts\n * const admin = getMobxAdministration(store);\n * admin.name_;\n * ```\n *\n * @example\n * ```ts\n * const values = getMobxAdministration(formState).values_;\n * ```\n */\nexport const getMobxAdministration = (\n  context: AnyObject,\n): ObservableObjectAdministration => context[$mobx];\n","/**\n * ---header-docs-section---\n * # yummies/mobx\n *\n * ## Description\n *\n * **Lazy subscriptions** tied to MobX observation: start work when the first reaction observes\n * tracked keys, stop when nothing listens anymore (optionally after a delay). Ideal for polling,\n * WebSocket feeds, or expensive caches that should idle when the UI is not mounted.\n *\n * ## Usage\n *\n * ```ts\n * import { lazyObserve } from \"yummies/mobx\";\n * ```\n */\n\nimport { onBecomeObserved, onBecomeUnobserved } from 'mobx';\n\n/**\n * Starts side effects only while one or more MobX observables are being observed.\n *\n * When the first property becomes observed, `onStart` is called. When all tracked\n * properties become unobserved, `onEnd` is called with the value returned by\n * `onStart`. Cleanup can be delayed via `endDelay`.\n *\n * It uses MobX `onBecomeObserved` and `onBecomeUnobserved` hooks to perform\n * lazy subscription management.\n *\n * @template TMetaData Data returned from `onStart` and forwarded to `onEnd`.\n * @param config Configuration for tracked properties and lifecycle callbacks.\n * @returns Cleanup function that clears the tracked state and runs `onEnd`.\n *\n * @example\n * ```ts\n * const stop = lazyObserve({\n *   context: store,\n *   property: 'items',\n *   onStart: () => api.subscribe(),\n *   onEnd: (subscription) => subscription.unsubscribe(),\n * });\n * ```\n *\n * @example\n * ```ts\n * lazyObserve({\n *   property: [boxA, boxB],\n *   onStart: () => console.log('observed'),\n *   endDelay: 300,\n * });\n * ```\n */\nexport const lazyObserve = <TMetaData = void>({\n  context,\n  property,\n  onStart,\n  onEnd,\n  endDelay = false,\n}: {\n  context?: any;\n  property: any | any[];\n  onStart?: () => TMetaData;\n  onEnd?: (metaData: TMetaData, cleanupFn: VoidFunction) => void;\n  endDelay?: number | false;\n}) => {\n  let timeoutId: ReturnType<typeof setTimeout> | undefined;\n  let metaData: TMetaData | undefined;\n  const observingProps = new Set<string>();\n  const properties = Array.isArray(property) ? property : [property];\n\n  const cleanup = () => {\n    observingProps.clear();\n\n    if (endDelay === false) {\n      onEnd?.(metaData!, cleanup);\n      metaData = undefined;\n      return;\n    }\n\n    if (timeoutId) {\n      clearTimeout(timeoutId);\n      timeoutId = undefined;\n    }\n\n    timeoutId = setTimeout(() => {\n      onEnd?.(metaData!, cleanup);\n      timeoutId = undefined;\n      metaData = undefined;\n    }, endDelay);\n  };\n\n  const start = (property: string) => {\n    const isAlreadyObserving = observingProps.size > 0;\n    observingProps.add(property);\n\n    if (isAlreadyObserving) {\n      return;\n    }\n\n    if (timeoutId) {\n      clearTimeout(timeoutId);\n      timeoutId = undefined;\n    }\n\n    metaData = onStart?.();\n  };\n\n  const stop = (property: string) => {\n    const isAlreadyNotObserving = !observingProps.size;\n\n    observingProps.delete(property);\n\n    const isObserving = observingProps.size > 0;\n\n    if (isAlreadyNotObserving || isObserving) {\n      return;\n    }\n\n    cleanup();\n  };\n\n  properties.forEach((property) => {\n    if (context) {\n      onBecomeObserved(context, property, () => start(property));\n      onBecomeUnobserved(context, property, () => stop(property));\n    } else {\n      onBecomeObserved(property, () => start(property));\n      onBecomeUnobserved(property, () => stop(property));\n    }\n  });\n\n  return cleanup;\n};\n"],"mappings":"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"}