{"version":3,"file":"react-svg.cjs","names":["React"],"sources":["../src/owner-window.ts","../src/ReactSVG.tsx"],"sourcesContent":["// Hat-tip: https://github.com/mui/material-ui/tree/master/packages/mui-utils/src.\n\nconst ownerWindow = (node?: Node | null) => {\n  const doc = node?.ownerDocument || document\n  return doc.defaultView || window\n}\n\nexport default ownerWindow\n","import { SVGInjector } from '@tanem/svg-injector'\nimport * as React from 'react'\n\nimport ownerWindow from './owner-window'\nimport type { Props, WrapperType } from './types'\n\nconst svgNamespace = 'http://www.w3.org/2000/svg'\nconst xlinkNamespace = 'http://www.w3.org/1999/xlink'\n\n// Random prefix avoids ID collisions when multiple copies of react-svg are\n// bundled (e.g. microfrontends). The counter ensures each component instance\n// within the same bundle gets a unique ID.\nconst idPrefix = `react-svg-${Math.random().toString(36).slice(2, 6)}`\nlet idCounter = 0\n\n// forwardRef is still required: function components only accept a `ref` prop\n// directly from React 19 onwards, and the supported floor is React 16.8.\n//\n// The type annotation keeps declaration emit from inlining the interfaces\n// `Props` is built from, which aren't exported.\n// eslint-disable-next-line @eslint-react/no-forward-ref\nexport const ReactSVG: React.ForwardRefExoticComponent<\n  Props & React.RefAttributes<WrapperType>\n> = React.forwardRef<WrapperType, Props>(\n  (\n    {\n      afterInjection = () => undefined,\n      beforeInjection = () => undefined,\n      desc = '',\n      evalScripts = 'never',\n      fallback: Fallback,\n      httpRequestWithCredentials = false,\n      loading: Loading,\n      loadingDelay = 0,\n      onError = () => undefined,\n      renumerateIRIElements = true,\n      src,\n      title = '',\n      useRequestCache = true,\n      wrapper = 'div',\n      ...rest\n    },\n    forwardedRef,\n  ) => {\n    const [hasError, setHasError] = React.useState(false)\n    const [isLoading, setIsLoading] = React.useState(true)\n\n    // `loading` is held back until the delay elapses, so an injection that\n    // resolves sooner - a warm cache, localhost, a file:// read - never paints\n    // an indicator at all. The initial value has to account for the delay\n    // rather than start false: effects run after paint, so initialising to\n    // false would cost the default a frame without the loader.\n    const [hasLoadingDelayElapsed, setHasLoadingDelayElapsed] = React.useState(\n      loadingDelay <= 0,\n    )\n\n    // Bumped whenever an injection starts, so the delay effect below can tell\n    // one injection from the next. `isLoading` can't carry that on its own: a\n    // re-injection that begins while the previous request is still in flight\n    // leaves it true throughout, so with an unchanged `loadingDelay` neither of\n    // that effect's other dependencies would change and the timer would never\n    // re-arm.\n    //\n    // Skipped for the first injection, so mount still settles in one render -\n    // every value that effect writes already holds its default there.\n    const [injectionId, setInjectionId] = React.useState(0)\n    const hasInjectedRef = React.useRef(false)\n\n    const reactWrapperRef = React.useRef<WrapperType | null>(null)\n\n    // The callbacks are read through a ref so that changing them - which inline\n    // arrow props do on every render - doesn't tear down and re-run the\n    // injection. Declared before the injection effect so it always holds the\n    // current props by the time that effect runs.\n    const callbacksRef = React.useRef({\n      afterInjection,\n      beforeInjection,\n      onError,\n    })\n    React.useEffect(() => {\n      callbacksRef.current = { afterInjection, beforeInjection, onError }\n    })\n\n    // Read through a ref for the same reason, and declared here so it is\n    // current by the time the injection effect runs: that effect has to clear\n    // the elapsed flag, but listing `loadingDelay` as a dependency would make\n    // changing the delay re-inject.\n    const loadingDelayRef = React.useRef(loadingDelay)\n    React.useEffect(() => {\n      loadingDelayRef.current = loadingDelay\n    })\n\n    const refCallback = React.useCallback(\n      (reactWrapper: WrapperType | null) => {\n        reactWrapperRef.current = reactWrapper\n        if (typeof forwardedRef === 'function') {\n          forwardedRef(reactWrapper)\n        } else if (forwardedRef) {\n          forwardedRef.current = reactWrapper\n        }\n      },\n      [forwardedRef],\n    )\n\n    // Only props that affect the injected SVG are listed as dependencies. Props\n    // spread onto the React wrapper (className, style, event handlers, ...) are\n    // applied by React itself and don't warrant a re-injection.\n    React.useEffect(() => {\n      const reactWrapper = reactWrapperRef.current\n\n      /* istanbul ignore next */\n      if (!(reactWrapper instanceof ownerWindow(reactWrapper).Node)) {\n        return\n      }\n\n      // Guards against a teardown - unmount, or a dependency change that starts\n      // a fresh injection - landing while the previous injection is still in\n      // flight. The stale callbacks must not touch state, but errors are still\n      // reported.\n      let isActive = true\n      let nonReactWrapper: WrapperType | null = null\n\n      const removeSVG = () => {\n        if (nonReactWrapper?.parentNode) {\n          nonReactWrapper.parentNode.removeChild(nonReactWrapper)\n          nonReactWrapper = null\n        }\n      }\n\n      // A new injection is starting, so any result from the previous one is\n      // stale. On mount the three flags already hold these defaults and React\n      // bails out - and `injectionId` is skipped there for the same reason - so\n      // this only re-renders when a dependency actually changed.\n      //\n      // The elapsed flag has to be cleared here rather than left to the delay\n      // effect below: that effect only reacts once this render has committed,\n      // and the render in between would still see a flag left true by the\n      // previous injection and mount `loading` regardless of the delay. It\n      // takes `loadingDelay <= 0` rather than a plain false for the reason the\n      // initial state does - the default would otherwise lose a frame to a\n      // re-injection.\n      /* eslint-disable @eslint-react/set-state-in-effect */\n      setHasError(false)\n      setIsLoading(true)\n      setHasLoadingDelayElapsed(loadingDelayRef.current <= 0)\n      if (hasInjectedRef.current) {\n        setInjectionId((id) => id + 1)\n      } else {\n        hasInjectedRef.current = true\n      }\n      /* eslint-enable @eslint-react/set-state-in-effect */\n\n      let nonReactTarget: WrapperType\n\n      if (wrapper === 'svg') {\n        nonReactWrapper = document.createElementNS(svgNamespace, wrapper)\n        nonReactWrapper.setAttribute('xmlns', svgNamespace)\n        nonReactWrapper.setAttribute('xmlns:xlink', xlinkNamespace)\n        nonReactTarget = document.createElementNS(svgNamespace, wrapper)\n      } else {\n        nonReactWrapper = document.createElement(wrapper)\n        nonReactTarget = document.createElement(wrapper)\n      }\n\n      nonReactWrapper.appendChild(nonReactTarget)\n      nonReactTarget.dataset.src = src\n\n      reactWrapper.appendChild(nonReactWrapper)\n\n      const handleError = (error: unknown) => {\n        removeSVG()\n        if (isActive) {\n          setHasError(true)\n          setIsLoading(false)\n        }\n        callbacksRef.current.onError(error)\n      }\n\n      const afterEach = (error: Error | null, svg?: SVGSVGElement) => {\n        if (error) {\n          handleError(error)\n          return\n        }\n\n        if (!isActive) {\n          return\n        }\n\n        setIsLoading(false)\n\n        try {\n          callbacksRef.current.afterInjection(svg!)\n        } catch (afterInjectionError) {\n          handleError(afterInjectionError)\n        }\n      }\n\n      // WAI best practice: SVGs need role=\"img\" plus aria-labelledby/\n      // aria-describedby pointing to <title>/<desc> element IDs for screen\n      // readers to announce them. svg-injector copies the HTML title\n      // *attribute* (tooltip) but doesn't create SVG-namespace child\n      // elements or ARIA linkage, so we handle that here.\n      const beforeEach = (svg: SVGSVGElement): void => {\n        svg.setAttribute('role', 'img')\n\n        const ariaLabelledBy: string[] = []\n        const ariaDescribedBy: string[] = []\n\n        if (title) {\n          const originalTitle = svg.querySelector(':scope > title')\n          if (originalTitle) {\n            svg.removeChild(originalTitle)\n          }\n          const titleId = `${idPrefix}-title-${++idCounter}`\n          // createElementNS is required: createElement would produce an\n          // HTML-namespace node that screen readers ignore inside SVG.\n          const newTitle = document.createElementNS(svgNamespace, 'title')\n          newTitle.id = titleId\n          newTitle.textContent = title\n          svg.prepend(newTitle)\n          ariaLabelledBy.push(titleId)\n        }\n\n        if (desc) {\n          const originalDesc = svg.querySelector(':scope > desc')\n          if (originalDesc) {\n            svg.removeChild(originalDesc)\n          }\n          const descId = `${idPrefix}-desc-${++idCounter}`\n          const newDesc = document.createElementNS(svgNamespace, 'desc')\n          newDesc.id = descId\n          newDesc.textContent = desc\n          const existingTitle = svg.querySelector(':scope > title')\n          if (existingTitle) {\n            existingTitle.after(newDesc)\n          } else {\n            svg.prepend(newDesc)\n          }\n          ariaDescribedBy.push(descId)\n        }\n\n        if (ariaLabelledBy.length > 0) {\n          svg.setAttribute('aria-labelledby', ariaLabelledBy.join(' '))\n        }\n\n        if (ariaDescribedBy.length > 0) {\n          svg.setAttribute('aria-describedby', ariaDescribedBy.join(' '))\n        }\n\n        try {\n          callbacksRef.current.beforeInjection(svg)\n        } catch (error) {\n          handleError(error)\n        }\n      }\n\n      SVGInjector(nonReactTarget, {\n        afterEach,\n        beforeEach,\n        cacheRequests: useRequestCache,\n        evalScripts,\n        httpRequestWithCredentials,\n        renumerateIRIElements,\n      })\n\n      return () => {\n        isActive = false\n        removeSVG()\n      }\n    }, [\n      desc,\n      evalScripts,\n      httpRequestWithCredentials,\n      renumerateIRIElements,\n      src,\n      title,\n      useRequestCache,\n      wrapper,\n    ])\n\n    // Keyed on `injectionId` rather than living in the injection effect, so\n    // that changing `loadingDelay` restarts the timer without re-running the\n    // injection. Only the timer lives here; a re-injection's flag is cleared by\n    // the injection effect itself, which is a render earlier than this can run.\n    //\n    // `isLoading` is a dependency so the timer is cleared once an injection\n    // finishes, and `injectionId` so it re-arms for every injection - including\n    // one that starts while the previous request is still in flight, which\n    // leaves `isLoading` true the whole way through.\n    React.useEffect(() => {\n      if (!isLoading) {\n        return\n      }\n\n      /* eslint-disable @eslint-react/set-state-in-effect */\n      if (loadingDelay <= 0) {\n        setHasLoadingDelayElapsed(true)\n        return\n      }\n\n      setHasLoadingDelayElapsed(false)\n      /* eslint-enable @eslint-react/set-state-in-effect */\n\n      const timeoutId = setTimeout(() => {\n        setHasLoadingDelayElapsed(true)\n      }, loadingDelay)\n\n      return () => {\n        clearTimeout(timeoutId)\n      }\n    }, [injectionId, isLoading, loadingDelay])\n\n    const Wrapper = wrapper\n\n    return (\n      <Wrapper\n        {...rest}\n        ref={refCallback}\n        {...(wrapper === 'svg'\n          ? {\n              xmlns: svgNamespace,\n              xmlnsXlink: xlinkNamespace,\n            }\n          : {})}\n      >\n        {isLoading && hasLoadingDelayElapsed && Loading && <Loading />}\n        {hasError && Fallback && <Fallback />}\n      </Wrapper>\n    )\n  },\n)\n\nReactSVG.displayName = 'ReactSVG'\n"],"mappings":"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"}