{"version":3,"file":"objectEnlive.min.mjs","names":[],"sources":["../../../../src/util/misc/objectEnlive.ts"],"sourcesContent":["import { noop } from '../../constants';\nimport type { FabricObject } from '../../shapes/Object/FabricObject';\nimport type {\n  Abortable,\n  Constructor,\n  TCrossOrigin,\n  TFiller,\n} from '../../typedefs';\nimport { createImage } from './dom';\nimport { classRegistry } from '../../ClassRegistry';\nimport type { BaseFilter } from '../../filters/BaseFilter';\nimport type { FabricObject as BaseFabricObject } from '../../shapes/Object/Object';\nimport { FabricError, SignalAbortedError } from '../internals/console';\nimport type { Shadow } from '../../Shadow';\n\nexport type LoadImageOptions = Abortable & {\n  /**\n   * cors value for the image loading, default to anonymous\n   */\n  crossOrigin?: TCrossOrigin;\n};\n\n/**\n * Loads image element from given url and resolve it, or catch.\n * @param {String} url URL representing an image\n * @param {LoadImageOptions} [options] image loading options\n * @returns {Promise<HTMLImageElement>} the loaded image.\n */\nexport const loadImage = (\n  url: string,\n  { signal, crossOrigin = null }: LoadImageOptions = {},\n) =>\n  new Promise<HTMLImageElement>(function (resolve, reject) {\n    if (signal && signal.aborted) {\n      return reject(new SignalAbortedError('loadImage'));\n    }\n    const img = createImage();\n    let abort: EventListenerOrEventListenerObject;\n    if (signal) {\n      abort = function (err: Event) {\n        img.src = '';\n        reject(err);\n      };\n      signal.addEventListener('abort', abort, { once: true });\n    }\n    const done = function () {\n      img.onload = img.onerror = null;\n      abort && signal?.removeEventListener('abort', abort);\n      resolve(img);\n    };\n    if (!url) {\n      done();\n      return;\n    }\n    img.onload = done;\n    img.onerror = function () {\n      abort && signal?.removeEventListener('abort', abort);\n      reject(new FabricError(`Error loading ${img.src}`));\n    };\n    crossOrigin && (img.crossOrigin = crossOrigin);\n    img.src = url;\n  });\n\nexport type EnlivenObjectOptions = Abortable & {\n  /**\n   * Method for further parsing of object elements,\n   * called after each fabric object created.\n   */\n  reviver?: <\n    T extends\n      | BaseFabricObject\n      | FabricObject\n      | BaseFilter<string>\n      | Shadow\n      | TFiller,\n  >(\n    serializedObj: Record<string, any>,\n    instance: T | undefined,\n    error?: FabricError,\n  ) => void | Promise<T>;\n};\n\n/**\n * @TODO type this correctly.\n * Creates corresponding fabric instances from their object representations\n * @param {Object[]} objects Objects to enliven\n * @param {EnlivenObjectOptions} [options]\n * @param {(serializedObj: object, instance: FabricObject) => any} [options.reviver] Method for further parsing of object elements,\n * called after each fabric object created.\n * @param {AbortSignal} [options.signal] handle aborting, see https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal\n * @returns {Promise<FabricObject[]>}\n */\nexport const enlivenObjects = <\n  T extends\n    | BaseFabricObject\n    | FabricObject\n    | BaseFilter<string>\n    | Shadow\n    | TFiller,\n>(\n  objects: any[],\n  { signal, reviver = noop }: EnlivenObjectOptions = {},\n) =>\n  new Promise<T[]>((resolve, reject) => {\n    const instances: T[] = [];\n    signal && signal.addEventListener('abort', reject, { once: true });\n    Promise.allSettled(\n      objects.map((obj) =>\n        classRegistry\n          .getClass<\n            Constructor<T> & {\n              fromObject(options: any, context: Abortable): Promise<T>;\n            }\n          >(obj.type)\n          .fromObject(obj, { signal }),\n      ),\n    )\n      .then(async (elementsResult) => {\n        for (const [index, result] of elementsResult.entries()) {\n          if (result.status === 'fulfilled') {\n            await reviver(objects[index], result.value);\n            instances.push(result.value);\n          }\n          if (result.status === 'rejected') {\n            const fallback = await reviver(\n              objects[index],\n              undefined,\n              result.reason,\n            );\n            if (fallback) {\n              instances.push(fallback as T);\n            }\n          }\n        }\n        resolve(instances);\n      })\n      .catch((error) => {\n        // cleanup\n        instances.forEach((instance) => {\n          (instance as FabricObject).dispose &&\n            (instance as FabricObject).dispose();\n        });\n        reject(error);\n      })\n      .finally(() => {\n        signal && signal.removeEventListener('abort', reject);\n      });\n  });\n\n/**\n * Creates corresponding fabric instances residing in an object, e.g. `clipPath`\n * @param {Object} object with properties to enlive ( fill, stroke, clipPath, path )\n * @param {object} [options]\n * @param {AbortSignal} [options.signal] handle aborting, see https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal\n * @returns {Promise<Record<string, FabricObject | TFiller | null>>} the input object with enlived values\n */\nexport const enlivenObjectEnlivables = <\n  R = Record<string, FabricObject | TFiller | null>,\n>(\n  serializedObject: any,\n  { signal }: Abortable = {},\n) =>\n  new Promise<R>((resolve, reject) => {\n    const instances: (FabricObject | TFiller | Shadow)[] = [];\n    signal && signal.addEventListener('abort', reject, { once: true });\n    // enlive every possible property\n    const promises = Object.values(serializedObject).map((value: any) => {\n      if (!value) {\n        return value;\n      }\n      /**\n       * clipPath or shadow or gradient or text on a path or a pattern,\n       * or the backgroundImage or overlayImage of canvas\n       * If we have a type and there is a classe registered for it, we enlive it.\n       * If there is no class registered for it we return the value as is\n       * */\n      if (value.type && classRegistry.has(value.type)) {\n        return enlivenObjects<FabricObject | Shadow | TFiller>([value], {\n          signal,\n        }).then(([enlived]) => {\n          instances.push(enlived);\n          return enlived;\n        });\n      }\n      return value;\n    });\n    const keys = Object.keys(serializedObject);\n    Promise.all(promises)\n      .then((enlived) => {\n        return enlived.reduce((acc, instance, index) => {\n          acc[keys[index]] = instance;\n          return acc;\n        }, {});\n      })\n      .then(resolve)\n      .catch((error) => {\n        // cleanup\n        instances.forEach((instance: any) => {\n          instance.dispose && instance.dispose();\n        });\n        reject(error);\n      })\n      .finally(() => {\n        signal && signal.removeEventListener('abort', reject);\n      });\n  });\n"],"mappings":"0OA4BA,MAAa,GACX,EAAA,CACE,OAAA,EAAQ,YAAA,EAAc,MAA2B,EAAA,GAEnD,IAAI,QAA0B,SAAU,EAAS,EAAA,CAC/C,GAAI,GAAU,EAAO,QACnB,OAAO,EAAO,IAAI,EAAmB,YAAA,CAAA,CAEvC,IAAM,EAAM,GAAA,CACR,EACA,IACF,EAAQ,SAAU,EAAA,CAChB,EAAI,IAAM,GACV,EAAO,EAAA,EAET,EAAO,iBAAiB,QAAS,EAAO,CAAE,KAAA,CAAM,EAAA,CAAA,EAElD,IAAM,EAAO,UAAA,CACX,EAAI,OAAS,EAAI,QAAU,KAC3B,IAAA,GAAA,MAAS,EAAQ,oBAAoB,QAAS,EAAA,EAC9C,EAAQ,EAAA,EAEL,GAIL,EAAI,OAAS,EACb,EAAI,QAAU,UAAA,CACZ,IAAA,GAAA,MAAS,EAAQ,oBAAoB,QAAS,EAAA,EAC9C,EAAO,IAAI,EAAY,iBAAiB,EAAI,MAAA,CAAA,EAE9C,IAAgB,EAAI,YAAc,GAClC,EAAI,IAAM,GATR,GAAA,EAAA,CAyCO,GAQX,EAAA,CACE,OAAA,EAAQ,QAAA,EAAU,GAA+B,EAAA,GAEnD,IAAI,SAAc,EAAS,IAAA,CACzB,IAAM,EAAiB,EAAA,CACvB,GAAU,EAAO,iBAAiB,QAAS,EAAQ,CAAE,KAAA,CAAM,EAAA,CAAA,CAC3D,QAAQ,WACN,EAAQ,IAAK,GACX,EACG,SAIC,EAAI,KAAA,CACL,WAAW,EAAK,CAAE,OAAA,EAAA,CAAA,CAAA,CAAA,CAGtB,KAAK,KAAO,IAAA,CACX,IAAK,GAAA,CAAO,EAAO,KAAW,EAAe,SAAA,CAK3C,GAJI,EAAO,SAAW,cAAX,MACH,EAAQ,EAAQ,GAAQ,EAAO,MAAA,CACrC,EAAU,KAAK,EAAO,MAAA,EAEpB,EAAO,SAAW,WAAY,CAChC,IAAM,EAAA,MAAiB,EACrB,EAAQ,GAAA,IACR,GACA,EAAO,OAAA,CAEL,GACF,EAAU,KAAK,EAAA,CAIrB,EAAQ,EAAA,EAAA,CAET,MAAO,GAAA,CAEN,EAAU,QAAS,GAAA,CAChB,EAA0B,SACxB,EAA0B,SAAA,EAAA,CAE/B,EAAO,EAAA,EAAA,CAER,YAAA,CACC,GAAU,EAAO,oBAAoB,QAAS,EAAA,EAAA,EAAA,CAWzC,GAGX,EAAA,CACE,OAAA,GAAsB,EAAA,GAExB,IAAI,SAAY,EAAS,IAAA,CACvB,IAAM,EAAiD,EAAA,CACvD,GAAU,EAAO,iBAAiB,QAAS,EAAQ,CAAE,KAAA,CAAM,EAAA,CAAA,CAE3D,IAAM,EAAW,OAAO,OAAO,EAAA,CAAkB,IAAK,GAC/C,GASD,EAAM,MAAQ,EAAc,IAAI,EAAM,KAAA,CACjC,EAAgD,CAAC,EAAA,CAAQ,CAC9D,OAAA,EAAA,CAAA,CACC,MAAA,CAAO,MACR,EAAU,KAAK,EAAA,CACR,GAAA,CAbF,EAAA,CAkBL,EAAO,OAAO,KAAK,EAAA,CACzB,QAAQ,IAAI,EAAA,CACT,KAAM,GACE,EAAQ,QAAQ,EAAK,EAAU,KACpC,EAAI,EAAK,IAAU,EACZ,GACN,EAAA,CAAA,CAAA,CAEJ,KAAK,EAAA,CACL,MAAO,GAAA,CAEN,EAAU,QAAS,GAAA,CACjB,EAAS,SAAW,EAAS,SAAA,EAAA,CAE/B,EAAO,EAAA,EAAA,CAER,YAAA,CACC,GAAU,EAAO,oBAAoB,QAAS,EAAA,EAAA,EAAA,CAAA,OAAA,KAAA,wBAAA,KAAA,eAAA,KAAA"}