[
  {
    "path": ".gitignore",
    "content": "*.log\n.DS_Store\nnode_modules\n.cache\ndist\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 raunofreiberg\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# axe-mode\n\n![npm](https://img.shields.io/npm/v/axe-mode?color=%236469FF)\n\n> WIP\n\nThis project is an attempt to leverage [`axe-core`](https://github.com/dequelabs/axe-core) in a component to find accessibility violations and provide information on how to resolve them.\n\nCurrently, this only works for React.\n\n[See it in action on CodeSandbox.](https://codesandbox.io/s/youthful-pare-oxtcc)\n\n![Demo](https://i.gyazo.com/2eeb2f0bacbabfbe706932c545ec682c.gif)\n\n\n## Usage\n\nInstall the library:\n\n```bash\nyarn add axe-mode -D\n```\n\nor\n\n```bash\nnpm install axe-mode --save-dev\n```\n\nImport the component and wrap it around your application or any other component tree you would like to validate:\n\n```tsx\nimport AxeMode from 'axe-mode';\n\nfunction App() {\n  return (\n    <AxeMode disabled={process.env.NODE_ENV !== 'development'}>\n      <h1 aria-expanded=\"123\">Hello world!</h1>\n    </AxeMode>\n  );\n}\n```\n\nLaunch your application as usual. Any violations of accessibility will show up as an overlay. If you wish to interact with your application, overlays can be toggled on/off with <kbd>Ctrl + I</kbd>.\n\nYou can safely leave the component around your application since [this whole library and its dependencies will be dropped in production.](https://github.com/raunofreiberg/axe-mode/blob/master/src/index.tsx#L7)\n\n**Note**: Make sure to only run in production by using the `disabled` prop with your environment variable.\n"
  },
  {
    "path": "example/.gitignore",
    "content": ".now"
  },
  {
    "path": "example/.npmignore",
    "content": "node_modules\n.cache\ndist"
  },
  {
    "path": "example/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\" />\n    <title>Playground</title>\n  </head>\n\n  <body>\n    <div id=\"root\"></div>\n    <script src=\"./index.tsx\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "example/index.tsx",
    "content": "import 'react-app-polyfill/ie11';\nimport './styles.css';\nimport * as React from 'react';\nimport * as ReactDOM from 'react-dom';\nimport AxeMode from '../src/index';\n\nfunction Subtitle() {\n  return <h6>Accessibility testing componentized</h6>;\n}\n\nfunction Image() {\n  const ref = React.useRef<HTMLImageElement | null>(null);\n\n  React.useEffect(() => {\n    // For testing whether violations from\n    // DOM mutations are displayed.\n    const id = setTimeout(() => {\n      ref?.current?.setAttribute('alt', 'Avatar');\n    }, 3000);\n\n    return () => clearTimeout(id);\n  }, [ref]);\n\n  return (\n    <img\n      ref={ref}\n      src=\"https://avatars1.githubusercontent.com/u/23662329?v=4\"\n      width=\"40\"\n      height=\"40\"\n    />\n  );\n}\n\nconst App = () => {\n  return (\n    <AxeMode>\n      <header>\n        <a href=\"#\" className=\"iconLink\" id=\"hey\">\n          <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n            <path\n              d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z\"\n              fill=\"currentColor\"\n            />\n          </svg>\n        </a>\n        <Image />\n      </header>\n      <main>\n        <div className=\"login\">\n          <h1>Axe Mode</h1>\n          <Subtitle />\n          <input placeholder=\"Username\" />\n          <input placeholder=\"Password\" />\n          <button\n            aria-expanded={'foo' as any}\n            onClick={() => console.log('yo')}\n          >\n            Label\n          </button>\n        </div>\n      </main>\n    </AxeMode>\n  );\n};\n\nReactDOM.render(<App />, document.getElementById('root'));\n"
  },
  {
    "path": "example/package.json",
    "content": "{\n  \"name\": \"example\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.js\",\n  \"license\": \"MIT\",\n  \"scripts\": {\n    \"start\": \"parcel index.html\",\n    \"build\": \"parcel build index.html\"\n  },\n  \"dependencies\": {\n    \"react-app-polyfill\": \"^1.0.0\"\n  },\n  \"alias\": {\n    \"react\": \"../node_modules/react\",\n    \"react-dom\": \"../node_modules/react-dom/profiling\",\n    \"scheduler/tracing\": \"../node_modules/scheduler/tracing-profiling\"\n  },\n  \"devDependencies\": {\n    \"@types/react\": \"^16.9.11\",\n    \"@types/react-dom\": \"^16.8.4\",\n    \"parcel\": \"^1.12.3\",\n    \"typescript\": \"^3.4.5\"\n  }\n}\n"
  },
  {
    "path": "example/styles.css",
    "content": "* {\n  box-sizing: border-box;\n}\n\nbody {\n  margin: 0;\n  height: 200vh;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen,\n  Ubuntu, Cantarell, \"Open Sans\", \"Helvetica Neue\", sans-serif;\n}\n\n.iconLink {\n  display: inline-block;\n  width: 24px;\n  height: 24px;\n  color: #222328;\n}\n\nheader {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  background: white;\n  height: 64px;\n  padding: 0 32px;\n  box-shadow: inset 0 -1px 0 0 #e6ebf4, 0 4px 8px 0 rgba(189, 192, 207, .08);\n}\n\nheader img {\n  border-radius: 50%;\n}\n\ninput {\n  height: 40px;\n  padding: 8px 16px;\n  margin: 0;\n  border-radius: 4px;\n  border: 1px solid #E6EBF4;\n  appearance: none;\n  font-size: 14px;\n  background-color: #FAFAFC;\n  color: #222328;\n}\n\n.login button {\n  padding: 0 16px;\n  background: #222328;\n  height: 40px;\n  margin: 0;\n  border: 0;\n  border-radius: 4px;\n  color: white;\n  font-weight: 500;\n  text-transform: uppercase;\n  font-size: 14px;\n  cursor: pointer;\n  width: 100%;\n}\n\nmain {\n  height: calc(100vh - 64px);\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n}\n\n.login {\n  display: grid;\n  grid-gap: 16px;\n  width: 300px;\n}\n\n.login h1, .login h6 {\n  text-align: center;\n}\n\n.login h1, h6 {\n  margin: 0;\n}\n\nh6 {\n  color: #505366;\n  line-height: 24px;\n}\n"
  },
  {
    "path": "example/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": false,\n    \"target\": \"es5\",\n    \"module\": \"commonjs\",\n    \"jsx\": \"react\",\n    \"moduleResolution\": \"node\",\n    \"noImplicitAny\": false,\n    \"noUnusedLocals\": false,\n    \"noUnusedParameters\": false,\n    \"removeComments\": true,\n    \"strictNullChecks\": true,\n    \"preserveConstEnums\": true,\n    \"sourceMap\": true,\n    \"lib\": [\"es2015\", \"es2016\", \"dom\"],\n    \"baseUrl\": \".\",\n    \"types\": [\"node\"]\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"version\": \"0.0.1-alpha.2\",\n  \"license\": \"MIT\",\n  \"main\": \"dist/index.js\",\n  \"typings\": \"dist/index.d.ts\",\n  \"files\": [\n    \"dist\",\n    \"src\"\n  ],\n  \"engines\": {\n    \"node\": \">=10\"\n  },\n  \"scripts\": {\n    \"start\": \"tsdx watch\",\n    \"build\": \"tsdx build\",\n    \"test\": \"tsdx test --passWithNoTests\",\n    \"lint\": \"tsdx lint\",\n    \"prepare\": \"tsdx build\"\n  },\n  \"peerDependencies\": {\n    \"react\": \">=16\"\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"tsdx lint\"\n    }\n  },\n  \"prettier\": {\n    \"printWidth\": 80,\n    \"semi\": true,\n    \"singleQuote\": true,\n    \"trailingComma\": \"es5\"\n  },\n  \"name\": \"axe-mode\",\n  \"author\": \"raunofreiberg\",\n  \"module\": \"dist/axe-mode.esm.js\",\n  \"devDependencies\": {\n    \"@types/react\": \"^16.9.34\",\n    \"@types/react-dom\": \"^16.9.7\",\n    \"husky\": \"^4.2.5\",\n    \"react\": \"^16.13.1\",\n    \"react-dom\": \"^16.13.1\",\n    \"rollup-plugin-postcss\": \"^3.1.1\",\n    \"tsdx\": \"^0.13.2\",\n    \"tslib\": \"^1.11.1\",\n    \"typescript\": \"^3.8.3\"\n  },\n  \"dependencies\": {\n    \"@reach/auto-id\": \"^0.10.1\",\n    \"@reach/observe-rect\": \"^1.1.0\",\n    \"@reach/popover\": \"^0.10.1\",\n    \"axe-core\": \"^3.5.3\"\n  },\n  \"eslintConfig\": {\n    \"extends\": \"react-app\",\n    \"overrides\": [\n      {\n        \"files\": [\n          \"example/*\"\n        ],\n        \"rules\": {\n          \"jsx-a11y/alt-text\": 0,\n          \"jsx-a11y/anchor-is-valid\": 0,\n          \"jsx-a11y/accessible-emoji\": 0\n        }\n      }\n    ]\n  },\n  \"eslintIgnore\": [\"dist\"]\n}\n"
  },
  {
    "path": "src/axe-mode.tsx",
    "content": "import './styles.css';\nimport * as React from 'react';\nimport axe, { ElementContext, Result } from 'axe-core';\nimport Popover from '@reach/popover';\nimport observeRect from '@reach/observe-rect';\nimport { IconMinor, IconModerate, IconSevere } from './icons';\n\ntype ViolationsByNode = Array<{ node: string; violations: Result[] }>;\ntype AxeCoreModule = typeof axe;\n\nfunction getValidator(axe: AxeCoreModule) {\n  return (node: ElementContext): Promise<Result[]> => {\n    return new Promise((resolve, reject) => {\n      axe.run(node, { reporter: 'v2' }, (error, results) => {\n        if (error) reject(error);\n        resolve(results.violations);\n      });\n    });\n  };\n}\n\n// Copied from:\n// https://stackoverflow.com/questions/29321742/react-getting-a-component-from-a-dom-element-for-debugging\n// ¯\\_(ツ)_/¯\nfunction getComponentFromNode(node: HTMLElement): string {\n  const [component] = Object.keys(node)\n    .filter(key => key.startsWith('__reactInternalInstance$'))\n    .map((key: string) => {\n      const fiberNode = (node as any)[key];\n      const component = fiberNode && fiberNode._debugOwner;\n      return component.type.displayName || component.type.name;\n    });\n  return component;\n}\n\nfunction segmentViolationsByNode(violations: Result[]): ViolationsByNode {\n  // Find all DOM nodes affected by the violations\n  const nodes = violations.flatMap(violation =>\n    violation.nodes.flatMap(node => node.target)\n  );\n\n  // Based on the found nodes, find all violations that they caused\n  return nodes.map(node => {\n    const violationsByNode = violations.filter(violation =>\n      violation.nodes.some(n => n.target.includes(node))\n    );\n    return {\n      node,\n      violations: violationsByNode,\n    };\n  });\n}\n\nfunction setOverlayPosition(\n  overlayNode: HTMLElement,\n  { width, height, x, y }: DOMRect\n) {\n  overlayNode.style.setProperty('width', `${width}px`);\n  overlayNode.style.setProperty('height', `${height}px`);\n  overlayNode.style.setProperty('left', `${x}px`);\n  overlayNode.style.setProperty('top', `${y}px`);\n}\n\nfunction Violation({\n  target,\n  violations,\n}: {\n  target: any;\n  violations: Result[];\n}) {\n  const [open, setOpen] = React.useState(false);\n  const targetRef = React.useRef<HTMLElement | null>(null);\n  const popoverRef = React.useRef<HTMLDivElement | null>(null);\n  const overlayRef = React.useRef<HTMLElement | null>(null);\n\n  function toggle() {\n    setOpen(prevOpen => !prevOpen);\n  }\n\n  function close() {\n    setOpen(false);\n  }\n\n  React.useEffect(() => {\n    const targetNode = document.querySelector(target);\n    const overlayNode = document.createElement('axe-mode-overlay');\n\n    targetRef.current = targetNode;\n    overlayRef.current = overlayNode;\n\n    const { observe, unobserve } = observeRect(targetNode, targetRect => {\n      setOverlayPosition(overlayNode, targetRect);\n    });\n\n    const bounds = targetNode.getBoundingClientRect();\n    setOverlayPosition(overlayNode, bounds);\n\n    observe();\n    document.body.appendChild(overlayNode);\n    overlayNode.addEventListener('mousedown', toggle);\n\n    return () => {\n      unobserve();\n      document.body.removeChild(overlayNode);\n      overlayNode.removeEventListener('mousedown', toggle);\n    };\n  }, [target]);\n\n  React.useEffect(() => {\n    function listener(e: MouseEvent) {\n      const eventTarget = e.target as Node;\n      const isTargetInPopover =\n        eventTarget === overlayRef.current ||\n        popoverRef.current?.contains(eventTarget);\n\n      if (!isTargetInPopover) {\n        close();\n      }\n    }\n\n    if (open) {\n      document.addEventListener('mousedown', listener);\n    }\n\n    return () => {\n      document.removeEventListener('mousedown', listener);\n    };\n  }, [open, target]);\n\n  if (!open) {\n    return null;\n  }\n\n  return (\n    <Popover ref={popoverRef} targetRef={targetRef} className=\"popover\">\n      <div className=\"controls\">\n        <h2>Accessibility violation</h2>\n        <button className=\"close\" aria-label=\"Close popover\" onClick={close}>\n          <svg viewBox=\"0 0 24 24\">\n            <path\n              d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"\n              fill=\"currentColor\"\n              fillRule=\"evenodd\"\n            />\n          </svg>\n        </button>\n      </div>\n      <code>\n        {getComponentFromNode(document.querySelector(target)) || target}\n      </code>\n      {violations.map(violation => {\n        const [{ any, all }] = violation.nodes.filter(node =>\n          node.target.includes(target)\n        );\n\n        return (\n          <article key={violation.id} className=\"checks\">\n            <div className=\"header\">\n              {violation.impact === 'minor' ? (\n                <IconMinor />\n              ) : violation.impact === 'moderate' ? (\n                <IconModerate />\n              ) : (\n                <IconSevere />\n              )}\n              <h3>\n                <a\n                  href={violation.helpUrl}\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                >\n                  {violation.help}\n                </a>\n              </h3>\n            </div>\n            {!!all.length && (\n              <>\n                <small>Fix all of the following:</small>\n                <ul>\n                  {all.map(check => (\n                    <li key={check.id}>{check.message}</li>\n                  ))}\n                </ul>\n              </>\n            )}\n            {!!any.length && (\n              <>\n                <small>Fix any of the following:</small>\n                <ul>\n                  {any.map(check => (\n                    <li key={check.id}>{check.message}</li>\n                  ))}\n                </ul>\n              </>\n            )}\n          </article>\n        );\n      })}\n    </Popover>\n  );\n}\n\nexport interface AxeModeProps {\n  children: React.ReactElement | React.ReactElement[];\n  disabled?: boolean;\n}\n\nexport default function AxeModeImpl({ children, disabled }: AxeModeProps) {\n  const [violations, setViolations] = React.useState<Result[]>([]);\n  const [interactive, setInteractive] = React.useState(false);\n  const idleId = React.useRef<number | null>(null);\n  const childrenRef = React.useRef<HTMLElement | null>(null);\n\n  React.useEffect(() => {\n    if (disabled || interactive || !childrenRef.current) {\n      return;\n    }\n\n    if (idleId.current && 'cancelIdleCallback' in window) {\n      window.cancelIdleCallback(idleId.current);\n      idleId.current = null;\n    }\n\n    function getViolations() {\n      const validateNode = getValidator(axe);\n      validateNode(childrenRef.current as ElementContext).then(setViolations);\n    }\n\n    function callback() {\n      // Safari does not support requestIdleCallback 😔\n      if ('requestIdleCallback' in window) {\n        idleId.current = window.requestIdleCallback(getViolations);\n      } else {\n        getViolations();\n      }\n    }\n\n    const observer = new MutationObserver(callback);\n    // We need to run this once so we don't wait for\n    // DOM mutations to display the violations.\n    callback();\n\n    observer.observe(childrenRef.current, {\n      attributes: true,\n      childList: true,\n      subtree: true,\n    });\n\n    return () => {\n      if (idleId.current && 'cancelIdleCallback' in window) {\n        window.cancelIdleCallback(idleId.current);\n        idleId.current = null;\n      }\n      observer.disconnect();\n    };\n  }, [disabled, interactive]);\n\n  React.useEffect(() => {\n    function listener(e: KeyboardEvent) {\n      if (e.ctrlKey && e.key === 'i') {\n        setInteractive(!interactive);\n      }\n    }\n\n    document.addEventListener('keydown', listener);\n\n    return () => {\n      document.removeEventListener('keydown', listener);\n    };\n  }, [interactive]);\n\n  const violationsByNode = segmentViolationsByNode(violations);\n\n  if (disabled || interactive) {\n    return <>{children}</>;\n  }\n\n  console.log(violationsByNode);\n\n  return (\n    <>\n      <span ref={childrenRef}>{children}</span>\n      {violationsByNode.map(({ node, violations }, index) => (\n        <Violation key={index} target={node} violations={violations} />\n      ))}\n    </>\n  );\n}\n"
  },
  {
    "path": "src/icons.tsx",
    "content": "import * as React from 'react';\nimport { useId } from '@reach/auto-id';\n\nexport const IconMinor: React.FC<Omit<\n  React.ComponentPropsWithoutRef<'svg'>,\n  'viewBox'\n>> = props => {\n  const titleId = `minor-icon-${useId(props.id)}`;\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      role=\"img\"\n      aria-labelledby={titleId}\n      {...props}\n      viewBox=\"0 0 500 500\"\n    >\n      <title id={titleId}>Minor impact</title>\n      <path\n        d=\"M439.8,30.73C330.44,13.58,233.42,80.12,124.31,73.18l.13-1.74a31.5,31.5,0,0,0-62.83-4.65L34.12,438.28A31.49,31.49,0,0,0,63.21,472c.79.06,1.57.09,2.36.09A31.51,31.51,0,0,0,97,442.93l6.85-92.58c109,16.51,205.76-49.64,314.59-42.6a31.22,31.22,0,0,0,33.21-29.06q7.15-107.8,14.3-215.09A31.13,31.13,0,0,0,439.8,30.73Z\"\n        fill=\"#FF9800\"\n      />\n    </svg>\n  );\n};\n\nexport const IconModerate: React.FC<Omit<\n  React.ComponentPropsWithoutRef<'svg'>,\n  'viewBox'\n>> = props => {\n  const titleId = `moderate-icon-${useId(props.id)}`;\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      role=\"img\"\n      aria-labelledby={titleId}\n      {...props}\n      viewBox=\"0 0 500 500\"\n    >\n      <title id={titleId}>Moderate impact</title>\n      <path\n        d=\"M250,18C121.87,18,18,121.87,18,250S121.87,482,250,482,482,378.13,482,250,378.13,18,250,18Zm-20.6,89.34h42a14.54,14.54,0,0,1,14.52,15.35l-8.33,148.79A14.54,14.54,0,0,1,263,285.21H237.4a14.53,14.53,0,0,1-14.52-13.76l-8-148.79A14.54,14.54,0,0,1,229.4,107.34Zm49.35,287.19q-10.26,10.13-28.87,10.13-19.08,0-29-10.25T211,366q0-18.39,9.78-28.52t29.1-10.13q19.32,0,29.22,10T289,366Q289,384.4,278.75,394.53Z\"\n        fill=\"#FF5B5B\"\n      />\n    </svg>\n  );\n};\n\nexport const IconSevere: React.FC<Omit<\n  React.ComponentPropsWithoutRef<'svg'>,\n  'viewBox'\n>> = props => {\n  const titleId = `severe-icon-${useId(props.id)}`;\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      role=\"img\"\n      aria-labelledby={titleId}\n      {...props}\n      viewBox=\"0 0 500 500\"\n    >\n      <title id={titleId}>Severe impact</title>\n      <path\n        d=\"M492.39,420,282.09,44.09C268.05,19,232,19,217.91,44.09L7.61,420c-13.71,24.51,4,54.72,32.09,54.72H460.3C488.38,474.73,506.1,444.52,492.39,420Zm-263-291.94h42a14.54,14.54,0,0,1,14.52,15.35l-8.33,148.79A14.54,14.54,0,0,1,263,305.94H237.4a14.54,14.54,0,0,1-14.52-13.76l-8-148.79A14.53,14.53,0,0,1,229.4,128.07Zm49.35,287.19q-10.26,10.13-28.87,10.13-19.08,0-29-10.25t-9.9-28.4q0-18.37,9.78-28.51t29.1-10.13q19.32,0,29.22,10t9.9,28.63Q289,405.13,278.75,415.26Z\"\n        fill=\"#FFB963\"\n      />\n    </svg>\n  );\n};\n"
  },
  {
    "path": "src/index.tsx",
    "content": "import * as React from 'react';\nimport { AxeModeProps } from './axe-mode';\n\nconst AxeMode = React.lazy(() => import('./axe-mode'));\n\nexport default function Loader(props: AxeModeProps) {\n  if (process.env.NODE_ENV === 'development') {\n    return (\n      <React.Suspense fallback={null}>\n        <AxeMode {...props} />\n      </React.Suspense>\n    );\n  }\n  return <React.Fragment>{props.children}</React.Fragment>;\n}\n\nexport { AxeModeProps };\n"
  },
  {
    "path": "src/styles.css",
    "content": "@keyframes slideDown {\n  0% {\n    opacity: 0;\n    transform: translateY(-8px);\n  }\n  100% {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n\naxe-mode-overlay {\n  position: fixed;\n  background: rgba(255, 91, 91, 0.2);\n  border: 1px solid rgb(255, 91, 91);\n  border-radius: 4px;\n  cursor: pointer;\n}\n\n.popover {\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen,\n  Ubuntu, Cantarell, \"Open Sans\", \"Helvetica Neue\", sans-serif;\n  position: absolute;\n  border-radius: 4px;\n  box-shadow: 0 2px 8px 0 rgba(189, 192, 207, 0.16);\n  border: 1px solid #E6EBF4;\n  background-color: white;\n  padding: 16px;\n  margin: 8px 0;\n  z-index: 1337;\n  animation: slideDown 0.4s cubic-bezier(.2, .8, .4, 1);\n}\n.popover h2 {\n  margin: 0;\n  font-size: 20px;\n  color: #222328;\n}\n\n.popover ul {\n  padding-left: 14px;\n  margin-top: 8px;\n  margin-bottom: 0;\n  list-style-type: '・ ';\n}\n\n.popover li {\n  padding: 0;\n  max-width: 40ch;\n  margin: 8px 0 0 0;\n  font-size: 14px;\n  color: #505366;\n}\n\n.popover small {\n  display: block;\n  font-size: 12px;\n  color: #BDC0CF;\n  margin: 4px 0 8px 0;\n}\n\n.popover h2 {\n  max-width: 40ch;\n}\n\n.popover a {\n  color: #6469FF;\n}\n\n\n.popover code {\n  font-size: 12px;\n  line-height: 20px;\n  padding-left: 5px;\n  padding-right: 5px;\n  background-color: rgba(100, 105, 255, 0.05);\n  color: #6469FF;\n  border-radius: 3px;\n}\n\n\n.popover .checks {\n  margin-top: 16px;\n}\n\n.popover .checks .header {\n  display: flex;\n  font-size: 1.2rem;\n  margin: 0.5em 0;\n  align-items: center;\n}\n\n.popover .checks .header svg {\n  width: 1em;\n  height: 1em;\n  margin-right: 0.325em;\n}\n\n.popover .checks .header h3 {\n  font-size: 1em;\n  margin: 0;\n}\n\n.controls {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  margin-bottom: 4px;\n}\n\n.close {\n  width: 24px;\n  height: 24px;\n  border: 0;\n  background: none;\n  padding: 0;\n  margin: 0;\n  cursor: pointer;\n}\n"
  },
  {
    "path": "test/blah.test.tsx",
    "content": "import * as React from 'react';\nimport * as ReactDOM from 'react-dom';\nimport { Thing } from '../src';\n\ndescribe('it', () => {\n  it('renders without crashing', () => {\n    const div = document.createElement('div');\n    ReactDOM.render(<Thing />, div);\n    ReactDOM.unmountComponentAtNode(div);\n  });\n});\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"include\": [\"src\", \"types\"],\n  \"compilerOptions\": {\n    \"module\": \"esnext\",\n    \"lib\": [\"dom\", \"esnext\"],\n    \"importHelpers\": true,\n    \"declaration\": true,\n    \"sourceMap\": true,\n    \"rootDir\": \"./src\",\n    \"strict\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"moduleResolution\": \"node\",\n    \"baseUrl\": \"./\",\n    \"paths\": {\n      \"*\": [\"src/*\", \"node_modules/*\"]\n    },\n    \"jsx\": \"react\",\n    \"esModuleInterop\": true\n  }\n}\n"
  },
  {
    "path": "tsdx.config.js",
    "content": "const postcss = require('rollup-plugin-postcss');\nconst path = require('path');\n\nmodule.exports = {\n  rollup(config, options) {\n    config.plugins = [postcss(), ...config.plugins];\n\n    // To get code splitting to work, we need to set output.dir instead of\n    // output.file, which is what TSDX does by default\n    const { file, ...output } = config.output || {};\n    config.output = {\n      ...output,\n      dir: path.join(__dirname, 'dist'),\n    };\n\n    return config;\n  },\n};\n"
  },
  {
    "path": "types/index.d.ts",
    "content": "type RequestIdleCallbackOptions = {\n  timeout: number;\n};\ntype RequestIdleCallbackDeadline = {\n  readonly didTimeout: boolean;\n  timeRemaining: () => number;\n};\n\ndeclare global {\n  // tsdx supports this out of the box, can be useful for omitting unused code \n  // from the prod bundle.\n  const __DEV__: boolean;\n  interface Window {\n    requestIdleCallback: (\n      callback: (deadline: RequestIdleCallbackDeadline) => void,\n      opts?: RequestIdleCallbackOptions\n    ) => number;\n    cancelIdleCallback: (handle: number) => void;\n  }\n}\n\nexport {};\n"
  }
]