{"version":3,"names":["isServer","createEffect","createMemo","createSignal","loadImage","src","referrerPolicy","crossOrigin","Promise","resolve","reject","image","window","Image","onload","onerror","Error","undefined","complete","naturalWidth","useImageLoadingStatus","options","status","setStatus","name","ownedWrite","probe","effect","error","_err","cleanup"],"sources":["use-image-loading-status.ts"],"sourcesContent":["import { isServer } from \"@solidjs/web\";\nimport {\n\ttype Accessor,\n\tcreateEffect,\n\tcreateMemo,\n\tcreateSignal,\n} from \"solid-js\";\n\n/**\n * Image loading status reported by the probe. Mirrors Base UI React's\n * `ImageLoadingStatus` union (`packages/react/src/avatar/image/useImageLoadingStatus.ts`).\n *\n * It survives the move to async-native (`solidify.md` §4) because the Avatar\n * compound coordinates `<Avatar.Image>` and its sibling `<Avatar.Fallback>`\n * through a shared status signal in root context — sibling parts, not nested\n * subtrees, so a `<Loading>`/`<Errored>` boundary can't replace it. The union\n * is a *derived view* of the async probe below, not a hand-rolled state\n * machine: a failed image is a domain state (→ fallback), not an exception\n * that should escape to `<Errored>` — the same messages-vs-exceptions split\n * `createValidator` draws.\n */\nexport type ImageLoadingStatus = \"idle\" | \"loading\" | \"loaded\" | \"error\";\n\n/**\n * Inputs to {@link useImageLoadingStatus}. Each entry is an accessor so the\n * primitive can react to upstream prop changes without being re-created.\n * Matching the React helper, only `src`, `referrerPolicy`, and `crossOrigin`\n * participate in re-probing.\n */\nexport interface UseImageLoadingStatusOptions {\n\tsrc: Accessor<string | undefined>;\n\treferrerPolicy: Accessor<string | undefined>;\n\tcrossOrigin: Accessor<string | undefined>;\n}\n\n/**\n * Probe a single image off-screen via `new window.Image()`, returning a\n * Promise that resolves once the resource loads and rejects when it errors.\n * This lets a consumer decide whether to actually mount a real `<img>` based\n * on the outcome — avoiding the broken-image flash that happens when the\n * visible `<img>` itself is asked to load a 404.\n *\n * The Promise is the unit the async `createMemo` in {@link useImageLoadingStatus}\n * hands to the reactive graph; recomputing the memo (on a `src` change) simply\n * abandons the previous probe — its eventual `onload`/`onerror` resolves an\n * orphaned Promise nobody is awaiting, so there's no manual \"is this still the\n * active probe?\" latch to maintain.\n */\nfunction loadImage(\n\tsrc: string,\n\treferrerPolicy: string | undefined,\n\tcrossOrigin: string | undefined,\n): Promise<void> {\n\treturn new Promise<void>((resolve, reject) => {\n\t\tconst image = new window.Image();\n\t\timage.onload = () => resolve();\n\t\timage.onerror = () => reject(new Error(`Failed to load image: ${src}`));\n\t\tif (referrerPolicy) {\n\t\t\timage.referrerPolicy = referrerPolicy;\n\t\t}\n\t\t// `crossOrigin` stays camelCase here — we're writing to a DOM property\n\t\t// on the probe element, not a JSX attribute. The JSX prop is\n\t\t// `crossorigin`; the IDL property is `crossOrigin`.\n\t\timage.crossOrigin =\n\t\t\tcrossOrigin === undefined ? null : (crossOrigin as string | null);\n\t\timage.src = src;\n\n\t\t// Fast path for cached/decoded images — `complete` is synchronously\n\t\t// true if the resource is already in the browser cache, in which case\n\t\t// `onload`/`onerror` may never fire.\n\t\tif (image.complete) {\n\t\t\tif (image.naturalWidth > 0) {\n\t\t\t\tresolve();\n\t\t\t} else {\n\t\t\t\treject(new Error(`Failed to load image: ${src}`));\n\t\t\t}\n\t\t}\n\t});\n}\n\n/**\n * Runs a standalone image probe whose async outcome drives a discrete\n * `ImageLoadingStatus` accessor.\n *\n * Solid 2 shape (`solidify.md` §4 — RFC 05 async-native):\n *\n * - `probe` is an async `createMemo` returning {@link loadImage}'s Promise.\n *   It re-runs whenever `src`/`referrerPolicy`/`crossOrigin` flip; the prior\n *   in-flight probe is discarded by the graph (last-write-wins), so no manual\n *   `isActive` latch is needed.\n * - The bundled `createEffect(compute, { effect, error })` reads `probe()` in\n *   its compute half. While the Promise is pending the compute *suspends* —\n *   the `effect` (apply) half does not run, and no `ASYNC_OUTSIDE_LOADING_BOUNDARY`\n *   diagnostic fires (verified: a suspended *computation* without a `<Loading>`\n *   ancestor is silent; only a pending *read in render* requires the boundary).\n *   On resolve the apply half lands `\"loaded\"`; on reject the `error` half\n *   lands `\"error\"` — caught from the compute phase per RFC 01's bundle\n *   contract, so the rejection is handled here rather than escaping upward.\n * - A separate split effect tracks the probe inputs and lands `\"loading\"`\n *   synchronously the moment they change to a non-empty `src` (the bundle\n *   effect can't — it's suspended until the probe settles). An empty `src`\n *   lands `\"error\"` directly, preserving the React helper's \"no loading flash\n *   for a missing src\" behaviour (the memo also rejects for empty `src`, so\n *   the two agree).\n *\n * The returned `status` accessor is a plain signal read; callers can drive\n * further effects off it (mirror into a root context, forward into a consumer\n * callback).\n */\nexport function useImageLoadingStatus(\n\toptions: UseImageLoadingStatusOptions,\n): Accessor<ImageLoadingStatus> {\n\t// `ownedWrite: true` — `setStatus` is called from the apply/error halves of\n\t// `createEffect` (owned scope). Without it, dev-mode emits\n\t// SIGNAL_WRITE_IN_OWNED_SCOPE.\n\tconst [status, setStatus] = createSignal<ImageLoadingStatus>(\"idle\", {\n\t\tname: \"useImageLoadingStatus.status\",\n\t\townedWrite: true,\n\t});\n\n\t// The RC's synchronous server renderer evaluates memos during render. Image\n\t// probing is browser-only; keep the initial idle status so the fallback is\n\t// rendered on the server and the client owns the first real probe.\n\tif (isServer) return status;\n\n\t// Async probe — source of truth. A non-empty `src` resolves on load /\n\t// rejects on error; an empty `src` is a domain \"error\" state, surfaced as a\n\t// rejected Promise so the bundle's `error` half routes it to `\"error\"`.\n\tconst probe = createMemo(\n\t\t() => {\n\t\t\tconst src = options.src();\n\t\t\tif (!src) {\n\t\t\t\treturn Promise.reject(new Error(\"Avatar image: missing src\"));\n\t\t\t}\n\t\t\treturn loadImage(src, options.referrerPolicy(), options.crossOrigin());\n\t\t},\n\t\t{ name: \"useImageLoadingStatus.probe\" },\n\t);\n\n\t// Land \"loading\" (or \"error\" for a missing src) synchronously when the\n\t// inputs change. The bundle effect below is suspended while the probe is\n\t// pending, so it can't surface the in-flight state itself.\n\tcreateEffect(\n\t\t() => options.src(),\n\t\t(src) => {\n\t\t\tsetStatus(src ? \"loading\" : \"error\");\n\t\t},\n\t);\n\n\t// Resolve the settled probe into the terminal status. Reading `probe()`\n\t// suspends the compute while pending; the apply half fires only once the\n\t// image has loaded, the error half only on failure.\n\tcreateEffect(\n\t\t() => {\n\t\t\tprobe();\n\t\t\treturn undefined;\n\t\t},\n\t\t{\n\t\t\teffect: () => {\n\t\t\t\tsetStatus(\"loaded\");\n\t\t\t},\n\t\t\terror: (_err, cleanup) => {\n\t\t\t\tsetStatus(\"error\");\n\t\t\t\tcleanup();\n\t\t\t},\n\t\t},\n\t);\n\n\treturn status;\n}\n"],"mappings":"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","ignoreList":[]}