{"version":3,"file":"index.mjs","sources":["../../src/index.tsx"],"sourcesContent":["import * as React from 'react'\nimport useKey from '@accessible/use-key'\nimport useConditionalFocus from '@accessible/use-conditional-focus'\nimport useSwitch from '@react-hook/switch'\nimport useMergedRef from '@react-hook/merged-ref'\nimport usePrevious from '@react-hook/previous'\nimport useId from '@accessible/use-id'\nimport {useA11yButton} from '@accessible/button'\nimport Portalize from 'react-portalize'\nimport type {PortalizeProps} from 'react-portalize'\nimport clsx from 'clsx'\n\nconst DisclosureContext = React.createContext<DisclosureContextValue>({\n  isOpen: false,\n  open: noop,\n  close: noop,\n  toggle: noop,\n})\n\n/**\n * This hook provides the current value of the disclosure's context object\n */\nexport function useDisclosure() {\n  return React.useContext(DisclosureContext)\n}\n\n/**\n * This component creates the context for your disclosure target and trigger\n * and contains some configuration options.\n */\nexport function Disclosure({\n  id,\n  open,\n  defaultOpen,\n  onChange = noop,\n  children,\n}: DisclosureProps) {\n  id = useId(id)\n  const [isOpen, toggle] = useSwitch(defaultOpen, open, onChange)\n\n  const context = React.useMemo(\n    () => ({\n      id,\n      open: toggle.on,\n      close: toggle.off,\n      toggle,\n      isOpen,\n    }),\n    [id, isOpen, toggle]\n  )\n\n  return (\n    <DisclosureContext.Provider value={context}>\n      {children}\n    </DisclosureContext.Provider>\n  )\n}\n\nfunction portalize(\n  Component: React.ReactElement,\n  portal: boolean | undefined | null | string | Omit<PortalizeProps, 'children'>\n) {\n  if (!portal) return Component\n  const props: PortalizeProps = {children: Component}\n  if (typeof portal === 'string') props.container = portal\n  else Object.assign(props, portal)\n  return React.createElement(Portalize, props)\n}\n\n/**\n * A React hook for creating a headless disclosure target to [WAI-ARIA authoring practices](https://www.w3.org/TR/wai-aria-practices-1.1/examples/disclosure/disclosure-faq.html).\n *\n * @param target A React ref or HTML element\n * @param options Configuration options\n */\nexport function useA11yTarget<T extends HTMLElement>(\n  target: React.RefObject<T> | T | null,\n  options: UseA11yTargetOptions = {}\n) {\n  const {\n    preventScroll,\n    closeOnEscape = true,\n    openClass,\n    closedClass,\n    openStyle,\n    closedStyle,\n  } = options\n  const {id, isOpen, close} = useDisclosure()\n  const prevOpen = usePrevious(isOpen)\n  // Provides the target focus when it is in a new open state\n  useConditionalFocus(target, !prevOpen && isOpen, {\n    includeRoot: true,\n    preventScroll,\n  })\n  // Handles closing the modal when the ESC key is pressed\n  useKey(target, {Escape: () => closeOnEscape && close()})\n\n  return {\n    'aria-hidden': !isOpen,\n    id,\n    className: isOpen ? openClass : closedClass,\n    style: Object.assign(\n      {visibility: isOpen ? 'visible' : 'hidden'} as const,\n      isOpen ? openStyle : closedStyle\n    ),\n  } as const\n}\n\n/**\n * This component wraps any React element and turns it into a\n * disclosure target.\n */\nexport function Target({\n  closeOnEscape = true,\n  portal,\n  openClass,\n  closedClass,\n  openStyle,\n  closedStyle,\n  preventScroll,\n  children,\n}: TargetProps) {\n  const ref = React.useRef<HTMLElement>(null)\n  const childProps = children.props\n  const a11yProps = useA11yTarget(ref, {\n    openClass: clsx(childProps.className, openClass) || void 0,\n    closedClass: clsx(childProps.className, closedClass) || void 0,\n    openStyle: childProps.style\n      ? Object.assign({}, childProps.style, openStyle)\n      : openStyle,\n    closedStyle: childProps.style\n      ? Object.assign({}, childProps.style, closedStyle)\n      : closedStyle,\n    closeOnEscape,\n    preventScroll,\n  })\n\n  return portalize(\n    React.cloneElement(\n      children,\n      Object.assign(a11yProps, {\n        ref: useMergedRef(\n          ref,\n          // @ts-expect-error\n          children.ref\n        ),\n      })\n    ),\n    portal\n  )\n}\n\n/**\n * A React hook for creating a headless close button to [WAI-ARIA authoring practices](https://www.w3.org/TR/wai-aria-practices-1.1/examples/disclosure/disclosure-faq.html).\n * In addition to providing accessibility props to your component, this\n * hook will add events for interoperability between actual <button> elements\n * and fake ones e.g. <a> and <div> to the target element.\n *\n * @param target A React ref or HTML element\n * @param options Configuration options\n */\nexport function useA11yCloseButton<T extends HTMLElement>(\n  target: React.RefObject<T> | T | null,\n  {onClick}: UseA11yCloseButtonOptions = {}\n) {\n  const {close, isOpen, id} = useDisclosure()\n  return Object.assign(\n    {\n      'aria-controls': id,\n      'aria-expanded': isOpen,\n      'aria-label': 'Close',\n    } as const,\n    useA11yButton<T>(target, (e) => {\n      close()\n      onClick?.(e)\n    })\n  )\n}\n\n/**\n * This is a convenience component that wraps any React element and adds\n * an onClick handler which closes the disclosure.\n */\nexport function CloseButton({children}: CloseButtonProps) {\n  const ref = React.useRef<HTMLElement>(null)\n  const childProps = children.props\n  const a11yProps = useA11yCloseButton(ref, {\n    onClick: childProps.onClick,\n  })\n\n  return React.cloneElement(\n    children,\n    Object.assign(a11yProps, {\n      onClick: undefined,\n      'aria-label': childProps.hasOwnProperty('aria-label')\n        ? childProps['aria-label']\n        : a11yProps['aria-label'],\n      ref: useMergedRef(\n        ref,\n        // @ts-expect-error\n        children.ref\n      ),\n    })\n  )\n}\n\n/**\n * A React hook for creating a headless disclosure trigger to [WAI-ARIA authoring practices](https://www.w3.org/TR/wai-aria-practices-1.1/examples/disclosure/disclosure-faq.html).\n * In addition to providing accessibility props to your component, this\n * hook will add events for interoperability between actual <button> elements\n * and fake ones e.g. <a> and <div> to the target element\n *\n * @param target A React ref or HTML element\n * @param options Configuration options\n */\nexport function useA11yTrigger<T extends HTMLElement>(\n  target: React.RefObject<T> | T | null,\n  options: UseA11yTriggerOptions = {}\n) {\n  const {openClass, closedClass, openStyle, closedStyle, onClick} = options\n  const {isOpen, id, toggle} = useDisclosure()\n  const prevOpen = usePrevious(isOpen)\n  useConditionalFocus(target, prevOpen && !isOpen, {includeRoot: true})\n\n  return Object.assign(\n    {\n      'aria-controls': id,\n      'aria-expanded': isOpen,\n      className: isOpen ? openClass : closedClass,\n      style: isOpen ? openStyle : closedStyle,\n    } as const,\n    useA11yButton<T>(target, (e) => {\n      toggle()\n      onClick?.(e)\n    })\n  )\n}\n\n/**\n * This component wraps any React element and adds an `onClick` handler\n * which toggles the open state of the disclosure target.\n */\nexport function Trigger({\n  openClass,\n  closedClass,\n  openStyle,\n  closedStyle,\n  children,\n}: TriggerProps) {\n  const ref = React.useRef<HTMLElement>(null)\n  const childProps = children.props\n  const a11yProps = useA11yTrigger(ref, {\n    openClass: clsx(childProps.className, openClass) || void 0,\n    closedClass: clsx(childProps.className, closedClass) || void 0,\n    openStyle: childProps.style\n      ? Object.assign({}, childProps.style, openStyle)\n      : openStyle,\n    closedStyle: childProps.style\n      ? Object.assign({}, childProps.style, closedStyle)\n      : closedStyle,\n    onClick: childProps.onClick,\n  })\n\n  return React.cloneElement(\n    children,\n    Object.assign(a11yProps, {\n      onClick: undefined,\n      ref: useMergedRef(\n        ref,\n        // @ts-expect-error\n        children.ref\n      ),\n    })\n  )\n}\n\nfunction noop() {}\n\nexport interface DisclosureContextValue {\n  /**\n   * The open state of the disclosure\n   */\n  isOpen: boolean\n  /**\n   * Opens the disclosure\n   */\n  open: () => void\n  /**\n   * Closes the disclosure\n   */\n  close: () => void\n  /**\n   * Toggles the open state of the disclosure\n   */\n  toggle: () => void\n  /**\n   * A unique ID for the disclosure target\n   */\n  id?: string\n}\n\nexport interface DisclosureProps {\n  /**\n   * This creates a controlled disclosure component where the open state of the\n   * disclosure is controlled by this property.\n   */\n  open?: boolean\n  /**\n   * This sets the default open state of the disclosure. By default the disclosure\n   * is closed.\n   * @default false\n   */\n  defaultOpen?: boolean\n  /**\n   * By default this component creates a unique id for you, as it is required\n   * for certain aria attributes. Supplying an id here overrides the auto id feature.\n   */\n  id?: string\n  /**\n   * This callback is invoked any time the `open` state of the disclosure changes.\n   */\n  onChange?: (open: boolean) => void\n  /**\n   * By default this component creates a unique id for you, as it is required for\n   * certain aria attributes. Supplying an id here overrides the auto id feature.\n   */\n  children: React.ReactNode\n}\n\nexport interface UseA11yTriggerOptions {\n  /**\n   * Adds this class name to props when the disclosure is open\n   */\n  openClass?: string\n  /**\n   * Adds this class name to props when the disclosure is closed\n   */\n  closedClass?: string\n  /**\n   * Adds this style to props when the disclosure is open\n   */\n  openStyle?: React.CSSProperties\n  /**\n   * Adds this style to props when the disclosure is closed\n   */\n  closedStyle?: React.CSSProperties\n  /**\n   * Adds an onClick handler in addition to the default one that\n   * toggles the disclosure's open state.\n   */\n  onClick?: (e: MouseEvent) => any\n}\n\nexport interface TriggerProps extends Omit<UseA11yTriggerOptions, 'onClick'> {\n  /**\n   * The child is cloned by this component and has aria attributes injected\n   * into its props as well as the events defined above.\n   */\n  children: JSX.Element | React.ReactElement\n}\n\nexport interface UseA11yTargetOptions {\n  /**\n   * Adds this class name to props when the disclosure is open\n   */\n  openClass?: string\n  /**\n   * Adds this class name to props when the disclosure is closed\n   */\n  closedClass?: string\n  /**\n   * Adds this style to props when the disclosure is open\n   */\n  openStyle?: React.CSSProperties\n  /**\n   * Adds this style to props when the disclosure is closed\n   */\n  closedStyle?: React.CSSProperties\n  /**\n   * Prevents the `window` from scrolling when the target is\n   * focused after opening.\n   */\n  preventScroll?: boolean\n  /**\n   * When `true`, this closes the target element when the `Escape`\n   * key is pressed.\n   * @default true\n   */\n  closeOnEscape?: boolean\n}\n\nexport interface TargetProps extends UseA11yTargetOptions {\n  /**\n   * When `true` this will render the disclosure into a React portal with the\n   * id `#portals`. You can render it into any portal by providing its query\n   * selector here, e.g. `#foobar`, `[data-portal=true]`, or `.foobar`.\n   * @default false\n   */\n  portal?:\n    | boolean\n    | undefined\n    | null\n    | string\n    | Omit<PortalizeProps, 'children'>\n  /**\n   * The child is cloned by this component and has aria attributes injected into its\n   * props as well events.\n   */\n  children: JSX.Element | React.ReactElement\n}\n\nexport interface UseA11yCloseButtonOptions {\n  /**\n   * Adds an onClick handler in addition to the default one that\n   * closes the disclosure.\n   */\n  onClick?: (e: MouseEvent) => any\n}\n\nexport interface CloseButtonProps {\n  /**\n   * The child is cloned by this component and has aria attributes injected into its\n   * props as well events.\n   */\n  children: JSX.Element | React.ReactElement\n}\n\n/* istanbul ignore next */\nif (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production') {\n  Disclosure.displayName = 'Disclosure'\n  Target.displayName = 'Target'\n  Trigger.displayName = 'Trigger'\n  CloseButton.displayName = 'CloseButton'\n}\n"],"names":["useDisclosure","React","DisclosureContext","Disclosure","id","open","defaultOpen","onChange","noop","children","useId","isOpen","toggle","useSwitch","context","on","close","off","__reactCreateElement__","Provider","value","useA11yTarget","target","options","preventScroll","closeOnEscape","openClass","closedClass","openStyle","closedStyle","prevOpen","usePrevious","useConditionalFocus","includeRoot","useKey","Escape","className","style","Object","assign","visibility","Target","portal","ref","childProps","props","a11yProps","clsx","Component","container","Portalize","portalize","useMergedRef","useA11yCloseButton","onClick","useA11yButton","e","CloseButton","undefined","hasOwnProperty","useA11yTrigger","Trigger"],"mappings":"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"}