{"version":3,"file":"useContrastMode.cjs","names":["Tokens","_interopRequireWildcard","require","_react","_hexToRgb","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","ContrastModeContext","exports","createContext","contrastMode","defaultContrast","useContrastModeContext","useContext","hueNeutral50Rgb","hexToRgb","HueNeutral50","asFormattedString","isTransparentColor","color","normalizeRgbaToRgb","rgba","replace","getElementComputedBackgroundColor","element","window","getComputedStyle","backgroundColor","normalizeBackgroundColor","bgColor","test","normalizedColor","defaultParentBackgroundColor","getParentElement","parentElement","root","getRootNode","ShadowRoot","host","HTMLElement","getBackgroundColor","deriveContrastMode","useContrastMode","explicitContrastMode","contrastContainerRef","useRef","existingContrastMode","parentBackgroundColor","setParentBackgroundColor","useState","detectedContrastMode","setDetectedContrastMode","updateBackgroundColor","useCallback","newBgColor","current","useLayoutEffect","observer","MutationObserver","htmlElement","document","documentElement","observe","attributes","attributeFilter","head","childList","subtree","onTransitionEnd","event","TransitionEvent","propertyName","eventRoot","addEventListener","removeEventListener","disconnect"],"sources":["../../src/useContrastMode.tsx"],"sourcesContent":["/*!\n * Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.\n * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the \"License.\")\n *\n * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *\n * See the License for the specific language governing permissions and limitations under the License.\n */\n\nimport * as Tokens from \"@okta/odyssey-design-tokens\";\nimport {\n  createContext,\n  type RefObject,\n  useCallback,\n  useContext,\n  useLayoutEffect,\n  useRef,\n  useState,\n} from \"react\";\n\nimport { hexToRgb } from \"./hexToRgb.js\";\n\nexport type ContrastMode = \"lowContrast\" | \"highContrast\";\nexport type ContrastModeContextType = {\n  /**\n   * Odyssey's app wrapper element: the contrast and height container `OdysseyThemeProvider` renders. `useAppElementContainerQuery` observes it so container queries track the space Odyssey actually occupies. Absent outside a provider, and `current` stays `null` when the provider renders with `hasWrapperElement={false}`.\n   */\n  contrastContainerRef?: RefObject<HTMLDivElement>;\n  contrastMode: ContrastMode;\n};\n\nexport const ContrastModeContext = createContext<ContrastModeContextType>({\n  contrastMode: \"lowContrast\",\n});\n\nexport const defaultContrast = \"lowContrast\";\n\nexport const useContrastModeContext = () => useContext(ContrastModeContext);\n\nexport const hueNeutral50Rgb = hexToRgb(Tokens.HueNeutral50).asFormattedString;\n\nexport const isTransparentColor = (color: string) =>\n  color === \"rgba(0, 0, 0, 0)\" || color === \"transparent\";\n\nexport const normalizeRgbaToRgb = (rgba: string) =>\n  rgba.replace(/rgba\\((\\d+),\\s*(\\d+),\\s*(\\d+),\\s*[\\d.]+\\)/, \"rgb($1, $2, $3)\");\n\nexport const getElementComputedBackgroundColor = (\n  element: HTMLElement,\n): string => window.getComputedStyle(element).backgroundColor;\n\nexport const normalizeBackgroundColor = (bgColor: string): string => {\n  if (/rgba\\((\\d+),\\s*(\\d+),\\s*(\\d+),\\s*[\\d.]+\\)/.test(bgColor)) {\n    const normalizedColor = normalizeRgbaToRgb(bgColor);\n    return normalizedColor === hueNeutral50Rgb\n      ? Tokens.HueNeutral50\n      : normalizedColor;\n  }\n\n  return bgColor === hueNeutral50Rgb ? Tokens.HueNeutral50 : bgColor;\n};\n\n/** Default background color when none is detected: HueNeutral50 (gray = highContrast). */\nexport const defaultParentBackgroundColor = Tokens.HueNeutral50;\n\n/**\n * Returns the parent element, crossing shadow DOM boundaries when necessary. When `parentElement` is null (e.g., at a shadow root), this checks if the element is inside a ShadowRoot and jumps to the host element to continue traversal.\n */\nconst getParentElement = (element: HTMLElement): HTMLElement | null => {\n  if (element.parentElement) {\n    return element.parentElement;\n  }\n\n  const root = element.getRootNode();\n  if (root instanceof ShadowRoot && root.host instanceof HTMLElement) {\n    return root.host;\n  }\n\n  return null;\n};\n\n/**\n * Determines the effective background color of an element.\n *\n * @param element - The HTML element to check.\n * @returns The effective background color. Returns  defaultParentBackgroundColor if no non-transparent background is found.\n *\n * Note:\n * - Low contrast mode is used for white background (HueNeutralWhite).\n * - High contrast mode is used for gray background (defaultParentBackgroundColor = HueNeutral50).\n * - Crosses shadow DOM boundaries via `getRootNode().host` to detect backgrounds set outside of shadow roots.\n */\nexport const getBackgroundColor = (element: HTMLElement | null): string => {\n  while (element) {\n    const bgColor = getElementComputedBackgroundColor(element);\n    if (!isTransparentColor(bgColor)) {\n      return normalizeBackgroundColor(bgColor);\n    }\n    element = getParentElement(element);\n  }\n  return defaultParentBackgroundColor; // Default to gray/high contrast if no background color is found\n};\n\nexport const deriveContrastMode = (bgColor: string): ContrastMode =>\n  bgColor === Tokens.HueNeutral50 ? \"highContrast\" : \"lowContrast\";\n\ntype UseContrastModeProps = {\n  contrastMode?: ContrastMode;\n};\n\nexport const useContrastMode = ({\n  contrastMode: explicitContrastMode,\n}: UseContrastModeProps) => {\n  const contrastContainerRef = useRef<HTMLDivElement>(null);\n  const { contrastMode: existingContrastMode } = useContrastModeContext();\n\n  const [parentBackgroundColor, setParentBackgroundColor] = useState(\n    defaultParentBackgroundColor,\n  );\n  const [detectedContrastMode, setDetectedContrastMode] =\n    useState<ContrastMode>(() => existingContrastMode);\n\n  const contrastMode = explicitContrastMode ?? detectedContrastMode;\n\n  const updateBackgroundColor = useCallback(() => {\n    const newBgColor = getBackgroundColor(contrastContainerRef.current);\n    setParentBackgroundColor(newBgColor);\n    setDetectedContrastMode(deriveContrastMode(newBgColor));\n  }, []);\n\n  useLayoutEffect(() => {\n    if (explicitContrastMode) return;\n\n    const observer = new MutationObserver(updateBackgroundColor);\n\n    // In shadow DOM contexts, document.documentElement and document.head may not be accessible. Guard against null to prevent observer.observe(null) from throwing.\n    const htmlElement = document.documentElement;\n    if (htmlElement) {\n      observer.observe(htmlElement, {\n        attributes: true,\n        attributeFilter: [\"class\", \"style\"],\n      });\n    }\n\n    if (document.head) {\n      observer.observe(document.head, {\n        childList: true,\n        subtree: true,\n      });\n    }\n\n    const onTransitionEnd = (event: Event) => {\n      if (\n        event instanceof TransitionEvent &&\n        event.propertyName === \"background-color\"\n      ) {\n        updateBackgroundColor();\n      }\n    };\n\n    // Attach the transitionend listener to the element's root node so it works inside shadow DOM (where events don't bubble to `document`).\n    const eventRoot = contrastContainerRef.current?.getRootNode() ?? document;\n    eventRoot.addEventListener(\"transitionend\", onTransitionEnd);\n    updateBackgroundColor();\n\n    return () => {\n      eventRoot.removeEventListener(\"transitionend\", onTransitionEnd);\n      observer.disconnect();\n    };\n  }, [explicitContrastMode, updateBackgroundColor]);\n\n  return {\n    contrastContainerRef,\n    contrastMode,\n    parentBackgroundColor,\n  };\n};\n"],"mappings":";;;;;;AAYA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AAUA,IAAAE,SAAA,GAAAF,OAAA;AAAyC,SAAAD,wBAAAI,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAN,uBAAA,YAAAA,CAAAI,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAvBzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAwBO,MAAMkB,mBAAmB,GAAAC,OAAA,CAAAD,mBAAA,GAAG,IAAAE,oBAAa,EAA0B;EACxEC,YAAY,EAAE;AAChB,CAAC,CAAC;AAEK,MAAMC,eAAe,GAAAH,OAAA,CAAAG,eAAA,GAAG,aAAa;AAErC,MAAMC,sBAAsB,GAAGA,CAAA,KAAM,IAAAC,iBAAU,EAACN,mBAAmB,CAAC;AAACC,OAAA,CAAAI,sBAAA,GAAAA,sBAAA;AAErE,MAAME,eAAe,GAAAN,OAAA,CAAAM,eAAA,GAAG,IAAAC,kBAAQ,EAAChC,MAAM,CAACiC,YAAY,CAAC,CAACC,iBAAiB;AAEvE,MAAMC,kBAAkB,GAAIC,KAAa,IAC9CA,KAAK,KAAK,kBAAkB,IAAIA,KAAK,KAAK,aAAa;AAACX,OAAA,CAAAU,kBAAA,GAAAA,kBAAA;AAEnD,MAAME,kBAAkB,GAAIC,IAAY,IAC7CA,IAAI,CAACC,OAAO,CAAC,2CAA2C,EAAE,iBAAiB,CAAC;AAACd,OAAA,CAAAY,kBAAA,GAAAA,kBAAA;AAExE,MAAMG,iCAAiC,GAC5CC,OAAoB,IACTC,MAAM,CAACC,gBAAgB,CAACF,OAAO,CAAC,CAACG,eAAe;AAACnB,OAAA,CAAAe,iCAAA,GAAAA,iCAAA;AAEvD,MAAMK,wBAAwB,GAAIC,OAAe,IAAa;EACnE,IAAI,2CAA2C,CAACC,IAAI,CAACD,OAAO,CAAC,EAAE;IAC7D,MAAME,eAAe,GAAGX,kBAAkB,CAACS,OAAO,CAAC;IACnD,OAAOE,eAAe,KAAKjB,eAAe,GACtC/B,MAAM,CAACiC,YAAY,GACnBe,eAAe;EACrB;EAEA,OAAOF,OAAO,KAAKf,eAAe,GAAG/B,MAAM,CAACiC,YAAY,GAAGa,OAAO;AACpE,CAAC;AAACrB,OAAA,CAAAoB,wBAAA,GAAAA,wBAAA;AAGK,MAAMI,4BAA4B,GAAAxB,OAAA,CAAAwB,4BAAA,GAAGjD,MAAM,CAACiC,YAAY;AAK/D,MAAMiB,gBAAgB,GAAIT,OAAoB,IAAyB;EACrE,IAAIA,OAAO,CAACU,aAAa,EAAE;IACzB,OAAOV,OAAO,CAACU,aAAa;EAC9B;EAEA,MAAMC,IAAI,GAAGX,OAAO,CAACY,WAAW,CAAC,CAAC;EAClC,IAAID,IAAI,YAAYE,UAAU,IAAIF,IAAI,CAACG,IAAI,YAAYC,WAAW,EAAE;IAClE,OAAOJ,IAAI,CAACG,IAAI;EAClB;EAEA,OAAO,IAAI;AACb,CAAC;AAaM,MAAME,kBAAkB,GAAIhB,OAA2B,IAAa;EACzE,OAAOA,OAAO,EAAE;IACd,MAAMK,OAAO,GAAGN,iCAAiC,CAACC,OAAO,CAAC;IAC1D,IAAI,CAACN,kBAAkB,CAACW,OAAO,CAAC,EAAE;MAChC,OAAOD,wBAAwB,CAACC,OAAO,CAAC;IAC1C;IACAL,OAAO,GAAGS,gBAAgB,CAACT,OAAO,CAAC;EACrC;EACA,OAAOQ,4BAA4B;AACrC,CAAC;AAACxB,OAAA,CAAAgC,kBAAA,GAAAA,kBAAA;AAEK,MAAMC,kBAAkB,GAAIZ,OAAe,IAChDA,OAAO,KAAK9C,MAAM,CAACiC,YAAY,GAAG,cAAc,GAAG,aAAa;AAACR,OAAA,CAAAiC,kBAAA,GAAAA,kBAAA;AAM5D,MAAMC,eAAe,GAAGA,CAAC;EAC9BhC,YAAY,EAAEiC;AACM,CAAC,KAAK;EAC1B,MAAMC,oBAAoB,GAAG,IAAAC,aAAM,EAAiB,IAAI,CAAC;EACzD,MAAM;IAAEnC,YAAY,EAAEoC;EAAqB,CAAC,GAAGlC,sBAAsB,CAAC,CAAC;EAEvE,MAAM,CAACmC,qBAAqB,EAAEC,wBAAwB,CAAC,GAAG,IAAAC,eAAQ,EAChEjB,4BACF,CAAC;EACD,MAAM,CAACkB,oBAAoB,EAAEC,uBAAuB,CAAC,GACnD,IAAAF,eAAQ,EAAe,MAAMH,oBAAoB,CAAC;EAEpD,MAAMpC,YAAY,GAAGiC,oBAAoB,IAAIO,oBAAoB;EAEjE,MAAME,qBAAqB,GAAG,IAAAC,kBAAW,EAAC,MAAM;IAC9C,MAAMC,UAAU,GAAGd,kBAAkB,CAACI,oBAAoB,CAACW,OAAO,CAAC;IACnEP,wBAAwB,CAACM,UAAU,CAAC;IACpCH,uBAAuB,CAACV,kBAAkB,CAACa,UAAU,CAAC,CAAC;EACzD,CAAC,EAAE,EAAE,CAAC;EAEN,IAAAE,sBAAe,EAAC,MAAM;IACpB,IAAIb,oBAAoB,EAAE;IAE1B,MAAMc,QAAQ,GAAG,IAAIC,gBAAgB,CAACN,qBAAqB,CAAC;IAG5D,MAAMO,WAAW,GAAGC,QAAQ,CAACC,eAAe;IAC5C,IAAIF,WAAW,EAAE;MACfF,QAAQ,CAACK,OAAO,CAACH,WAAW,EAAE;QAC5BI,UAAU,EAAE,IAAI;QAChBC,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO;MACpC,CAAC,CAAC;IACJ;IAEA,IAAIJ,QAAQ,CAACK,IAAI,EAAE;MACjBR,QAAQ,CAACK,OAAO,CAACF,QAAQ,CAACK,IAAI,EAAE;QAC9BC,SAAS,EAAE,IAAI;QACfC,OAAO,EAAE;MACX,CAAC,CAAC;IACJ;IAEA,MAAMC,eAAe,GAAIC,KAAY,IAAK;MACxC,IACEA,KAAK,YAAYC,eAAe,IAChCD,KAAK,CAACE,YAAY,KAAK,kBAAkB,EACzC;QACAnB,qBAAqB,CAAC,CAAC;MACzB;IACF,CAAC;IAGD,MAAMoB,SAAS,GAAG5B,oBAAoB,CAACW,OAAO,EAAEnB,WAAW,CAAC,CAAC,IAAIwB,QAAQ;IACzEY,SAAS,CAACC,gBAAgB,CAAC,eAAe,EAAEL,eAAe,CAAC;IAC5DhB,qBAAqB,CAAC,CAAC;IAEvB,OAAO,MAAM;MACXoB,SAAS,CAACE,mBAAmB,CAAC,eAAe,EAAEN,eAAe,CAAC;MAC/DX,QAAQ,CAACkB,UAAU,CAAC,CAAC;IACvB,CAAC;EACH,CAAC,EAAE,CAAChC,oBAAoB,EAAES,qBAAqB,CAAC,CAAC;EAEjD,OAAO;IACLR,oBAAoB;IACpBlC,YAAY;IACZqC;EACF,CAAC;AACH,CAAC;AAACvC,OAAA,CAAAkC,eAAA,GAAAA,eAAA","ignoreList":[]}