{"version":3,"file":"YogaManagerWorker-BI8TTm0U.cjs","names":[],"sources":["../src/types/NodeOperations.ts","../src/util/toSerializableValue.ts","../src/YogaManagerWorker.ts"],"sourcesContent":["export enum NodeOperations {\n  AddNode = 1,\n  RemoveNode = 2,\n  AddChildNode = 3,\n  AddChildNodeAtIndex = 4,\n  DetachChildNode = 5,\n  AddIndependentRoot = 6,\n  RemoveIndependentRoot = 7,\n}\n","function isPrimitiveValue(\n  valueType:\n    | 'string'\n    | 'number'\n    | 'bigint'\n    | 'boolean'\n    | 'symbol'\n    | 'undefined'\n    | 'object'\n    | 'function',\n): boolean {\n  return (\n    valueType === 'string' ||\n    valueType === 'number' ||\n    valueType === 'boolean' ||\n    valueType === 'bigint'\n  );\n}\n\n// oxlint-disable-next-line typescript/no-explicit-any -- Any value can be passed in\nexport function toSerializableValue<T>(key: string, value: any): T | null {\n  const valueType = typeof value;\n\n  if (isPrimitiveValue(valueType)) {\n    return value as T;\n  } else if (valueType === 'object') {\n    // Only transforms can be objects\n    if (key === 'transform') {\n      return value as T;\n    } else if (value != null && 'current' in value && isPrimitiveValue(typeof value.current)) {\n      // ...unless it's a reanimated animation. Unfortunately, there's no real\n      // good way to serialize animations. There's also no real good way to\n      // keep this logic in the reanimated plugin, so we'll just have to do it\n      // here.\n      return value.current as T;\n    }\n\n    return null;\n  }\n\n  return null;\n}\n","import { EventEmitter } from 'tseep';\n\nimport type { LightningElementStyle } from '@plextv/react-lightning';\n\nimport { NodeOperations } from './types/NodeOperations';\nimport { isFlexStyleProp } from './util/isFlexStyleProp';\nimport { SimpleDataView } from './util/SimpleDataView';\nimport { toSerializableValue } from './util/toSerializableValue';\nimport Worker from './worker?worker&inline';\nimport type { YogaManager, YogaManagerEvents } from './YogaManager';\n\n// oxlint-disable-next-line typescript/no-explicit-any -- Basic type for function signatures\ntype AnyFunc = (...args: any[]) => any;\n\nexport type Workerized<T> = {\n  [K in keyof T]: T[K] extends AnyFunc\n    ? ReturnType<T[K]> extends PromiseLike<unknown>\n      ? T[K]\n      : (...args: Parameters<T[K]>) => Promise<ReturnType<T[K]>>\n    : never;\n};\n\n/**\n * Coalesces calls within a sync task — runs `fn` once at the end of the\n * current sync code with the latest args. Uses a microtask, not setTimeout,\n * because the timer's 1ms+ minimum breaks coalescing during a React commit.\n */\nfunction debounceMicrotask<T extends (...args: unknown[]) => void | Promise<void>>(fn: T): T {\n  let scheduled = false;\n  let latestArgs: unknown[];\n\n  const debouncedFn = function (this: unknown, ...args: unknown[]) {\n    latestArgs = args;\n\n    if (scheduled) {\n      return;\n    }\n\n    scheduled = true;\n    queueMicrotask(() => {\n      scheduled = false;\n      fn.apply(this, latestArgs);\n    });\n  };\n\n  return debouncedFn as T;\n}\n\nfunction wrapWorker<T>(worker: Worker): Workerized<T> {\n  const _callees: Record<string, [AnyFunc, AnyFunc]> = {};\n  const _eventEmitter = new EventEmitter<YogaManagerEvents>();\n  let _stylesToSend: Record<number, Partial<LightningElementStyle>> = {};\n  let _numStylesToSend = 0;\n  let _needsRender = false;\n  const _childOperations = new SimpleDataView(undefined, undefined, _onChildOpsOverflow);\n\n  /**\n   * Overflow flush is nodeOps-only — combining pending styles with a\n   * partial nodeOps batch would land styles before the remaining nodeOps,\n   * targeting nodes that don't exist yet (\"node not found\" warnings).\n   */\n  function _onChildOpsOverflow(filledBuffer: ArrayBuffer) {\n    worker.postMessage(\n      {\n        method: 'nodeOperations',\n        args: [filledBuffer],\n      },\n      [filledBuffer],\n    );\n  }\n\n  function flushSendStyles() {\n    // Cheap counter check instead of `Object.keys(_stylesToSend).length` —\n    // the latter walks every key in the record on each call.\n    if (_numStylesToSend === 0) {\n      return;\n    }\n\n    // Combine with pending nodeOps — collapses two postMessages into one.\n    if (_childOperations.offset > 0) {\n      _flushBothInternal();\n\n      return;\n    }\n\n    worker.postMessage({\n      method: 'applyStyles',\n      args: [_stylesToSend, !_needsRender],\n    });\n\n    _needsRender = false;\n    _stylesToSend = {};\n    _numStylesToSend = 0;\n  }\n\n  const queueSendStyles = debounceMicrotask(flushSendStyles);\n\n  function applyStyle(\n    elementId: number,\n    style: Partial<LightningElementStyle> | null,\n    skipRender = false,\n  ) {\n    if (style) {\n      let styleToSend = _stylesToSend[elementId];\n\n      if (!styleToSend) {\n        _numStylesToSend++;\n        styleToSend = {};\n        _stylesToSend[elementId] = styleToSend;\n      }\n\n      // `for...in` skips Object.entries' tuple allocation — hot path on\n      // every applyStyle. Filter non-flex keys here so we don't serialize\n      // them, ship them across postMessage, and let the worker re-filter.\n      for (const key in style) {\n        if (!isFlexStyleProp(key)) {\n          continue;\n        }\n\n        // oxlint-disable-next-line typescript/no-explicit-any -- intentional: style values can be many shapes; toSerializableValue guards\n        const serializedValue = toSerializableValue(key, (style as any)[key]);\n\n        if (serializedValue != null) {\n          // @ts-expect-error\n          styleToSend[key] = serializedValue;\n        }\n      }\n    } else {\n      // Existence check is required — `applyStyle(id, null)` fires from\n      // childRemoved regardless of whether anything was buffered, and a\n      // counter underflow breaks the > 50 / === 0 thresholds below.\n      if (!_stylesToSend[elementId]) {\n        return;\n      }\n\n      delete _stylesToSend[elementId];\n      _numStylesToSend--;\n    }\n\n    _needsRender ||= !skipRender;\n\n    if (_numStylesToSend > 50) {\n      flushSendStyles();\n    } else {\n      queueSendStyles();\n    }\n  }\n\n  function flushChildOperations() {\n    const buffer = _childOperations.buffer;\n\n    if (buffer.byteLength === 0) {\n      return;\n    }\n\n    // Combine with pending styles if any. See `_flushBothInternal`.\n    if (_numStylesToSend > 0) {\n      _flushBothInternal();\n\n      return;\n    }\n\n    worker.postMessage(\n      {\n        method: 'nodeOperations',\n        args: [buffer],\n      },\n      [buffer],\n    );\n\n    _childOperations.reset();\n  }\n\n  /**\n   * Single 'flushBoth' postMessage — worker applies nodeOps then styles,\n   * preserving the causal ordering. Caller must have verified BOTH queues\n   * have data; this function blindly transfers and clears.\n   */\n  function _flushBothInternal() {\n    const buffer = _childOperations.buffer;\n\n    worker.postMessage(\n      {\n        method: 'flushBoth',\n        args: [buffer, _stylesToSend, !_needsRender],\n      },\n      [buffer],\n    );\n\n    _childOperations.reset();\n    _stylesToSend = {};\n    _numStylesToSend = 0;\n    _needsRender = false;\n  }\n\n  const queueSendNodeOperations = debounceMicrotask(flushChildOperations);\n\n  // Coalesce N synchronous queueRender calls into one postMessage —\n  // unmount cascades otherwise produce ~2 messages per destroyed node.\n  let _wantsRender = false;\n  let _renderElementId = 0;\n  let _renderForce = false;\n\n  function flushRender() {\n    if (!_wantsRender) {\n      return;\n    }\n\n    // Capture before flushSendStyles resets _needsRender. When applyStyles\n    // ships with skipRender=false the worker auto-renders, so the explicit\n    // queueRender below would be redundant.\n    const willAutoRender = _numStylesToSend > 0 && _needsRender;\n\n    flushChildOperations();\n    flushSendStyles();\n\n    if (!willAutoRender) {\n      worker.postMessage({\n        method: 'queueRender',\n        args: [_renderElementId, _renderForce],\n      });\n    }\n\n    _wantsRender = false;\n    _renderElementId = 0;\n    _renderForce = false;\n  }\n\n  const queueRenderDrain = debounceMicrotask(flushRender);\n\n  function nodeOperation(\n    method:\n      | 'addNode'\n      | 'removeNode'\n      | 'addChildNode'\n      | 'detachChildNode'\n      | 'addIndependentRoot'\n      | 'removeIndependentRoot',\n    elementOrParentId: number,\n    childId?: number,\n    index?: number,\n  ) {\n    switch (method) {\n      case 'addNode':\n        _childOperations.writeUint8(NodeOperations.AddNode);\n        _childOperations.writeUint32(elementOrParentId);\n        break;\n      case 'removeNode':\n        _childOperations.writeUint8(NodeOperations.RemoveNode);\n        _childOperations.writeUint32(elementOrParentId);\n        break;\n      case 'addIndependentRoot':\n        _childOperations.writeUint8(NodeOperations.AddIndependentRoot);\n        _childOperations.writeUint32(elementOrParentId);\n        break;\n      case 'removeIndependentRoot':\n        _childOperations.writeUint8(NodeOperations.RemoveIndependentRoot);\n        _childOperations.writeUint32(elementOrParentId);\n        break;\n      case 'addChildNode':\n        if (childId === undefined) {\n          throw new Error('Child ID must be provided for addChildNode operation');\n        }\n\n        _childOperations.writeUint8(\n          index === undefined ? NodeOperations.AddChildNode : NodeOperations.AddChildNodeAtIndex,\n        );\n        _childOperations.writeUint32(elementOrParentId);\n        _childOperations.writeUint32(childId);\n\n        if (index !== undefined) {\n          _childOperations.writeUint32(index);\n        }\n        break;\n      case 'detachChildNode':\n        if (childId === undefined) {\n          throw new Error('Child ID must be provided for detachChildNode operation');\n        }\n\n        _childOperations.writeUint8(NodeOperations.DetachChildNode);\n        _childOperations.writeUint32(elementOrParentId);\n        _childOperations.writeUint32(childId);\n        break;\n      default:\n        throw new Error(`Unknown node operation: ${method}`);\n    }\n\n    queueSendNodeOperations();\n  }\n\n  worker.onmessage = (event: MessageEvent<{ id: string; result?: unknown; error?: string }>) => {\n    const { id, result, error } = event.data;\n\n    if (id === 'render') {\n      // Special case for render updates\n      _eventEmitter.emit('render', result as ArrayBuffer);\n\n      return;\n    }\n\n    const callee = _callees[id];\n\n    if (!callee) {\n      console.error(`No handler found for worker message id: ${id}`);\n\n      return;\n    }\n\n    const [resolve, reject] = callee;\n\n    delete _callees[id];\n\n    if (error) {\n      reject(new Error(error));\n    } else {\n      resolve(result);\n    }\n  };\n\n  // Used by `init` only — every other call is fire-and-forget on the\n  // buffered pipeline. Flushes pending ops/styles for causal ordering.\n  function _awaitable(method: string, args: unknown[]): Promise<unknown> {\n    return new Promise((resolve, reject) => {\n      const id = getId();\n\n      _callees[id] = [resolve, reject];\n\n      flushChildOperations();\n      flushSendStyles();\n\n      worker.postMessage({ id, method, args });\n    });\n  }\n\n  // Pre-bound methods instead of a Proxy — Proxy.get + closure allocation\n  // per node-op call was measurable self-time in VL recycle bursts.\n  const proxy = {\n    on: _eventEmitter.on.bind(_eventEmitter),\n    off: _eventEmitter.off.bind(_eventEmitter),\n    applyStyle,\n    addNode: (elementId: number) => nodeOperation('addNode', elementId),\n    removeNode: (elementId: number) => nodeOperation('removeNode', elementId),\n    addChildNode: (parentId: number, childId: number, index?: number) =>\n      nodeOperation('addChildNode', parentId, childId, index),\n    detachChildNode: (parentId: number, childId: number) =>\n      nodeOperation('detachChildNode', parentId, childId),\n    queueRender: (elementId: number, force?: boolean) => {\n      _wantsRender = true;\n      _renderElementId = elementId;\n      _renderForce = !!force;\n      queueRenderDrain();\n    },\n    addIndependentRoot: (elementId: number) => nodeOperation('addIndependentRoot', elementId),\n    removeIndependentRoot: (elementId: number) => nodeOperation('removeIndependentRoot', elementId),\n    init: (yogaOptions?: unknown) => _awaitable('init', [yogaOptions]),\n  };\n\n  return proxy as unknown as Workerized<T>;\n}\n\nlet count = 0;\nfunction getId(): number {\n  return ++count;\n}\n\nexport default (): Workerized<YogaManager> => wrapWorker<YogaManager>(new Worker());\n"],"mappings":"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"}